Discourse 인증서 갱신 실패

여기서 대화를 계속합니다:

Redsift에서 인증서가 일주일 안에 만료된다는 알림을 받았습니다. 보통 Discourse는 충분한 시간 전에 인증서를 갱신합니다. 이번에는 그렇지 않았고, 문제를 해결하기 위해 재빌드(이슈를 해결할 것으로 예상됨)를 시작하기 전에 @Falco 님, 인증서가 갱신되지 않은 근본적인 원인을 파악하는 데 도움이 되도록 확인하고 여기에 게시할 사항이 있나요?

루트 인증서는 ISRGX1이며, 만료 예정인 인증서의 정보는 다음과 같습니다:

공용 이름 (CN) E6
조직 (O) Let’s Encrypt
조직 단위 (OU) <인증서에 포함되지 않음>
발급일 2025년 7월 16일 (수) 오후 7:36:45
만료일 2025년 10월 14일 (화) 오후 7:36:44

현재 빌드 버전은 3.6.0.beta1-dev (7ee52c8f85)입니다.

1개의 좋아요

Let’s Encrypt가 필요한 엔드포인트가 리디렉션되던 시기가 있었습니다. 재빌드하면 이 문제가 해결됩니다.

5개의 좋아요

업데이트 후 얼마나 지나면 인증서가 갱신되나요?

기억이 맞다면 인증서는 3개월간 유효하며, 이제 그 전에 자동으로 갱신을 시도할 것입니다.

1개의 좋아요

네, 어떻게 작동해야 하는지는 알고 있습니다.

하지만 포럼 소프트웨어를 업데이트한 지 하루가 지났는데도 인증서가 아직 갱신되지 않은 것 같습니다. 만료까지 5일밖에 남지 않았으니 정말로 서둘러 갱신해야 합니다.

현재 Discourse stable 브랜치를 사용 중인데, 이게 문제가 될 수 있을까요? 엔드포인트 수정이 백포트되지 않았을 수도 있나요?

제게는 재구축 직후 바로 인증서가 업데이트되었습니다.

웹을 통해 재구축했나요, 아니면 명령줄을 통해 재구축했나요?

1개의 좋아요

네, 설명은 여기에 있었습니다:

1개의 좋아요

명령줄로 재빌드한 후, 내 포럼이 마침내 인증서를 업데이트했습니다.

3개의 좋아요

저희도 SSL이 갱신되지 않는 동일한 경험을 했습니다.

discourse-docker에서 web.ssl.template이 올바르게 작동하는지 누군가 재확인해 주시면 좋겠습니다. 제 판단으로는 포트 80이 Let’s Encrypt가 사용하는 /.well-known/ URL을 실제로 서빙하지 않는 것 같았습니다. /var/www/discourse/public/.well-known/에 수동으로 배치한 테스트 파일까지 포함하여 모든 URL이 SSL로 포워딩되고 있었습니다. 결국 앱 컨테이너 내부에서 /etc/nginx/conf.d/outlets/before-server/20-redirect-http-to-https.conf 파일을 직접 수정해야 했습니다.

아마도 discourse-docker의 커밋 ae4887a 이후부터 이런 문제가 시작된 것이 아닐까 싶습니다.

2개의 좋아요

최근에 잘 알려진 루트에서 또 다른 오류가 발생했습니다.

마지막으로 리빌드를 한 시기는 언제입니까?

2개의 좋아요

저도 마찬가지입니다. 인증서 만료에 대한 경고가 나오지 않았습니다. 서버에 접속해서 /var/discourse % ./launcher rebuild 명령으로 재빌드를 실행하니 해결되었습니다.

2개의 좋아요

바닐라 nginx 설치 환경(1.18.0, 1.26.3에서도 동일할 것으로 보임)에서 테스트해 본 결과, location 블록 외부에 return 301 https://thehostname$request_uri;를 작성하면, catch-all이 아니라 그 앞에 있는 모든 location 블록을 완전히 무시하는 것으로 확인되었습니다. /.well-known/는 301 리다이렉트가 서버 블록의 마지막에 /와 같은 다른 location을 대상으로 하지 않는 한, 포트 80에서 단순히 제공되지 않는 것 같습니다. 이는 이 Stack Overflow 게시물과 동일한 문제일 수 있습니다.

rebuild가 작동하는 것은 다행이지만, 제 경우 인증서가 이미 갱신되어 있었기 때문에, 인증서가 만료된 상태였다면 rebuild가 Let’s Encrypt 검증 서버가 해당 경로에 도달할 수 있게 해주는지 확인할 수 없었습니다. 템플릿을 수정하는 것이 아니라, 해당 템플릿 라인이 적용되기 전에 인증서 갱신을 시작하는 등 rebuild가 갱신을 가능하게 하는 다른 원인이 있을 수 있지만, 이것이 rebuild로 갱신이 작동하는 이유인지는 확인할 수 없습니다.

이것이 Discourse라고 생각하신다면, GitHub 커밋에 답글을 달거나 새로운 큰 리포트를 여시는 것이 좋습니다.

1개의 좋아요

letsencrypt 갱신이 실패한다는 것을 확인했습니다. 저는 수년 동안 셀프호스팅된 Discourse를 운영해 왔는데, 매우 이상하게도 지난 몇 달 동안 두 번 연속으로 갱신이 실패했습니다. 두 번째 실패는 오늘 아침에 있었고, 그래서 조사를 시작했습니다.

다음 두 커밋으로 원인을 추적했습니다:

그리고 관련 줄 링크:

https://github.com/discourse/discourse_docker/commit/c9064be6b7a743e3d86dbc69ddaa80701766aa87#diff-b8c95dfe3760424eecc60d21538dbd785f096d46ef95764c60f4b608f40dd536R26

저는 두 가지 문제가 있다고 생각합니다.

첫째, return 301 https://${DISCOURSE_HOSTNAME}$request_uri;가 끝에 $request_uri 없이 return 301 https://<내 서버 이름>으로 변환됩니다. 제 셀프호스팅 설치 환경과 지난주에 설정한 친구의 셀프호스팅 설치 환경에서 모두 확인했습니다. Discourse 템플릿이 어떻게 작동하는지 이해하지 못하므로, 왜 이것이 제거되는지 알 수 없습니다.

둘째, @lessLost가 언급했듯이, 301 리다이렉트는 location 블록 밖에 있습니다. 서버 레벨의 리다이렉트가 모든 location 블록을 무시한다고 생각합니다. LetsEncrypt는 갱신에 http를 사용합니다. 그러나 curl -I http://YOUR_DOMAIN/.well-known/acme-challenge/test를 실행하면 404(예상되는 동작; 301이 아닌 404가 필요합니다) 대신 https로 301이 반환됩니다.

제 셀프호스팅 설치 환경에서는 수동으로 이 문제를 수정했지만, 업데이트 시 제 변경 사항이 덮어써질 것으로 예상됩니다. 불행히도 템플릿을 충분히 이해하지 못해 @pfaffman에게 풀 리퀘스트를 제출할 수 없습니다 — 할 수만 있다면 그렇게 할 것입니다.

수정하여 추가:

이것은 오해인 것 같습니다 —

LetsEncrypt가 기본적으로 http를 사용한다는 것에 대해 상당히 확신합니다(명확한 이유: 인증서가 만료되면 갱신할 수 없으므로!). 하지만 서버 블록 레벨에 301을 배치하면 모든 요청이 https로 301되도록 강제되며, 이는 이 갱신 전략과 일치하지 않습니다.

수정 2: http 갱신 전략에 대한 증거, 하지만 이것을 확인하기 위해 구글에서 검색해 보실 수도 있습니다.

1개의 좋아요

마지막으로 재빌드한 시점은 언제인가요?

오늘 아침, 잠에서 깨어난 지 약 10분 뒤 포럼을 방문했는데 인증서가 또 만료되어 있었다. (지난번에 만료되었을 때 — 약 3개월 전쯤이었나? — 재구성을 통해 갱신한 적이 있었다.)

그 이후로 이 문제를 수정하기 위한 변경 사항이 커밋되었을 것 같지만, 확인하는 데 3개월이 걸리므로 아직 결론을 내리기 어렵습니다. 현재 인증서가 만료되기 약 2주 전에 알림을 설정해 두는 것이 좋습니다.

1개의 좋아요

이것은 사실이 아닙니다.

  1. 위에서 댓글로 첨부한 링크들은 git blame에서 가져온 것입니다. 파일의 최신 버전(관련 라인 링크): discourse_docker/templates/web.ssl.template.yml at 247c71a1e45d32b0b814a8e9d5fdaa4faaf727b9 · discourse/discourse_docker · GitHub
  2. 제 친구의 새 사이트 설치는 일주일 전이었습니다. 위의 템플릿 37번째 줄은 return 301 https://${DISCOURSE_HOSTNAME}$request_uri;라고 되어 있지만, Discourse Docker 컨테이너에서 그녀의 (그리고 제) /etc/nginx/conf.d/outlets/before-server/20-redirect-http-to-https.conf 파일은 return 301 https://<our_discourse_site>;라고 되어 있습니다. $request_uri가 제거되어 있는 것을 주목하세요. 무언가가 이를 사라지게 하고 있습니다! (무엇인지 모르겠지만).
  3. 조사 과정의 일환으로 오늘 아침에 강제 갱신을 시뮬레이션했습니다. 실패했습니다. 그런 다음 /etc/nginx/conf.d/outlets/before-server/20-redirect-http-to-https.conf를 변경했습니다. 성공했습니다!

사실 이건 괜찮습니다. Discourse를 업데이트할 때마다 20-redirect-http-to-https.conf를 수동으로 편집하면 됩니다. 이 댓글에 부딪히는 분들을 위해, 실행해야 하는 명령어는 다음과 같습니다:

cat > /etc/nginx/conf.d/outlets/before-server/20-redirect-http-to-https.conf << 'EOF'
server {
  listen 80;
  listen [::]:80;

  location ~ /.well-known {
    root /var/www/discourse/public;
    allow all;
  }

  location / {
    return 301 https://<YOUR_FORUM_ADDRESS>$request_uri;
  }
}
EOF

이 실패의 원인이 무엇인지 완전히 확신은 하지 못하지만, 위의 conf를 수정하면 해결된다는 것은 알고 있습니다. 또한, letsencrypt 갱신이 더 이상 조용히 실패하지 않도록 notifs도 수정했습니다 — 그래서 사전에 몇 가지 경고를 받을 수 있습니다. 알려드리고 싶어서요!

4개의 좋아요

리포트 감사합니다. 정당한 문제라고 생각합니다.

(참고로 @featheredtoast)

6개의 좋아요