로그인 실패: "알 수 없는 오류"

안녕하세요,

저는 기본 Docker 설치 가이드를 따라 설치한 자체 Discourse 인스턴스를 운영하고 있습니다. 문제가 발생하는 시점은 포럼을 며칠 사용한 후인데, 이때 로그인이 완전히 작동하지 않습니다. 참고로 이 포럼의 유일한 사용자는 저입니다. 불행히도 이 버그의 원인은 알지 못합니다.

재현 방법 #1:

  1. Docker 설치 가이드의 지시에 따라 새로운 Discourse 서버를 설치합니다.
  2. 설정 마법사가 완료되면, 로그아웃과 재로그인이 정상적으로 이루어지는지 확인합니다.
  3. 포럼을 정상적으로 계속 사용합니다. 몇 가지 카테고리와 게시글을 만들고 기본 테마를 변경하는 등의 작업을 수행합니다.
  4. 며칠 또는 몇 주간의 정상적인 사용 후, 로그아웃하면 다시 로그인할 수 없게 됩니다. 로그인 시 “Unknown error”(로그인 양식에 표시됨) 오류가 발생합니다.

재현 방법 #2:

  1. Docker 설치 가이드의 지시에 따라 새로운 Discourse 서버를 설치합니다.
  2. 설정 마법사가 완료되면, 로그아웃과 재로그인이 정상적으로 이루어지는지 확인합니다.
  3. 로그인 실패가 발생했던 다른 Discourse 인스턴스의 백업 파일을 복원합니다.
  4. 복원이 진행 중인 동안 로그아웃되었음을 알리는 팝업 메시지가 표시됩니다. 복원은 성공적으로 완료되었지만, 로그인 시 “Unknown error”(로그인 양식에 표시됨) 오류가 발생합니다.

저도 직접 문제를 디버깅해 보았지만, 관련 있는 오류 메시지를 찾지 못했습니다. 지금까지 시도한 내용은 다음과 같습니다:

cd /var/discourse
./launcher enter app
tail -F log/production_errors.log
tail -F log/production.log
tail -F log/unicorn.stderr.log
tail -F log/unicorn.stdout.log

로그인 실패 시 이 로그 파일들에는 오류 메시지가 표시되지 않습니다. 이 문제를 디버깅하는 데 도움이 될 수 있는 다른 방법은 무엇일까요? 미리 감사드립니다.

관리자로 로그인한 상태에서 웹 브라우저에서 /logs를 확인해 보셨나요?

음, 뭔가 원인을 찾았어요. ‘force https’ 설정을 활성화하는 즉시 로그인에 실패합니다. 제 Discourse 인스턴스는 SSL 터미네이션이 적용된 프록시 서버 뒤에 있습니다. 'force https’를 비활성화하면 다시 로그인이 정상적으로 작동합니다. 따라서 이는 Discourse의 버그라기보다는 제 인프라 구성 문제일 가능성이 높습니다.

또한 말씀하신 대로 조치해 보았지만, 로그에는 오류 메시지가 표시되지 않았습니다.

드디어 해결 방법을 찾았습니다. X-Forwarded-Proto 헤더를 설정해야 하며, 이 헤더는 클라이언트가 프록시 또는 로드 밸런서에 연결할 때 사용한 프로토콜(HTTP 또는 HTTPS)을 식별하는 데 사용됩니다.

프록시 서버로 HAProxy를 사용하므로 HAProxy 설정에 다음 줄을 추가해야 했습니다:

http-request set-header X-Forwarded-Proto https if { ssl_fc }

이제 "force https"가 활성화되어 있어도 로그인 기능이 정상적으로 작동합니다.

Discourse 서버로 설정된 모든 연결에 대해 PROXY 프로토콜도 사용하려고 합니다. PROXY 프로토콜은 수신 측(즉, Discourse 서버)에 들어오는 연결의 주소를 알려주어, 클라이언트의 주소나 접근한 공개 주소를 파악할 수 있게 합니다. 이 변경 사항이 없으면 Nginx는 클라이언트의 주소를 알 수 없으며, 모든 로그에는 리버스 프록시 서버의 주소가 대신 표시됩니다. 다음 변경 사항으로 해결할 수 있습니다:

root@talk3:/var/discourse# git diff
diff --git a/templates/web.template.yml b/templates/web.template.yml
index a60e6ef..55cb5f2 100644
--- a/templates/web.template.yml
+++ b/templates/web.template.yml
@@ -116,6 +116,19 @@ run:
       to: daemon off;

   - replace:
+      filename: /etc/nginx/nginx.conf
+      from: /# server_tokens off;/
+      to: |
+        server_tokens off;
+        real_ip_header proxy_protocol;
+        set_real_ip_from 192.168.1.19;  # address of proxy server
+
+  - replace:
+      filename: "/etc/nginx/conf.d/discourse.conf"
+      from: /listen 80;$/
+      to: "listen 80 proxy_protocol;"
+
+  - replace:
       filename: "/etc/nginx/conf.d/discourse.conf"
       from: /upstream[^\}]+\}/m
       to: "upstream discourse {

그리고 HAProxy에 이 서버에 대해 PROXY 프로토콜 사용을 강제하도록 지시합니다:

-    server server-1 192.168.1.27:80 check
+    server server-1 192.168.1.27:80 check send-proxy

마지막으로 ./launcher rebuild app을 실행하고 이제 클라이언트 주소가 로그에 기록되는지 확인합니다:

tail -F /var/discourse/shared/standalone/log/var-log/nginx/access.log