Discourse 설치 중 Bootstrap 오류: ENOENT - /etc/runit/1.d/letsencrypt

안녕하세요. 표준 ./launcher rebuild app 프로세스를 사용하여 Discourse를 설치하려고 하는데, 부트스트랩 단계에서 오류가 발생하고 있습니다:

FAILED
--------------------
Errno::ENOENT: No such file or directory @ rb_sysopen - /etc/runit/1.d/letsencrypt
Location of failure: /usr/local/lib/ruby/gems/3.3.0/gems/pups-1.3.0/lib/pups/replace_command.rb:11:in `read'
replace failed with the params {"filename"=>"/etc/runit/1.d/letsencrypt", "from"=>"/--keylength/", "to"=>"-d forum.mysite.org --keylength"}
bootstrap failed with exit code 1
** FAILED TO BOOTSTRAP ** please scroll up and look for earlier error messages, there may be more than one.

오류는 부트스트랩 중 컨테이너 내에 존재하지 않는 /etc/runit/1.d/letsencrypt 파일에 대해 replace 명령을 실행하려는 플러그인으로 인해 발생하는 것으로 보입니다. 해당 플러그인의 관련 부분은 다음과 같습니다:

- replace:
    filename: "/etc/runit/1.d/letsencrypt"
    from: "/--keylength/"
    to: "-d forum.mysite.org --keylength"

이 문제를 수정하거나 누락된 파일을 올바르게 재생성하는 방법에 대한 조언을 주실 수 있을까요?

미리 감사드립니다.

플러그인? 그것은 당신의 app.yml에 있는 cups 코드일 텐데 맞습니까? 다른 인증서를 추가하려는 건가요? 여기에서처럼요? 실제 코드와 두 인증서를 포함해 주실 수 있나요?

말씀하신 대로, 그 runit은 더 이상 존재하지 않으며, 이제 그 마법은 컨테이너 내부의 /usr/local/bin/letsencrypt에 있습니다.

사이트가 www.mysite.org이고 forum.mysite.org에 대한 인증서도 필요하시다면, 아마 다음과 같은 것이 필요할 것이라 생각합니다:

- replace:
    filename: "/usr/local/bin/letsencrypt"
    from: "/-d www.mysite.org/"
    to: "-d www.mysite.org -d forum.mysite.org "
    global: true

제가 할 것(당신에게는 도움이 안 될 수도 있지만)은 컨테이너에 들어가서 apt update;apt install -y vim을 실행한 후, /usr/local/bin/letsencrypt를 편집하여 원하는 인증서를 요청하도록 하는 것입니다.

위에서 링크한 Let’s Encrypt 토픽에 코드를 추가했는데, 이 코드를 사용하면 도메인을 입력하고 app.yml에 복사/붙여넣기할 수 있는 코드를 얻을 수 있습니다.

업데이트를 시도하던 중 동일한 것으로 보이는 오류 메시지를 확인했습니다.

임박한 업데이트가 필요하다는 메시지가 표시되기 전까지는 모든 것이 정상적으로 작동하고 있었습니다.

포럼 업데이트 웹페이지를 통해 Docker Manager를 업데이트하려고 클릭했을 때(나머지 업데이트 전에) - 다음과 같은 결과가 나타났습니다.

You are running an old version of the Discourse image
Updates via the web UI are disabled until you run the latest image. To do so log in to your server using SSH and run:

    cd /var/discourse
    ./launcher rebuild app

위 지침을 따랐더니 두 번째 단계에서 PuTTY에 다음과 같은 결과가 나타났습니다:

Errno::ENOENT: No such file or directory @ rb_sysopen - /etc/runit/1.d/letsencrypt
Location of failure: /usr/local/lib/ruby/gems/3.3.0/gems/pups-1.3.0/lib/pups/replace_command.rb:11:in `read'
replace failed with the params {"filename"=>"/etc/runit/1.d/letsencrypt", "from"=>"/--keylength/", "to"=>"-d www.nzarchitecture.net.nz --keylength"}
bootstrap failed with exit code 1

저는 인증서와 관련된 것을 변경하려는 것이 아닙니다. 또한 여러 도메인 설정이나 리다이렉트 설정도 시도하지 않았습니다.

원래 게시자처럼, 제 app.yml 파일에도 현재 다음과 같은 내용이 표시됩니다.

 after_ssl:
    - replace:
        filename: "/etc/runit/1.d/letsencrypt"
        from: /--keylength/
        to: "-d www.nzarchitecture.net.nz --keylength"

제안하신 내용을 따라

 apt update;apt install -y vim

을 실행했지만 결과는 다음과 같았습니다.

vim is already the newest version (2:9.1.0016-1ubuntu7.8).

두 번째로 제안된 단계에 대해서는, 아무것도 변경할 의도가 없었기 때문에 어떤 인증서가 필요한지 전혀 모르겠습니다.

/usr/local/bin/letsencrypt 폴더를 확인해 보았지만, 이는 빈 폴더입니다.

이러한 무지에 대해 죄송합니다!

다시 업데이트해야 하는 백업을 복원하는 방법 없이 포럼을 정상적으로 다시 구동하려면 어떻게 해야 하나요?

가능하다면, PuTTY에 붙여넣을 수 있는 간단한 명령어 시리즈가 이상적일 것 같습니다.

저만 이런 문제를 겪는 것이 아니므로, 포럼 웹사이트에서 호출되는 표준 docker manager 업데이트 스크립트에서 다른 사용자들이 이 오류를 피할 수 있도록 조정해야 할 부분이 있을까요?

좋아요, 몇 시간 동안 헤맨 끝에 다시 정상 작동하게 만들었습니다.

구버전의 app.yml 파일을 찾아서 이를 대체했는데, 이후 Discourse에 통합된 플러그인에 대한 기존 참조 항목들을 단순히 삭제했습니다.

이 구버전의 app.yml 파일에는 아래에 있는 코드가 포함되어 있지 않았습니다. 이 코드는 나중에 생긴 버전의 파일에서 발견했습니다.

 after_ssl:
    - replace:
        filename: "/etc/runit/1.d/letsencrypt"
        from: /--keylength/
        to: "-d www.nzarchitecture.net.nz --keylength"

제가 직접 이 코드를 넣은 기억은 없습니다. 무료 보안 인증서를 위해 letsencrypt를 사용하도록 사이트를 설정하긴 했지만, Set up HTTPS support with Let's Encrypt 의 지침에는 이러한 줄이 전혀 필요하지 않은 것 같아, 이 코드가 무슨 용도였는지 알 수 없습니다.

app.yml 파일에 이 줄들을 쓴 것이 다른 것이 있을까요? 예를 들어 베타 업데이트 과정에서 추가된 것일 수도 있을까요?

어쨌든 지금은 그 줄들이 사라지면서 사이트가 다시 작동하고 최신 상태입니다.

현재 SSL 인증서가 만료될 때쯤이면, 그 추가된 줄들이 어떤 용도였는지 알게 될 것 같습니다.

네, 그렇게 하고 계신 겁니다. 다만 기억나지 않으시는 것뿐이죠. :wink:

yml 파일에 after_ssl 스탠사가 있다면, 누군가 도메인 앞에 www를 붙여 넣었을 때 www 주소로 이동한 후 인증서 오류 없이 비-www 주소로 리다이렉트되도록 설정을 한 적이 있다는 뜻입니다.

제 제안은 컨테이너 안에 vim을 설치하고 거기서 파일들을 직접 수정해 보라는 것이었습니다. 하지만 app.yml에 추가해야 할 제 코드는 작동할 것이라 생각합니다.

그렇죠. 그리고 이제 https://www.nzarchitecture.net.nz/ 에 접속하면 인증서 오류가 발생합니다. https://forcewww.com/ 을 사용할 수 있습니다.

위 링크로 가서 제가 작동할 것이라 생각하지만, 업그레이드할 때 필요한 사이트를 찾지 못해 테스트하지는 못한 새로운 코드를 가져올 수 있습니다.

[quote="pfaffman, post:5, topic:376416"]
`app.yml`에 추가할 내 코드는 작동할 것 같습니다.

[/quote]

www.nzarchitecture.net.nz 도메인이 nzarchitecture.net.nz와 동일한 Let's Encrypt 인증서를 사용하려면, 제 코드가 아래와 같은 형태가 되어야 하는지 맞는지 확인하고 싶습니다.

after_ssl:
- replace:
filename: /usr/local/bin/letsencrypt
from: /-d nzarchitecture.net.nz /
to: "-d nzarchitecture.net.nz -d www.nzarchitecture.net.nz "
global: true


이 스탠스(stanza)(좋은 용어네요, 감사합니다!)를 기존 'after_ssl:' 스탠스 대신 app.yml 파일의 끝에 추가해 보았습니다. 이제 Discourse를 에러 없이 다시 빌드할 수는 있지만, 문제는 해결되지 않았습니다. 메인/인증된 도메인 nzarchitecture.net.nz 앞에 'www' 접두사를 붙여 사용하려고 하면 브라우저가 여전히 'net::ERR_CERT_COMMON_NAME_INVALID' 응답을 반환합니다.

혹시 도움이 될지 몰라 제 전체 app.yml 파일을 아래에 첨부합니다 (비밀번호와 이메일 주소는 마스킹 처리함)

this is the all-in-one, standalone Discourse Docker container template

After making changes to this file, you MUST rebuild

/var/discourse/launcher rebuild app

BE VERY CAREFUL WHEN EDITING!

YAML FILES ARE SUPER SUPER SENSITIVE TO MISTAKES IN WHITESPACE OR ALIGNMENT!

visit http://www.yamllint.com/ to validate this file as needed

templates:

  • “templates/postgres.template.yml”
  • “templates/redis.template.yml”
  • “templates/web.template.yml”
  • “templates/web.ratelimited.template.yml”

Uncomment these two lines if you wish to add Lets Encrypt (https)

  • “templates/web.ssl.template.yml”
  • “templates/web.letsencrypt.ssl.template.yml”
  • “templates/import/mysql-dep.template.yml”

which TCP/IP ports should this container expose?

If you want Discourse to share a port with another webserver like Apache or nginx,

see Run other websites on the same machine as Discourse for details

expose:

  • “80:80” # http
  • “443:443” # https

params:
db_default_text_search_config: “pg_catalog.english”

Set db_shared_buffers to a max of 25% of the total memory.

will be set automatically by bootstrap based on detected RAM, or you can override

db_shared_buffers: “128MB”

can improve sorting performance, but adds memory usage per-connection

#db_work_mem: “40MB”

Which Git revision should this container use? (default: tests-passed)

#version: tests-passed

env:
LANG: en_US.UTF-8

DISCOURSE_DEFAULT_LOCALE: en

How many concurrent web requests are supported? Depends on memory and CPU cores.

will be set automatically by bootstrap based on detected CPUs, or you can override

UNICORN_WORKERS: 2

TODO: The domain name this Discourse instance will respond to

Required. Discourse will not work with a bare IP number.

DISCOURSE_HOSTNAME: nzarchitecture.net.nz

Uncomment if you want the container to be started with the same

hostname (-h option) as specified above (default “$hostname-$config”)

#DOCKER_USE_HOSTNAME: true

TODO: List of comma delimited emails that will be made admin and developer

on initial signup example ‘user1@example.com,user2@example.com’

DISCOURSE_DEVELOPER_EMAILS: ‘****************’

TODO: The SMTP mail server used to validate new accounts and send notifications

SMTP ADDRESS, username, and password are required

WARNING the char ‘#’ in SMTP password can cause problems!

DISCOURSE_SMTP_ADDRESS: smtp.mailgun.org
DISCOURSE_SMTP_PORT: 587
DISCOURSE_SMTP_USER_NAME: ****************
DISCOURSE_SMTP_PASSWORD: “****************”
#DISCOURSE_SMTP_ENABLE_START_TLS: true # (optional, default true)

If you added the Lets Encrypt template, uncomment below to get a free SSL certificate

LETSENCRYPT_ACCOUNT_EMAIL: ******************

The http or https CDN address for this Discourse instance (configured to pull)

see Enable a CDN for your Discourse for details

#DISCOURSE_CDN_URL: https://discourse-cdn.example.com

The Docker container is stateless; all data is stored in /shared

volumes:

  • volume:
    host: /var/discourse/shared/standalone
    guest: /shared
  • volume:
    host: /var/discourse/shared/standalone/log/var-log
    guest: /var/log

Plugins go here

see Install plugins on a self-hosted site for details

hooks:
after_code:
- exec:
cd: $home/plugins
cmd:
- git clone GitHub - discourse/docker_manager: Plugin for use with discourse docker image · GitHub
- git clone GitHub - discourse/discourse-bbcode: vBulletin BBCode plugin · GitHub

Any custom commands to run after building

run:

  • exec: echo “Beginning of custom commands”

If you want to set the ‘From’ email address for your first registration, uncomment and change:

After getting the first signup email, re-comment the line. It only needs to run once.

#- exec: rails r “SiteSetting.notification_email=‘info@unconfigured.discourse.org’”

  • exec: echo “End of custom commands”

after_ssl:
- replace:
filename: /usr/local/bin/letsencrypt
from: /-d nzarchitecture.net.nz /
to: "-d nzarchitecture.net.nz -d www.nzarchitecture.net.nz "
global: true


/usr/local/bin/ 디렉토리에 파일이 없는 것이 문제의 일부일까요?

그것이 필요한 경우, 해당 위치에 배치할 올바른 letsencrypt 파일을 어디서 찾을 수 있을까요?

그리고 그 경로 끝에 있는 파일명이 'letsencrypt'라면, 파일명에 확장자가 없는 것이 정상적인가요?

제 아이디어는 after_ssl 줄을 삭제하고 나머지 줄의 들여쓰기를 없애는 것입니다.

제 SSH 키를 다음 명령으로 추가해 주신다면

ssh-import-id-gh pfaffman

그리고 저에게 이메일을 보내주세요. 제가 할 수 있는 일을 찾아보겠습니다.

감사합니다! @pfaffman

방금 이메일을 보냈어요

업데이트 사항을 공유합니다.

app.yml 하단의 run 섹션에 아래 내용을 추가하면 /usr/local/bin/letsencrypt가 DISCOURSE_HOSTNAME과 www.DISCOURSE_HOSTNAME에 대한 인증서를 요청하는 문제를 해결할 수 있습니다.

- exec: sed -i "s|-d \${DISCOURSE_HOSTNAME}|-d \${DISCOURSE_HOSTNAME} -d www.\${DISCOURSE_HOSTNAME}|g" /usr/local/bin/letsencrypt

이전에는 이 정도면 충분했지만(어떤 식으로든?), 이제는 http://www.HOSTNAME/.well-known…에 대한 요청이 들어오면 챌린지를 보내는 대신 non-www 사이트로 리디렉션됩니다. 다음과 같은 방식으로 시도해 보았지만:

server {
  listen 80;
  listen [::]:80;
  server_name nzarchitecture.net.nz www.nzarchitecture.net.nz;

  # ACME 챌린지 서빙 (Let's Encrypt)
  location ^~ /.well-known/acme-challenge/ {
    root /var/www/discourse/public;  # Let's Encrypt 웹루트와 일치하는지 확인하세요
    allow all;
  }

  # 나머지는 모두 HTTPS로 리디렉션
  location / {
    return 301 https://$host$request_uri;
  }
}

아직 완전히 해결하지는 못했습니다.

팀에서 이 내용을 보고 계신 분이라면, after_letsencrypt에서 이 작업을 호출할 수 있도록 letsencrypt 훅이 있으면 좋겠습니다. 이러한 변경 사항을 하기 전에는 after_ssl에서 작동했지만, 이제는 그렇게 하면 ssl 이후에 실행되지만 letsencrypt 이전에는 실행되지 않는 것 같습니다.

저도 같은 문제를 겪고 있습니다. 해결할 수 있으면 알려드릴게요.

저의 DISCOURSE_HOSTNAME은 www.textkit.com입니다. 저는 nzarchitecture.net.nz와 정반대로, www가 없는 호스트명을 인증서에 추가하고 있습니다. 저에게는 다음과 같은 방법으로 작동했습니다:

- exec: sed -i "s|-d \${DISCOURSE_HOSTNAME}|-d www.textkit.com -d textkit.com|g" /usr/local/bin/letsencrypt

@pfaffman과 nzarchitecture.net.nz가 왜 그의 버전에서 문제를 겪고 있는지는 정확히 말씀드리기 어렵지만, 아마도 제 경우의 호스트명 순서가 관련이 있을 수도 있습니다.

저도 같은 문제를 겪었습니다.

아래 부분을 주석 처리하여 제거했습니다:

  after_ssl:
#    - replace:
#        filename: "/etc/runit/1.d/letsencrypt"
#        from: /--keylength/
#        to: "-d example.com --keylength"
#    - replace:
#        filename: "/etc/nginx/conf.d/discourse.conf"
#        from: /return 301 https.+/
#        to: |
#          return 301 https://$host$request_uri;

그리고 @pfaffman 님의 조언에 따라 하단의 run 섹션에 다음 내용을 추가했습니다:

- exec: sed -i "s|-d \${DISCOURSE_HOSTNAME}|-d \${DISCOURSE_HOSTNAME} -d www.\${DISCOURSE_HOSTNAME}|g" /usr/local/bin/letsencrypt

제 경우엔 이것만으로 충분했던 것 같습니다:

  • 사이트가 재빌드되었고, 유효한 인증서가 발급된 것으로 보입니다.
  • 아펙스 도메인에서 www로のリダイ렉션이 정상 작동합니다.

@pfaffman 님 감사합니다!

오! 멋지네요. 인증서 갱신이 가능하도록 한 변경 사항이 제가 겪고 있던 문제도 함께 해결해 준 것일지도 모르겠어요.

PR이 승인되기 전에 이 문제가 필요한 다른 사이트를 만나게 되면 이 내용을 참고하겠습니다.

여기에는 몇 가지 동적인 요소가 있습니다. 재구축 시에는 저에게 잘 작동했는데, 상황이 바뀌면 다시 보고하겠습니다!

인증서 갱신을 허용하는 PR은 아직 병합되지 않았습니다. 해당 부분은 여전히 대기 중입니다.

다만, 병합이 완료되면 app.yml 파일을 훨씬 간소화할 수 있을 것입니다.

어찌 보면 이상하게도, 그 코드 조각은 내 사이트 중 하나에서는 작동하지만, 다른 사이트에서는 구버전 코드(그리고 오직 구버전 코드만)가 작동합니다. :person_shrugging:

어쨌든 곧 이 모든 것이 무의미해질 거라 희망합니다!

정말 이상하네요. discourse_docker가 오래된 버전으로 고정되어 있나요?

아니요, 그렇지 않습니다. 두 인스턴스 간에는 큰 차이가 없습니다(테마/플러그인/설정이 유사합니다). 다만 한 인스턴스가 다른 인스턴스보다 꽤 오래되었다는 점만 다릅니다.

글쎄요, 아마도 이건 단순히 이론적인 문제일 뿐이겠지요.

이 부분이 실제로 구현되었나요?

저의 Let’s Encrypt 인증서가 어제 자동 갱신되지 않은 채 만료되었습니다. 이 문제가 위에서 언급된 app.yml에 대한 제안된 변경 사항 때문인지, 아니면 Discourse의 후속 업데이트 때문인지는 확실하지 않습니다.

AI의 도움으로(네, 압니다!) 여러 번의 시행착오 끝에 nginx와 certbot을 사용하는 경로로 갔다가(결국 이것이 효과가 있었습니다), 그 변경 사항을 되돌리고 Discourse가 관리하는 기본 방식으로 복원한 후 갱신에 성공했습니다. 이 과정에서 몇 번의 재구축이 필요했기 때문에, 재구축 자체가 갱신을 트리거한 것인지 아니면 코드 변경 때문인지는 확신할 수 없습니다.

현재 인증서가 만료될 때까지 기다리는 것 외에는, 향후 갱신이 자동으로 이루어질지 테스트할 방법이 있을까요?

불편을 드려 죄송합니다. 혹시 이번 이전에는 마지막으로 언제 재빌드(rebuild)를 하셨는지 궁금합니다.

방금 갱신 프로세스를 다시 확인하고 테스트해 보았지만 재현이 되지 않습니다. 저희 테스트에서는 정상적으로 갱신이 이루어지므로, 저희 측에서 어떤 문제가 발생하고 있거나, Let’s Encrypt의 스테이징과 프로덕션 환경의 갱신 방식에 차이가 있는 것 같습니다.

다른 모든 방법이 실패할 경우, 사이트를 재빌드하면 갱신 프로세스가 강제 실행된다는 점도 확인해 드릴 수 있습니다.

저희는 내부적으로 acme.sh를 사용하며(컨테이너 내 /opt/acme.sh 경로에 위치해 있음), 원하시는 경우 실행 중인 Docker 컨테이너에 접속하여 해당 스크립트를 통해 직접 확인하거나 갱신할 수도 있습니다.