Nginx가 아닌 Apache vhost에서 Discourse 실행 방법

기본 nginx 대신 Apache vhost에서 Discourse를 실행하는 데 성공하신 분이 계신가요?

이 포럼에서 Apache 관련 논의의 대부분은 이미 Apache가 실행 중인 호스트에서 Discourse를 실행하는 방법에 대한 것입니다. 제가 본 모든 사례에서 사람들은 Apache를 nginx로 프록시하도록 설정하고 있었습니다. 명확히 하자면: 저는 Discourse를 실행하는 Docker 백엔드 컨테이너가 Nginx가 아닌 Apache에서 가상 호스트를 실행하길 원합니다.

구체적으로 말하면, mod_security를 활성화하기 위해 Nginx 대신 Apache에서 Discourse 백엔드를 실행하길 희망합니다. Nginx에 mod_security를 설정하려면 소스에서 Nginx를 컴파일해야 하는데, 이러한 복잡성은 피하고 싶습니다.

현재 프로덕션 서버에는 여러 사이트(WordPress, MediaWiki 등)가 이미 실행 중입니다. 우리는 Nginx로 HTTPS를 종료하고 기본적인 DOS 속도 제한을 수행한 후, Varnish 캐시를 거쳐 mod_security가 적용된 Apache 백엔드로 요청을 전달하는 아키텍처를 사용하고 있습니다. 가능하다면 Discourse에도 이 아키텍처를 유지하고 싶으며, 백엔드 Discourse Docker 컨테이너가 Nginx가 아닌 mod_security가 적용된 Apache를 실행하도록 하고 싶습니다.

Apache에서 Discourse를 실행하도록 설정하는 데 성공하신 분이 계신가요?

죄송합니다, 저는 Docker에 처음입니다. ‘/etc/nginx/conf.d/discourse.conf’ 파일이 Docker 컨테이너에 어떻게 배치되는지 찾는 데 큰 어려움을 겪고 있습니다. ‘./launcher’ 스크립트가 이 파일을 생성하고 컨테이너에 배치하는 과정을 단계별로 설명해 주실 수 있을까요?

수정: 잠깐, Nginx가 이미 Discourse에 의해 소스에서 컴파일되고 있는 건가요?

아니요, 없습니다. Discourse는 nginx와 상당히 긴밀하게 연결되어 있습니다. Apache로 대체하는 것은 어려울 뿐만 아니라 불가능할 수도 있습니다. 그리고 그렇게 하시는 분은 당신뿐이므로, 문제가 발생하더라도 다른 누구도 신경 쓰지 않을 것입니다.

모든 사람이 사용하는 Docker 컨테이너를 사용하시고, 보안에 도움이 될 것이라고 생각되면 Apache를 앞에 배치하세요.

그렇게 보입니다.

/etc/nginx/conf.d/discourse.conf 파일은 컨테이너에서 템플릿 파일 /var/docker/templates/web.template.yml에 의해 생성되는 것으로 보입니다. 이 템플릿은 $home/config/nginx.sample.conf에서 해당 파일을 복사하여 배치한 후, replace yaml 블록을 통해 변경 사항을 적용합니다(이 과정은 templates/web.socketed.template.yml과 같은 후속 템플릿에서 더 업데이트됩니다).

저는 image/base/install-nginx에서 소스에서 nginx를 컴파일할 때 nginx가 nginx.sample.conf 파일을 단순히 설치한다고 가정하고 있었습니다. 하지만 컨테이너에서 찾은 유일한 nginx.sample.conf 파일(/var/www/discourse/config/nginx.sample.conf)에는 이미 Discourse에 특화된 지시문(directives)이 포함되어 있었습니다.

nginx.sample.conf 파일은 어디서 온 것일까요?

nginx → varnish → apache → nginx这样的 구성은 피하고 싶습니다. :slight_smile:

정확히 말씀드리면, Discourse vhost를 apache(nginx 대신) 뒤에 배치하도록 컨테이너를 업데이트하는 것보다, ‘image/base/install-nginx’ 스크립트를 수정하여 mod_security 지원을 포함하도록 Discourse docker 컨테이너에서 nginx를 컴파일하는 것이 더 안전하다고 보시는 건가요? 그렇다면 install-nginx 스크립트를 수정할 때의 위험성은 무엇이며, 이것이 미래에 제 Discourse 설치를 어떻게 깨뜨릴 수 있을까요?

PSA: 여러분이 제안하는 모든 작업은 기술적으로 가능할지라도, 완전히 지원되지 않습니다. Discourse를 웹에 배포하기 위해 사람들이 만들어내는 모든 가능한 조합을 합리적으로 지원할 수 없습니다. 따라서 이 포럼에서의 지원은 discourse/docs/INSTALL-cloud.md at main · discourse/discourse · GitHub 가이드를 따르는 설치에 한정됩니다.

discourse/config/nginx.sample.conf at main · discourse/discourse · GitHub

결국 다양한 방식으로 깨지게 될 것입니다. 계속해서 업스트림 변경 사항과 병합하고, 영원히 자신의 포크를 관리해야 하는 부담을 지게 됩니다.

완벽합니다, 감사합니다! 와, 완전히 다른 저장소네요. 컨테이너가 그 파일을 다른 저장소에서 어떻게 가져오나요? 여기 있나요?

그리고 $home은 무엇인가요?

소스 코드를 읽어 보면 이 외에도 더 많은 내용을 확인할 수 있습니다: discourse_docker/image/base/Dockerfile at master · discourse/discourse_docker · GitHub

app.yml(Discourse) 설정을 다음과 같이 해결했습니다:
expose:
- "2045:80" # http
- "8443:443" # https

그리고 vhost는 다음과 같이 설정했습니다:
<VirtualHost *myhostIP*:443>
ServerName forum.domain.org
ServerAlias forum.domain.org
…
ProxyAddHeaders Off
ProxyPass / "http://localhost:2045/"
ProxyPassReverse / "http://localhost:2045/"
</VirtualHost>

질문을 오해하지 않았기를 바랍니다 :blush:

@ledimeo @pfaffman이 제안한 방법이며, 이번 경우 더 나은 선택이라고 생각합니다. 향후 새 버전이 출시될 때 문제를 크게 일으키지 않기 위해서입니다. 하지만 그는 이미 프론트에 다른 nginx를 리버스 프록시로 사용하고 있으며, 다음과 같은 구성을 원하지 않는 것 같습니다:

그럼에도 불구하고, apache를 nginx로 프록싱하는 것(결국 4층 구조가 되더라도)은 공식 설치에서 discourse의 동작 방식을 변경하려는 시도보다 최소한 유지보수가 더 용이하다고 생각합니다.

이 목적을 위해 nginx가 docker 컨테이너라는 ‘블랙박스’ 안에 있다고 생각하고 신경 쓰지 않는 것이 좋습니다.

즉: nginx → varnish → apache → Discourse (nginx와 unicorn로 구성됨)

(업스트림 프록시 IP를 신뢰하도록 설정하는 경우를 제외하고)

Discourse의 nginx에 Apache를 프록시로 추가하는 것은 확실히 하나의 옵션입니다.

전문가가 향후 업그레이드를 더 쉽게 만들어 줄 것이라는 점에 동의하며, 이는 중요한 포인트입니다.

하지만 아키텍처에 또 다른 홉(hop)을 추가하면 향후 문제를 디버깅하는 것이 더 복잡해질 뿐만 아니라, @sam이 2016년 이 게시물에서 지적했듯이 장기 폴링(long polling)을 사용하는 웹 애플리케이션에 대한 Apache의 프록시 성능에 대해서도 우려가 있습니다.

일반적으로 mod_security를 제외하고는 nginx를 Apache보다 선호합니다. OS 저장소에 Apache처럼 nginx에서 mod_security를 활성화할 수 있는 패키지가 포함되어 있다면 좋겠지만, 현재 nginx에서 mod_security를 활성화하려면 RHEL/Cent와 Debian 모두에서 소스에서 nginx를 컴파일해야 합니다. 그리고 프로덕션 환경에서 소스에서 컴파일된 패키지에 의존하는 것은 전염병처럼 피하려 합니다.

관련: install-nginx 스크립트를 살펴보던 중 사소한 논리 오류를 발견했습니다. /tmp/에서 nginx 소스를 삭제하도록 의도된 클리업 줄이 실제로는 아무 동작도 하지 않고 있습니다.

/tmp/nginx/ 디렉터리는 존재하지 않습니다: 실제 경로는 /tmp/nginx-$VERSION/입니다(현재는 /tmp/nginx-1.17.4/이며, 타르볼 /tmp/nginx-1.17.4.tar.gz도 있습니다).

아래처럼 수정하는 것이 의도하신 내용인 것 같습니다:

rm -fr /tmp/nginx-${VERSION}*

불행히도 업데이트된 /var/discourse/image/base/install-nginx 스크립트가 /var/discourse/launcher destroy app && /var/discourse/launcher/rebuild app을 실행할 때 실행되지 않는 것으로 보입니다.

이 rebuild 명령이 업데이트된 install-nginx 스크립트를 다시 실행하지 않는 데에는 어떤 이유가 있을까요?

재빌드 후 스크립트를 어떻게 수정하고 있나요? 훅을 사용하나요?

vim /var/discourse/image/base/install-nginx

재구축 이후에도 변경 사항을 확인할 수 있나요? 이미지 내 파일을 직접 그렇게 편집하는 방식은 작동하지 않습니다.

app.yml에서 파일을 수정하려면 훅(hooks)을 사용해야 합니다.

이전에 Docker를 사용해 본 적이 있나요?

Docker에 익숙하지 않다면, 이 과정은 다소 어려울 수 있습니다…

discourse_docker는 공개 Docker 레지스트리에 있는 기본 Docker 이미지 소스 코드를 포함하고 있으며, 이 이미지는 로컬에서 실행되지 않습니다. 그 이유는 재사용 가능한 이미지를 제공하기 위해서입니다.

음. 간단함을 위해 vim을 사용한다고 했었는데, 사실은 스크립트를 멱등적이고 견고하게 업데이트하기 위해 아래 명령어를 실행하고 있습니다.

cd /var/discourse/image/base
cp install-nginx install-nginx.`date "+%Y%m%d_%H%M%S"`.orig

# nginx 소스를 다운로드하기 직전에 modsecurity nginx 모듈을 체크아웃하는 블록을 추가
 grep 'ModSecurity' install-nginx || sed -i 's%\(curl.*nginx\.org/download.*\)%# mod_security --maltfield\napt-get install -y libmodsecurity-dev modsecurity-crs\ncd /tmp\ngit clone --depth 1 https://github.com/SpiderLabs/ModSecurity-nginx.git\n\n\1%' install-nginx

# 위에서 체크아웃한 ModSecurity 모듈을 포함하도록 configure 행을 업데이트
sed -i '/ModSecurity/! s%^[^#]*./configure \(.*nginx.*\)%#./configure \1\n./configure \1 --add-module=/tmp/ModSecurity-nginx%' install-nginx

# 정리(cleanup) 섹션에 한 줄 추가
grep 'rm -fr /tmp/ModSecurity-nginx' install-nginx || sed -i 's%\(rm -fr.*/tmp/nginx.*\)%rm -fr /tmp/ModSecurity-nginx\n\1%' install-nginx

부트스트랩 시 컨테이너가 사용하는 실제 install-nginx 스크립트가 수정되도록 이 명령어들을 어디에 배치해야 하나요?