신규 설치 후 502 Bad Gateway 오류 발생

안녕하세요,

저는 Discourse를 두 번 설치해 보았습니다. 한 번은 컨테이너로, 현재는 VM에서 설치했습니다. 두 설치 환경 모두에서 Discourse에 접근할 수 없습니다. 어떤 문제가 있는지 잘 모르겠습니다.

Discourse VM 사양:

  • 코어 4개
  • RAM 6GB
  • 저장소 50GB
  • OS: Ubuntu 22.04.3

OS 설치 후 실행한 명령어:

apt update -y && apt upgrade -y && apt wget curl zip git docker.io -y && reboot

이후 다음 가이드를 따랐습니다: discourse/docs/INSTALL-cloud.md at main · discourse/discourse · GitHub

설치가 완료된 후 컨테이너가 실행 중임을 확인할 수 있지만, 502 Bad Gateway 오류가 반환됩니다.

설정 방식: Nginx 리버스 프록시(SSL 포함) → VM. 이 구성은 작동하지 않습니다.
hosts 파일에 직접 추가해도 페이지가 로드되지 않습니다.

설치 로그의 마지막 줄을 보면 Docker가 새로운 네트워크를 생성한 것을 확인할 수 있습니다:

DOCKER_HOST_IP=172.17.0.1 --name app -t -p 80:80 -p 443:443

호스트 머신의 IP를 사용하도록 설정하는 방법은 무엇인가요?
네트워크 안에 또 다른 네트워크를 만들고 싶지 않습니다. 이 VM에는 이 서비스만 실행되므로 Docker가 호스트 IP를 사용하는 것에 문제가 없습니다.

도움 주시면 감사하겠습니다!

Docker 없이 설치할 수 있는 공식 방법이 있을까요?

컨테이너가 공개 IP가 있는 머신에 있나요? 해당 공개 IP에 도메인 이름이 지정되어 있나요?

discourse-setup을 실행했나요? DNS가 유효한지 및 호스트가 사용 가능한지를 확인하는 단계를 통과했나요?

재빌드를 여러 번 실행하여 Let’s Encrypt의 속도 제한에 걸려 인증서를 발급받지 못한 상태인가요?

아니요, 이 머신에는 로컬 IP가 할당되어 있으며 트래픽은 내 방화벽을 통해 해당 로컬 IP로 라우팅됩니다. 이것이 문제가 아닙니다.
공개 IP에는 서버용 A 레코드가 있으며 올바르게 라우팅됩니다. forum.somedomain.com은 → 올바른 서버를 가리킵니다.

예, 설치를 통과했습니다. 컨테이너가 실행되는 지점까지 100% 완료했습니다(3번).
모든 도메인/DNS 검사를 통과했습니다. 유효하다고 표시됩니다.

아니요, SSL 인증서는 내 리버스 프록시를 통해 발급되므로 레이트 리미트에 걸릴 수 없습니다. 인증서를 가지고 있습니다.

이 설치는 100% 완료되었습니다. 문제는 Docker가 172.17.0.1이라는 새로운 네트워크를 생성하는 것입니다. 저는 HOST 로컬 IP인 192.xx.xx.xx를 사용하길 원하므로 이는 필요하지 않습니다.

컨테이너는 실행 중이지만 다른 네트워크에서 실행되고 있습니다. HOST IP로 설정할 수 없습니다.

Docker 호스트는 호스트 서버의 IP(192.xxx.xxx.xxx)여야 하며 새로운 네트워크가 아닙니다. 아마도 작동은 하지만 그 네트워크에서 작동하고 있는 것 같습니다.
설치 과정에서 내 로컬 IP를 사용하고 172.17.0.1을 사용하지 않도록 어떻게 지시해야 하나요?

@pfaffman 이런 식으로요. 작성하신 댓글에서 가져왔습니다

설치 시 ./discourse-setup에 호스트 IP 192.168.1.X와 네트워크를 어떻게 설정하나요?

리버스 프록시를 사용하는 경우 discourse-setup을 사용할 수 없습니다. yml 파일을 직접 편집해야 합니다. 같은 머신에서 다른 사이트와 함께 discourse를 실행하는 방법에 대한 몇 가지 토론 주제가 있습니다.

SSL 처리를 리버스 프록시로 수행하는 경우, ssl 및 let’s encrypt 템플릿을 제거해야 합니다.

그게 바로 문제인데요, 저는 이 머신에서 다른 서비스를 실행하지 않습니다. 스탠드얼론 VM입니다.

오해가 있는 것 같습니다.

./docker-setup은 정상적으로 설치됩니다. 앱 전용 네트워크 172.17.0.1을 생성합니다.

인스톨러나 도커 컨테이너가 자체 네트워크를 생성하는 대신 브리지 네트워크를 사용하여 호스트 IP 192.168.1.X를 사용하게 하는 방법은 무엇인가요?

하지만 당신은 이렇게 말씀하셨습니다:

리버스 프록시를 사용 중이라면 discourse-setup을 사용할 수 없습니다.

네, 리버스 프록시는 다른 서버에 있지만 말씀하신 내용을 이해했습니다.

하나의 아이디어가 있습니다. 제 네트워크의 모든 트래픽을 도커 컨테이너 네트워크로 라우팅할 생각입니다.

nginx 리버스 프록시 뒤에 discourse를 실행하는 방법에 대한 설치 가이드가 있을까요?

아니면 discourse를 직접 빌드할 수 있는 방법이 있을까요?

그건 꽤 자명한 문제입니다. app.yml에서 Nginx가 트래픽을 전달하는 HTTP 포트가 허용되어 있고, SSL이 비활성화되어 있습니다. 이 두 가지만 수정하면 됩니다. 물론 실제 IP를 전달해야 하지만, 백엔드가 Discourse, Moodle, WordPress, 기타 무엇이든 항상 그렇게 해야 합니다. UFW는 백엔드에 대한 직접 접근을 허용할 필요가 없으므로, 프론트엔드와 백엔드 사이의 접근만 제한하려고 합니다.

기억이 맞다면 Apache2를 설정하는 문서가 여기에 있습니다. Nginx도 같은 일을 하지만, 물론 그만의 방식으로 수행합니다.

아니면 제가 지금 뭘 놓치고 있는 건가요?

처음부터 다시 설명해 드리겠습니다. 제가 놓치고 있는 단순한 부분이 있는지 확인해 주셨으면 합니다.

저는 Nginx 리버스 프록시를 사용하고 있습니다. 이 프록시는 공개 IP를 관리하고 서비스를 라우팅하는 역할을 합니다.

예: 클라이언트가 cloud.domain.com을 요청 → Nginx 리버스 프록시 (SSL 처리) → cloud.domain.com으로 포인터 설정

현재 저는 Discourse를 위해 VM을 설정했으며, 다음과 같은 명령을 사용했습니다.
Ubuntu 23.04. OS 설치 후 실행한 명령:

apt update -y \
apt upgrade -y \
apt install wget curl zip git docker.io -y

그 후 Discourse의 이 가이드를 따랐습니다: discourse/docs/INSTALL-cloud.md at main · discourse/discourse · GitHub

설정은 성공적으로 완료되었지만, 그 이후로 문제가 시작됩니다.

docker0 네트워크 때문에 호스트에서 도커 컨테이너에 접근할 수 없습니다. 172.17.0.2에는 ping이 가능하며 컨테이너는 정상적으로 실행 중이지만, 호스트 머신(192.168.1.10)의 80/443 포트에서 컨테이너로 트래픽이 전달되지 않습니다.

저희가 원하는 것은 컨테이너가 80 및 443 포트를 노출하고 있으므로 호스트 네트워크를 사용하도록 하는 것입니다.

첫 번째 Nginx 리버스 프록시는 외부 트래픽을 처리하여 VM으로 올바르게 전달합니다. 그렇지 않았다면 ./discourse-setup이 도메인 이름을 올바르게 인식하지 못했을 것이고, 컨테이너의 SSL 인증서를 가져올 수도 없었을 것입니다.

결론적으로, 컨테이너가 100% 정상 작동한다는 것은 알고 있지만, 도커 네트워크 문제로 인해 접근할 수 없는 상태입니다.

추가 정보가 필요하시면 알려 주세요.

이 문제를 해결하는 또 다른 방법은 discourse 기본 이미지를 사용하는 것입니다.

그리고 docker compose 등을 사용하여 자체 오케스트레이션을 구축할 수 있습니다 (redis와 postgres와 같은 다른 서비스도 필요하다는 점을 기억하세요).

Nginx 또는 Nginx+Varnish를 사용하여 같은 VPS에 Discourse를 실행하거나, 다른 IP의 VPS에 실행하는 것이 가능합니다. Nginx가 리버스 프록시로 작동할 때 실제로 무엇을 하는지 말씀해 주시지 않으셨습니다. 예제들이 조금 이해하기 어려운 이유는, 그것이 단순한 예시인지 아니면 실제로 사설 네트워크를 사용하려는 것인지 알 수 있는 방법이 없기 때문입니다.

하지만:

물론이죠. 그 포드는 수신되는 트래픽을 처리하는 용도이므로, 백엔드에는 다른 포트를 사용해야 합니다.

아래와 같은 설정을 사용하세요 (이것은 실제로 Varnish와 함께 사용되지만, 원리는 완전히 동일하며 매우 기초적인 내용입니다):

proxy_pass http://127.0.0.1:8080;
proxy_set_header X-Real-IP  $remote_addr;
proxy_set_header X-Forwarded-For
 $proxy_add_x_forwarded_for;
proxy_set_header X-Forwarded-Proto https;
proxy_set_header X-Forwarded-Port 443;
proxy_set_header Host $host;
proxy_pass_header Server;

이해합니다. 구체적으로 알려주셔서 감사합니다 :).

이 도커 네트워크가 혼란스럽기 때문에 어떤 것이 문제인지 확신이 서지 않습니다.

그렇기 때문에 도커 때문에 좌절하고 있는 것입니다 lol

아래는 WAN 네트워크가 nginx 리버스 프록시를 통해 트래픽을 올바른 호스트로 전달하고 라우팅하는 정확한 방식입니다.

map $scheme $hsts_header {
    https   "max-age=63072000;includeSubDomains; preload";
}

server {
  set $forward_scheme https;
  set $server         "10.10.1.38";
  set $port           443;

  listen 80;
listen [::]:80;

listen 443 ssl http2;
listen [::]:443 ssl http2;


  server_name forum.domainname.com;

  # Let's Encrypt SSL
  include conf.d/include/letsencrypt-acme-challenge.conf;
  include conf.d/include/ssl-ciphers.conf;
  ssl_certificate /srv/ssl/domainname.pem;
  ssl_certificate_key /srv/ssl/domainname-ke.pem;


# Asset Caching
include conf.d/include/assets.conf;

# Block Exploits
include conf.d/include/block-exploits.conf;

# HSTS (ngx_http_headers_module is required) (63072000 seconds = 2 years)
add_header Strict-Transport-Security $hsts_header always;

# Force SSL
include conf.d/include/force-ssl.conf;

proxy_set_header Upgrade $http_upgrade;
proxy_set_header Connection $http_connection;
proxy_http_version 1.1;


access_log /var/logs/domainname-access.log proxy;
error_log /var/logs/domainame_error.log warn;

proxy_set_header  X-Real-IP $remote_addr;
proxy_set_header  X-Forwarded-For $http_x_forwarded_for;
proxy_set_header  X-Forwarded-Proto $scheme;

location / {

  # HSTS (ngx_http_headers_module is required) (63072000 seconds = 2 years)
  add_header Strict-Transport-Security $hsts_header always;

    proxy_set_header Upgrade $http_upgrade;
    proxy_set_header Connection $http_connection;
    proxy_http_version 1.1;
    
    # Proxy!
    include conf.d/include/proxy.conf;
  }
}

이상한 점은, 이전에 클라이언트가 nginx 리버스 프록시 매니저를 원했을 때 도커 컨테이너를 설정해준 적이 있는데, 그때는 매우 간단했습니다.

docker-compose up -d
그것뿐이었죠. 프라이빗 IP 192.168.1.3은 컨테이너의 노출된 80/443 포트에 도달할 수 있었고, 발신 트래픽은 192.168.1.3으로 올바르게 라우팅되었습니다.

패킷 처리 시스템이 자체 샌드박스 안에서 작동하기 때문에 헷갈리는 겁니다. 기본적으로 그 정도 수준입니다.

하지만 도커를 이해하는 것과 사용하는 것은 별개의 문제입니다 (그리고 요즘 개발자분들이 꽤나 난감해하고 계시죠 :rofl:). 리버스 프록시가 방화벽을 통해 해당 IP로 트래픽을 보내고 있으며, 해당 IP와 리스닝 포트(청취 포트)를 지정해야 합니다. 그리고 그 IP에는 app.yml에서 지정한 포트에서 도커(즉, 디스커스)가 실행되고 있습니다. 디스커스와 함께 작동하는 내부 Nginx가 나머지 작업을 처리합니다.

SSL이 이미 리버스 프록시에서 종료(terminate)되었으므로, 디스커스는 443 포트를 리스닝하지 않아야 합니다.

또한 리버스 프록시에서 캐싱을 기본적으로 사용할 수 없습니다. 백엔드인 디스커스는 웹 페이지가 아니라 자바스크립트와 JSON을 전송하는 웹 애플리케이션이므로 그렇습니다.

그 부분은 어렴풋이 짐작은 하고 있었습니다.

이 부분은 전적으로 동의합니다. 울고 있다는 표현보다는, 리눅스를 제대로 다루는 시스템 관리자와 개발자들에게는 그냥 쓸모없는 것일 뿐이라고 말하는 게 더 적절할 것 같습니다. 격리된 LXC나 VM을 만든 뒤, 그 안에서 Docker가 또 다른 격리 환경을 만드는 것은 중복되고 무의미합니다.

이 부분이 가장 혼란스럽습니다. app.yml은 172.17.0.2에서 80:80과 443:443을 노출하고 있으며, 이 IP는 Docker 네트워크 172.17.0.1/16 내에 있고, VM의 IP는 10.10.1.38입니다.

10.10.1.38로 들어오는 모든 트래픽이 172.17.0.2로 전달되고, 나가는 모든 트래픽은 10.10.1.38을 통해 나가도록 Discourse/Docker를 설정하는 방법은 무엇인가요? 이 문제를 해결하는 데 필요한 것은 오직 이것뿐입니다. 정말로요.

WAN에서 forum.domainname.com으로의 라우팅은 제 리버스 프록시가 처리할 예정입니다.

캐싱은 제거해 두었습니다.

그 값들을 변경하지 않는 경우에만 해당됩니다. 변경해야 하며, 포트는 하나만 사용해야 합니다.

80:80과 443:443은 기본값이며, 프론트엔드로 동작하는 리버스 프록시나 기타 구성 요소가 없을 때만 기본적으로 사용됩니다.

좋은 아이디어를 주셨네요.

기본 파일들을 전부 확인하느라 바빴는데, 이제야 원인을 파악한 것 같아요.

이렇게 단순하네요, ㅋㅋ. 지금 다시 구축하고 있는데, 공식적으로 지원되는 표준 설치 방법을 사용하면 100% 잘 작동할 수도 있을 것 같아요.

성공 포럼이 이제 설치되어 정상적으로 작동합니다.

표준적이고 지원되는 설치 방법 사용 :smiley:


@pfaffman 현재 지원되는 설치 방법이므로 이 내용을 설치 항목으로 이동할 수 있습니다.

그곳에 있습니다. 다만 '지원되지 않음’으로 태그되어 있을 뿐이죠 :smirking_face:

그렇다면 왜 리버스 프록시 없이 설치를 시작하지 않았던 건가요? 그냥 궁금해서요.