Bootstrap-fout tijdens Discourse-installatie: ENOENT - /etc/runit/1.d/letsencrypt

Hallo, ik probeer Discourse te installeren met het standaard ./launcher rebuild app proces, maar ik loop tegen een fout aan tijdens de bootstrap:

FAILED
--------------------
Errno::ENOENT: Geen bestand of map gevonden @ rb_sysopen - /etc/runit/1.d/letsencrypt
Locatie van de fout: /usr/local/lib/ruby/gems/3.3.0/gems/pups-1.3.0/lib/pups/replace_command.rb:11:in `read'
Vervanging mislukt met de parameters {"filename"=>"/etc/runit/1.d/letsencrypt", "from"=>"/--keylength/", "to"=>"-d forum.mysite.org --keylength"}
bootstrap mislukt met exit code 1
** FAILED TO BOOTSTRAP ** scroll omhoog en zoek naar eerdere foutmeldingen, er kunnen er meer zijn.

Het lijkt erop dat de fout wordt veroorzaakt door een plugin die een replace commando probeert uit te voeren op het bestand /etc/runit/1.d/letsencrypt, dat niet bestaat in de container tijdens de bootstrap. De relevante regel in de plugin ziet er als volgt uit:

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

Enig advies over hoe dit te verhelpen of het ontbrekende bestand correct te regenereren?

Alvast bedankt.

A plugin? That’s cups code from your app.yml, right? Are you trying to add another certificate? Like in Set up Let’s Encrypt with multiple domains / redirects Can you include the actual code and both certificates?

As you point out, that runit no longer exists, and now that magic is in /usr/local/bin/letsencrypt (inside the container)

I think maybe you want something like this if your site is www.mysite.org and you also want it to have a cert for 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

What I would do (which may be of no help to you) is enter the container, apt update;apt install -y vim and then edit /usr/local/bin/letsencrypt such that it would request the certificates you want.

I added code to the let’s encrypt topic linked above that should let you enter your domain and get code that you can copy/paste into your app.yml.

1 like

Ik ben tegen wat lijkt op dezelfde foutmelding aangelopen tijdens een poging tot update.

Alles werkte tot ik de melding kreeg dat een kritieke update nodig was.

Nadat ik via de webpagina met forumupdates op Docker Manager had geklikt om bij te werken (voordat ik de rest bijwerkte) - kreeg ik dit resultaat:

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

Nadat ik deze instructies had gevolgd, kreeg ik dit resultaat in PuTTy bij de tweede stap:

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

Ik probeer niets te veranderen aan certificaten. Ik probeer ook geen meerdere domeinen of redirects in te stellen.

Net als de oorspronkelijke poster, toont mijn app.yml bestand momenteel dit:

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

Ik heb uw suggestie gevolgd:

 apt update;apt install -y vim

maar het resultaat was:

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

Wat betreft de tweede voorgestelde stap, ik heb geen idee welke certificaten ik wil, aangezien ik niets van plan was te veranderen.

Ik heb gekeken in /usr/local/bin/letsencrypt - maar dit is een lege map.

Sorry voor mijn absolute onwetendheid hier!

Hoe kan ik mijn forum weer online krijgen, zonder terug te hoeven vallen op het herstellen van een back-up die vervolgens opnieuw moet worden bijgewerkt?

Een eenvoudige reeks commando’s die ik in PuTTY kan plakken zou ideaal zijn, indien mogelijk?

Aangezien ik duidelijk niet de enige ben die dit tegenkomt, is het mogelijk dat er iets aangepast moet worden in het standaard docker manager update script dat wordt aangeroepen vanaf forumwebsites om deze fout voor andere gebruikers te voorkomen?

OK, after a few hours of thrashing around, I managed to get back up and running.

I found an old app.yml file and substituted that, just deleting the old references to plugins that have since been incorporated into Discourse

This older app.yml file did not contain the code below, that I found in the later one.

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

I don’t remember putting that code there myself although I had set up my site to use letsencrypt for the free security certificates, but the Set up HTTPS support with Let's Encrypt instructions don’t seem to require those lines at all, so no idea what they would have been for.

Could anything else have potentially written those lines to app.yml?. Eg. could they possibly added during an beta update?

At least for now, with those lines gone, my site is working again and up to date.

When my current ssl certificate expires I guess I may just find out what those extra lines were for.

Well, yes you are, but you don’t remember. :wink:

If you have that after_ssl stanza in your yml file then at some point you set things up so that if someone stuck a www in front of your domain it would go to the www address and get redirected to the non www address without a certificate error.

My suggestion was to install vim inside the container and try to muck with the files there, but I think my code to add to app.yml should work.

Right. And now if you visit https://www.nzarchitecture.net.nz/ you get a certificate error. You could use https://forcewww.com/

You could go to the link above and get the new code that I think should work, but haven’t tested since I haven’t found a site that I’m upgrading that needs it.

Am I correct that your code would be along the below lines, if I want www.nzarchitecture.net.nz to be covered by same letsencrypt certificate as nzarchitecture.net.nz ?

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

I tried adding this stanza (great terminology, thanks!) to the end of app.yml, in lieu of the original ’after_ssl:’ stanza, and now can rebuild Discourse without errors - but this does not seem to help me; my browser still throws a ‘net::ERR_CERT_COMMON_NAME_INVALID’ response if I try to use a ‘www’ prefix before my main/certified domain nzarchitecture.net.nz

My full app.yml below, in case it helps at all (password and email addresses redacted)

## 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 https://meta.discourse.org/t/17247 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 https://meta.discourse.org/t/14857 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 https://meta.discourse.org/t/19157 for details
hooks:
  after_code:
    - exec:
        cd: $home/plugins
        cmd:
          - git clone https://github.com/discourse/docker_manager.git
          - git clone https://github.com/discourse/discourse-bbcode.git
## 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

Is the fact that there are no files in /usr/local/bin/ part of the problem?

Where do I find the correct letsencrypt file to put there, if that is what is needed?

And, if ‘letsencrypt’ is the filename at the end of that path, is it normal that there is no file extension as part of this filename ?

Mijn idee is om de after_ssl-regel te verwijderen en de andere in te laten springen.

Als je mijn ssh-sleutel toevoegt met

ssh-import-id-gh pfaffman

En me een e-mail stuurt, zal ik kijken wat ik kan doen.

Bedankt! @pfaffman

Zojuist een e-mail naar je gestuurd

Here’s an update.

Adding this to the run section at the bottom of your app.yml will solve the problem of getting /usr/local/bin/letsencrypt to request certificates for DISCOURSE_HOSTNAME and www.DISCOURSE_HOSTNAME.

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

This (somehow?) used to be enough, but now when the request comes in for http://www.HOSTNAME/.well-known… it gets redirected to the non www site rather than sending the challenge that it’s supposed to send. I tried to do something like this:

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

  # Serve ACME challenge (Let's Encrypt)
  location ^~ /.well-known/acme-challenge/ {
    root /var/www/discourse/public;  # Make sure this matches your Let's Encrypt webroot
    allow all;
  }

  # Redirect everything else to HTTPS
  location / {
    return 301 https://$host$request_uri;
  }
}

but didn’t quite figure it out.

If anyone from team is listening, it would be good if there were a letsencrypt hook so that this could be called in an after_letsencrypt. Before making these changes in after_ssl worked, but it seems that now if we do that this gets run after ssl, but before letsencrypt.

3 likes

Ik zie dit probleem ook. Ik laat het je weten als ik het kan oplossen.

Mijn DISCOURSE_HOSTNAME is www.textkit.com. Ik doe het tegenovergestelde van nzarchitecture.net.nz en voeg een hostnaam zonder www toe aan mijn certificaat. Dit werkte voor mij:

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

Ik kan niet zeggen waarom @pfaffman en nzarchitecture.net.nz problemen zouden hebben met zijn versie, hoewel de volgorde van de hostnaam in de mijne er misschien mee te maken heeft.

I also hit this.

I removed this (by commenting it out):

  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;

and added this in the run section at the bottom as per @pfaffman

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

This appears to have been enough for me:

  • the site rebuilt and apparently appears to have valid certs
  • the redirection from apex to www is working

Thanks @pfaffman!

4 likes

Oh! Cool. Maybe the change that they made that allowed certificate renewals to work also solved the problem that I was facing.

I’ll keep this in mind if I come across any other sites that need this before the PR gets accepted.

1 like

Hier zijn een paar bewegende delen. Het werkte voor mij bij die herbouw, ik zal hier verslag uitbrengen als die situatie verandert!

1 like

De PR om certificaatvernieuwingen toe te staan is nog niet samengevoegd – dat deel is nog in behandeling.

Zodra het is samengevoegd, zou dit een veel eenvoudigere app.yml mogelijk moeten maken.

2 likes

Somewhat oddly, that bit of code works in one of my sites but the old code (and only the old code) works on my other site. :person_shrugging:

Well, hopefully this will all be moot soon anyway!

1 like

That’s very strange. Is discourse_docker pinned to an old version?

Nee, dat is het niet. Er is niet veel verschil tussen de instanties (vergelijkbare thema’s / plug-ins / configuratie), behalve dat één instantie een stuk ouder is dan de andere.

Hopelijk is dit puur academisch.

1 like

Has this been implemented at all?

My LetsEncrypt certificate just expired yesterday without auto renewing. Not sure if this has anything to do with the suggested changes to app.yml I made per this thread above, or with subsequent updates to Discourse.

With AI assistance (yes, I know!) I have now managed to get it to renew, after following the AI down a number of rabbit holes involving using ngix and certbot (which eventually did work in fairness), before reverting those changes and going back to the default method managed by Discourse. In the process I had to rebuild a couple of times, so not sure whether the fact of rebuilding, or changes to the code is what triggered renewal.

Other than waiting for the current certificate to expire, is there a way to test whether renewal going forward will go back to being automatic?

Sorry for the trouble - I’m curious, when was the last time you rebuilt before this?

We just checked and tested the renewal process again but are unable to reproduce - our tests renew properly so either something’s not happening on our side, or there’s something different in how lets encrypt’s staging vs prod renewal works.

I can also confirm that rebuilding your site does force the renewal process to take place, if all else fails.

We use acme.sh underneath the hood (in /opt/acme.shin the container) - if you’re inclined you can enter the running docker container and run the script to inspect/renew through there as well.

1 like