서브도메인 없이 설치 시 작동하지 않음

안녕하세요, 테스트용 VM인 최신 Ubuntu 20.04에 Discourse를 설치하려고 시도하고 있습니다. (CentOS Stream 9, Ubuntu 22.04, openSUSE MicroOS도 시도해 보았습니다.) 저는 프로젝트 초기부터 Discourse에 대한 경험을 가지고 있으며, 현재 마이그레이션을 위해 이를 평가하고 있습니다. 이 경우 도메인은 mydomain.tld가 될 것입니다. (프로덕션 도메인은 포럼만 사용되며 이름에 "forum"이 포함되어 있고 그렇게 잘 알려져 있으므로, discourse.mydomain.tld를 사용하는 것은 절대 원하지 않습니다.) 서브도메인 없이 Discourse를 설치하려는 최근 시도는 모두 실패했습니다. 약 6년(?) 전 서브도메인 없이 Discourse 포럼을 운영했던 적이 있어 과거에는 가능했음을 알고 있습니다. 현재 설치 과정은 성공적으로 완료되는 것처럼 보이지만, 사이트가 로드되지 않습니다. Ubuntu에서는 명시적으로 http://를 입력해도 자동으로 https://로 전환되며, 아예 로드가 되지 않습니다. CentOS와 MicroOS에서는 http://로 Nginx 환영 페이지가 로드되고, https://로는 아무것도 로드되지 않습니다.

위 운영체제에서 동일한 VM으로 서브도메인 discourse.mydomain.tld에 Discourse를 설치하면 Let’s Encrypt 자동 구성을 포함하여 모두 정상적으로 작동합니다. 도메인 등록업체의 DNS 레코드가 정확하고 적절한 rDNS 해석이 이루어지고 있다고 생각합니다. /etc/hosts의 서버 호스트 이름은 127.0.1.1 mydomain.tld mydomain으로 표시되며, discourse-install 스크립트는 도메인 이름 해석 검사를 통과합니다.

discourse-doctor 출력 결과는 다음과 같습니다. 필요하신 분을 위해 전체 discourse-install 로그도 가지고 있습니다:

DISCOURSE DOCTOR Sun Oct 9 13:32:47 UTC 2022
OS: Linux mydomain 5.4.0-125-generic #141-Ubuntu SMP Wed Aug 10 13:42:03 UTC 2022 x86_64 x86_64 x86_64 GNU/Linux


Found containers/app.yml

==================== YML SETTINGS ====================
DISCOURSE_HOSTNAME=mydomain.tld
SMTP_ADDRESS=mail.mydomain.tld
DEVELOPER_EMAILS=REDACTED 
SMTP_PASSWORD=REDACTED 
SMTP_PORT=587
SMTP_USER_NAME=admin@mydomain.tld
LETSENCRYPT_ACCOUNT_EMAIL=REDACTED 

==================== DOCKER INFO ====================
DOCKER VERSION: Docker version 20.10.12, build 20.10.12-0ubuntu2~20.04.1

DOCKER PROCESSES (docker ps -a)

CONTAINER ID   IMAGE                 COMMAND        CREATED          STATUS         PORTS                                                                      NAMES
d6f7f53a81db   local_discourse/app   "/sbin/boot"   10 minutes ago   Up 4 minutes   0.0.0.0:80->80/tcp, :::80->80/tcp, 0.0.0.0:443->443/tcp, :::443->443/tcp   app


Discourse container app is running


==================== PLUGINS ====================
          - git clone https://github.com/discourse/docker_manager.git

No non-official plugins detected.

See https://github.com/discourse/discourse/blob/main/lib/plugin/metadata.rb for the official list.

========================================
Discourse version at mydomain.tld: NOT FOUND
Discourse version at localhost: NOT FOUND


==================== MEMORY INFORMATION ====================
OS: Linux
RAM (MB): 2029

              total        used        free      shared  buff/cache   available
Mem:           1935         823         547          30         564         934
Swap:          2047           0        2047

==================== DISK SPACE CHECK ====================
---------- OS Disk Space ----------
Filesystem      Size  Used Avail Use% Mounted on
/dev/sda1        38G  8.0G   28G  23% /

==================== DISK INFORMATION ====================
Disk /dev/sda: 38.15 GiB, 40961572864 bytes, 80003072 sectors
Disk model: QEMU HARDDISK   
Units: sectors of 1 * 512 = 512 bytes
Sector size (logical/physical): 512 bytes / 512 bytes
I/O size (minimum/optimal): 512 bytes / 512 bytes
Disklabel type: gpt
Disk identifier: 6643DB1B-E542-4DE1-A04C-C8EB4DAAD77E

Device      Start      End  Sectors  Size Type
/dev/sda1  528384 80003038 79474655 37.9G Linux filesystem
/dev/sda14   2048     4095     2048    1M BIOS boot
/dev/sda15   4096   528383   524288  256M EFI System

Partition table entries are not in disk order.

==================== END DISK INFORMATION ====================

==================== MAIL TEST ====================
For a robust test, get an address from http://www.mail-tester.com/
Mail test skipped.

==================== DONE! ====================

도메인을 알 수 없으니 도움을 주기 어렵습니다. 인터넷의 다른 머신에서 verbose 옵션이 포함된 curl 명령을 domain.tld에 실행하면 어떻게 되나요?

답장 주셔서 감사합니다. 좋은 제안이네요. 연결을 수락하지 않는 것 같습니다:

$ curl -v mydomain.tld
*   Trying 1.2.3.4:80...
* connect to 1.2.3.4 port 80 failed: Connection refused
* Failed to connect to mydomain.tld port 80: Connection refused
* Closing connection 0
curl: (7) Failed to connect to mydomain.tld port 80: Connection refused

$ curl -v https://mydomain.tld
*   Trying 1.2.3.4:443...
* connect to 1.2.3.4 port 443 failed: Connection refused
* Failed to connect to mydomain.tld port 443: Connection refused
* Closing connection 0
curl: (7) Failed to connect to mydomain.tld port 443: Connection refused

Discourse 설정 로직에 제한이 있어서 .tld가 .com이나 .org처럼 일반적인 도메인이어야 한다고 기대하는 것일까요? 제 도메인은 테스트용으로 만든 5달러짜리 .tech 도메인입니다.

가능성은 낮습니다.

서버는 어디에 호스팅되어 있나요? 서버와 클라이언트 사이에 어떤 것이 있나요?

FQDN을 알려주시면 문제 해결에 도움이 됩니다. 현재 상태로는 눈이 가려진 채로 문제를 진단해 달라고 요청하는 것과 같으므로, 원인을 파악하는 데 시간이 좀 걸릴 수 있습니다.

이 인스턴스는 discourse-setup을 사용하여 설치되었나요, 아니면 YML 파일을 수동으로 생성하셨나요?

Hetzner에서 80/443 포트가 열려 있는지 확인해 보셨나요?

요즘은 Let’s Encrypt가 기본적으로 적용되기 때문에 보안 포트로의 리디렉션이 이루어집니다.

저는 discourse-setup를 사용했습니다. 네, 포트는 열려 있습니다. 서브도메인에 설치하는 것은 문제없이 작동하며, 같은 VM에 웹 프런트엔드가 있는 메일서버의 Docker 설치도 설정해 두었습니다(다만 나중에 포맷을 다시 했습니다).

아래 링크를 읽어보셨나요?

음, 아니야. 도메인 등록 대행사는 Hover인데, 보통 꽤 안정적인 편이야. 도메인 루트에 웹사이트를 설정할 때 문제가 생긴 적은 20년 동안 서버를 세팅하면서 한 번도 없었는데, 이건 좀 이상하네…

Hover에서 하나를 가지고 있던 도메인의 경우 작동했던 기억은 없지만, 꽤 오래된 일이었습니다.

NS를 CloudFlare로 변경하고, 비용 없이 DNS가 문제인지 테스트해 볼 수 있습니다.

이렇게 알려주셔서 정말 감사합니다.

NS를 CloudFlare로 변경한 뒤, 비용 없이 DNS가 문제인지 테스트해볼 수 있습니다.

아주 기초적인 질문이지만, 로컬 DNS 서버를 Cloudflare로 설정하라는 말씀인가요? (현재 8.8.8.8을 사용 중입니다.) 아니면 도메인에 다른 DNS 서비스를 사용하라는 뜻인가요?

Hover에 대해 문의했는데, 그들은 다음 내용을 안내해 주었습니다:

Glue 레코드를 사용해 볼 수 있습니다. 이렇게 하면 서버를 DNS 관리자로 설정하고, Glue 레코드를 사용하여 설정할 수 있는 네임서버로 도메인 이름을 라우팅할 수 있습니다. 기본적으로 서버가 네임서버가 되는 것입니다.

Connecting Your Domain Using Private Nameservers (Glue Records) : Hover Customer Support

이것은 여전히 나에게 엉뚱한 방향처럼 느껴집니다. 같은 상황에서 WordPress나 Drupal은 작동하는데, 왜 Discourse는 도메인 루트에서 작동하지 않는지 이해할 수 없습니다.

아니요, 도메인을 등록업체(레지스트라) 간에 이전할 필요는 없지만, 이 가설을 테스트하려면 Hover에서 도메인의 NS 레코드를 업데이트하여 다른 프로바이더의 DNS를 가리키도록 설정해야 합니다. 현재 NS는 ns1.hover.com과 ns2.hover.com으로 설정되어 있습니다.

이 과정은 매우 빠르고 비교적 간편합니다. CloudFlare에 가입한 후 해당 도메인을 추가하려고 하면, 두 개의 새 네임서버가 제공되며 이를 Hover에 입력해야 합니다. Hover 측 설정에 대한 가이드는 여기에서 확인할 수 있습니다:

클라우드플레어(CloudFlare)를 제외하고는 오래전에 아펙스 도메인을 사용했습니다. 잠시 후 제가 직접 테스트해서 다른 함정이 있는지 확인해 보겠습니다. 아펙스 도메인 관련 대부분의 문제는 CNAME 레코드에 적용되지만, 이제 A 레코드를 사용하고 있다는 점을 파악했습니다.

제 생각에는 잘못된 설정으로 인해 여러 번 재구성을 시도했고, 그 결과 레이트 리미팅으로 인해 Let’s Encrypt가 인증서를 발급하지 못하는 것 같습니다.

그렇다면 일주일 정도 기다리거나, 요즘에는 본래 권장되는 방법인 www를 서브도메인으로 사용하는 방법을 시도해 볼 수 있습니다.

/var/discourse/shared/log/var-log/nginx/access.log 파일에서 로그를 확인하거나, 다음과 같이 명령어를 실행해 볼 수 있습니다.

docker logs app

인증서가 존재하지 않거나 유효하지 않다는 오류 메시지가 표시될 것으로 예상됩니다.

현재 app.yml에서 SSL을 비활성화하고 재빌드했으며, 이제 Discourse가 서브도메인 없이 포트 80에서 로드되고 있습니다.

또한 Hetzner DNS를 권위적 DNS로 사용하도록 변경했습니다. 이것이 문제를 해결한 것인지, 아니면 Let’s Encrypt 인증서 발급 실패 문제 때문이었는지는 확신할 수 없습니다. Let’s Encrypt 인증서를 다시 생성하고 SSL을 재활성화할 수 있게 되면, 한 번 더 재빌드한 후 다시 보고드리겠습니다.

몇 번 이상 재구축을 시도해 보셨다면, Let’s Encrypt에서 레이트 리미팅을 받고 있을 가능성이 높습니다. 인증서에 다른 호스트명을 추가하여 이 문제를 우회할 수 있습니다.

네, 하지만 저는 그 방법들이 더 이상 효과가 없다고 생각합니다.

포트 443에 연결되지 않는 이유는 인증서가 손상되어 nginx에서 오류가 발생하기 때문입니다.

빠른 답변을 주셔서 모두 감사합니다. 결국 Let’s Encrypt의 요청 횟수 제한(rate limit) 문제였던 것 같습니다. Hover에서 새로운 도메인을 생성했고, 이번에는 서브도메인 없이 Discourse 설치가 정상적으로 완료되었습니다.

다시 한번 @pfaffman 또는 다른 분들께 질문드립니다. 어리석은 질문일 수 있는데: ./launcher rebuild app을 실행할 때마다 Let’s Encrypt 인증서가 업데이트되나요? 다시 말해, 시행착오를 좀 해보면서 Discourse 인스턴스를 처음부터 다시 세팅하는 것이 아니라 여러 번 연속으로 리빌드(재구축)하면 레이트 리미팅(rate limiting)에 다시 걸릴 수 있나요? 감사합니다.

유효한 인증서가 있으면 모든 재빌드 시마다 이를 다시 요청하지 않을 것이라고 꽤 확신합니다.