2025-08-21 최신 릴리스로 업그레이드 실패

최신 업그레이드를 위해 launcher에서 앱을 다시 빌드해야 했지만, 실패했습니다.

먼저 adplugin을 별도 설치로 보유하고 있다는 오류가 발생하여, 해당 항목을 제거했습니다.

이후 secondsite 데이터베이스를 마이그레이션하는 동안 실패한 것으로 보입니다:

2025-08-21 06:44:42.493 UTC [867] discourse@discourse_nu ERROR: must be owner of extension vector
2025-08-21 06:44:42.493 UTC [867] discourse@discourse_nu STATEMENT: ALTER EXTENSION vector UPDATE TO ‘0.7.0’;


1개의 마이그레이션 실패!

seconsite 마이그레이션 실패

원인

  • 마이그레이션이 “vector” 확장을 업그레이드하려고 합니다.
  • 마이그레이션을 실행하는 PostgreSQL 사용자(예: discourse)가 해당 확장의 소유자여야 하지만, 실제로는 다른 사용자(대부분 postgres)가 소유하고 있습니다.

해결 방법

  • 소유자로 데이터베이스에 연결하세요.
  • 소유자로 업데이트를 실행하세요.

같은 문제에 대한 토론을 확인하세요: Still an issue: ERROR: must be owner of extension vector - #2 by Falco

그렇게 하면 해결되었습니다.

하지만 1년 넘게 전부터 보고한 nginx와 secondsites 관련 문제는 여전히 남아 있습니다.

컨테이너 내의 nginx 설정 파일에서 URL이 첫 번째 사이트가 아닌지 확인하고, 그렇지 않으면 해당 사이트로 변경하는 로직이 있습니다. 해당 코드를 다시 주석 처리했습니다.

nginx 설정 처리 방식에 큰 변화가 있었습니다.

리버스 프록시 없이 멀티사이트 구성을 사용하고 계신가요?

글쎄요, 제가 nginx를 직접 살펴본 지 거의 2년이 되어 가지만, 이 문제는 2년 전 Discourse로 이전했을 때부터 존재했었기 때문에 새로운 문제가 아닙니다.

nginx.conf 파일의 일부는 다음과 같습니다:

server {
    server_name  huskerlist.tssi.com;
    root         /var/www/html;

    allow 162.210.7.125;
    allow 162.210.7.112;
    allow 162.210.7.116;
    allow 76.84.125.160;
    allow 172.17.0.2;
    allow 72.250.242.47;
    allow all;

    if ( $lockdown ) {
       set $custom_server_name "lists.tssi.com";
       return 300 "site is down for maintenance";
    }


    client_max_body_size 100M;

    # 기본 서버 블록을 위한 설정 파일 로드.
    #include /etc/nginx/default.d/*.conf;

    location / {
            proxy_pass https://127.0.0.1:8443/;
            #proxy_pass http://unix:/var/discourse/shared/standalone/nginx.http.sock;
            proxy_set_header Host $http_host;
            proxy_http_version 1.1;
            proxy_set_header X-Forwarded-For $proxy_add_x_forwarded_for;
            proxy_set_header X-Forwarded-Proto $scheme;
            proxy_set_header X-Real-IP $remote_addr;
    }

    error_page 404 /404.html;
        location = /usr/share/nginx/html/40x.html {
    }

    error_page 500 502 503 504 /50x.html;
        location = /usr/share/nginx/html/50x.html {
    }

listen [::]:443 ssl; # Certbot이 관리
listen 443 ssl; # Certbot이 관리
ssl_certificate /etc/letsencrypt/live/lists.tssi.com/fullchain.pem; # Certbot이 관리
ssl_certificate_key /etc/letsencrypt/live/lists.tssi.com/privkey.pem; # Certbot이 관리
include /etc/letsencrypt/options-ssl-nginx.conf; # Certbot이 관리
ssl_dhparam /etc/letsencrypt/ssl-dhparams.pem; # Certbot이 관리

}

server {
    server_name  nu-sports.tssi.com;
    root         /var/www/html;

    allow 162.210.7.125;
    allow 162.210.7.112;
    allow 162.210.7.116;
    allow 76.84.125.160;
    allow 172.17.0.2;
    allow 72.250.242.47;
    allow all;

    if ( $lockdown ) {
       set $custom_server_name "lists.tssi.com";
       rewrite ^ https://lists.tssi.com/n-maint.html;
    }
    client_max_body_size 100M;

    # 기본 서버 블록을 위한 설정 파일 로드.
    #include /etc/nginx/default.d/*.conf;

    location / {
            proxy_pass https://127.0.0.1:8443/;
            #proxy_pass http://unix:/var/discourse/shared/standalone/nginx2.http.sock:;
            proxy_set_header Host $http_host;
            proxy_http_version 1.1;
            proxy_set_header X-Forwarded-For $proxy_add_x_forwarded_for;
            proxy_set_header X-Forwarded-Proto $scheme;
            proxy_set_header X-Real-IP $remote_addr;
    }

    error_page 404 /404.html;
        location = /usr/share/nginx/html/40x.html {
    }

    error_page 500 502 503 504 /50x.html;
        location = /usr/share/nginx/html/50x.html {
    }

listen [::]:443 ssl; # Certbot이 관리
listen 443 ssl; # Certbot이 관리
ssl_certificate /etc/letsencrypt/live/lists.tssi.com/fullchain.pem; # Certbot이 관리
ssl_certificate_key /etc/letsencrypt/live/lists.tssi.com/privkey.pem; # Certbot이 관리
include /etc/letsencrypt/options-ssl-nginx.conf; # Certbot이 관리
ssl_dhparam /etc/letsencrypt/ssl-dhparams.pem; # Certbot이 관리

}

어떤 이유로든 새 컨테이너가 설정될 때마다 (예: 재부팅 시) 다음 파일이 다시 작성됩니다.

/etc/nginx/conf.d/outlets/server/20-https.conf

이 파일의 다음 줄들이 기본 discourse 시스템으로의 리다이렉트를 유발합니다:

if ($https_host != huskerlist.tssi.com) {

rewrite (.$) https://huskerlist.tssi.com

}

이를 방지할 방법이 있을까요? 이 코드의 목적은 무엇인가요?

맞습니다. 컨테이너 내부에서 해당 파일을 편집하고 계신가요? 새 컨테이너를 빌드하면 새 컨테이너가 생성됩니다. 그 파일만 다시 작성하는 것이 아니라 모든 파일을 다시 작성합니다.

app.yml에 내용을 추가하여 파일이 다시 작성된 후에 파일을 변경할 수 있습니다.

해당 파일에 어떤 변경 사항을 넣고 계신가요? 왜 그러시나요?

아, 잠깐.

이 질문에 답을 주지 않으셨지만, 답은 '예’라고 생각합니다.

사이트가 하나의 호스트네임으로만 사용 가능하도록 강제하는 것입니다. (보통 사이트가 여러 호스트네임으로 동시에 사용 가능하기를 원하지 않으므로)

따라서 app.yml에 해당 동작을 되돌리는 코드를 추가해야 합니다.

오래전에 이 문제에 대한 해결책을 Setup Multisite Configuration with Let's Encrypt and no Reverse Proxy 에 가지고 있었습니다.

따라서 exec에 sed를 추가하거나 replace 구문을 사용하여 해당 부분을 제거하거나 수정해야 합니다. 아마도 멀티사이트를 위해 그 토픽의 내용을 따르는 것이 여전히 필요할 것입니다(아직 작동할 것으로 생각합니다) 이제 DISCOURSE_HOSTNAME_ALIASES: www.domain.com,otherdomain.org,www.otherdomain.org를 사용하여 추가 호스트네임에 대한 인증서를 발급받을 수 있습니다.

가장 지적인 해결책은 if ($http_host != 코드에 다른 호스트네임 별명을 어떻게든 추가하는 것일 수 있습니다. 현재 그렇게 설정된 사이트가 없어서 재미로 시간을 들여 조사하고 싶지는 않습니다.

하지만 네, web ssl template에는 다음이 있습니다:

        if (\$http_host != ${DISCOURSE_HOSTNAME}) {
          rewrite (.*) https://${DISCOURSE_HOSTNAME}\$1 permanent;
        }

따라서 이를 삭제하거나 다른 호스트네임도 확인하도록 만드는 방법을 찾아야 합니다.

결국 말씀하시는 것은, 하나의 서버에 두 개의 독립적인 포럼을 호스팅하기 위한 ‘secondsite’ 방식이 깨져 있고, 수정 대상 목록에도 포함되어 있지 않다는 것이군요.

따라서 이를 삭제하거나, 다른 호스트명도 확인하도록 하는 방법을 찾아야 합니다.

저는 컨테이너에서 해당 코드를 삭제하는 방식으로 처리해 왔지만, 컨테이너가 시작되거나 새로운 컨테이너 이미지가 생성될 때마다 해당 코드가 다시 복원됩니다. 따라서 소스 어딘가에서 수정이 이루어져야 하며, 새로운 컨테이너를 빌드할 때 app.yml에서 여러 도메인을 올바르게 확인하도록 빌드되어야 합니다. (그 3줄의 코드를 단순히 삭제하는 것보다 이것이 더 바람직할 것입니다.)

웹 SSL 템플릿을 빌드하는 코드가 app.yml에서 secondsite(그리고 thirdsite 등)를 확인하도록 업데이트되지 않는다면, 이는 app.yml에서 처리되어야 하는 문제로 보입니다. 이는 저에게만 적용되는 맞춤형 수정이 되며, 여러 포럼을 단일 서버에서 운영하는 모든 사용자를 위한 수정이 아닙니다. 특히 secondsite 방식은 현재 깨져 있는 것으로 보입니다.

현재 저는 클라이언트를 위한 대규모 시스템 마이그레이션 프로젝트 진행 중이며, 해당 사이트들은 아무튼 축구 시즌 동안 가장 활발하게 운영됩니다. 따라서 라이브 시스템을 즉석에서 수정하기보다, app.yml 수정 사항을 테스트하기 위해 테스트베드 서버를 설정해야 합니다.

잠시 생각해보니, SSL 템플릿을 수정하는 것은 다소 까다로운 문제입니다.

현재 로직은 다음과 같습니다: 사이트가 A가 아니라면, A로 변경하십시오.

세컨드 사이트(secondsite)를 도입하면 상황이 복잡해집니다. 사이트가 A도 아니고 B도 아닐 때, A 또는 B 중 하나로 변경하는 것이 올바른 조치인지 명확하지 않기 때문입니다. (이것이 Discourse에서 아직 이 문제를 다루지 않은 이유일 수 있습니다.)

결국 여러 사이트가 존재하는 경우, 해당 코드 줄을 삭제하는 것이 옳을 수 있습니다. 외부 nginx 서버는 A 또는 B와 일치하는 HTTPS 패킷만 전달해야 하기 때문입니다. HTTP를 HTTPS로 강제 전환하는 작업은 이미 외부 nginx 서버에서 이루어지고 있어야 합니다.

그것은 지원할 항목 목록에 포함된 적이 없습니다. 항상 권장되던 방법은 리버스 프록시를 사용하는 것이었습니다. 저는 리버스 프록시 없이 이를 수행하는 방법을 고안해냈습니다. 그리고 제 해킹 방식은 몇 년 전에 고장 났습니다.

리버스 프록시 없이 멀티사이트를 구성하는 것은 항상 쇼맨십에 불과했습니다. 전문가라면 SSL과 Let’s Encrypt 템플릿을 제거하고, SSL을 처리하는 리버스 프록시를 사용하는 것이 좋습니다. Cdck는 haproxy를 사용합니다. 저는 traefik을 사용해 왔습니다. Caddy는 관리가 꽤 쉽습니다. 하지만 저는 사용을 중단했는데, 이는 누군가가 자신의 사이트 CNAME을 제거하면 모든 인증서 갱신이 실패했기 때문입니다(이것이 더 이상 그런 것은 아닐 수 있으며, 이미 몇 년이 지났습니다).

nginx의 proxy_pass를 사용하여 두 개의 다른 FQDN에 대한 트래픽을 컨테이너로 전달하고 있는 경우, 이것이 멀티사이트를 위한 리버스 프록시 방식을 사용하고 있다는 의미인가요?

네. 그거 잊어버렸네요!

nginx 프록시로 https를 처리하도록 하고, yml 파일에서 ssl 및 let’s encrypt 템플릿을 제거한 뒤 다시 빌드하세요.