Bootstrap error during Discourse install: ENOENT - /etc/runit/1.d/letsencrypt

Hi, I’m trying to install Discourse using the standard ./launcher rebuild app process, but I’m running into an error during bootstrap:

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.

It looks like the error is triggered by a plugin trying to run a replace command on the file /etc/runit/1.d/letsencrypt, which doesn’t exist inside the container during bootstrap. The relevant line in the plugin looks like this:

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

Any advice on how to fix this or properly regenerate the missing file?

Thanks in advance.

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

I have hit what looks like the same error message during an attempted update.

Everything had been working until I was prompted that a critical update was needed.

After clicking to update Docker Manager via my forum updates webpage (before updating the rest) - I got this result

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

Following those instructions got me this result in PuTTy at the second step:

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

I am not trying to change anything to do with certificates. I am also not trying to set up multiple domains or redirects

like the original poster, my app.yml file also shows this currently

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

I followed your suggestion

 apt update;apt install -y vim

but result was

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

As for the second suggested step, I have no idea what certificates I want, having had no intention of changing anything.

I Iooked in /usr/local/bin/letsencrypt - but this is an empty folder.

Sorry about my absolute ignorance here!

How can I get my forum back on line, without resorting to restoring a backup that then just needs to be updated again?

A simple series of commands I can paste into PuTTY would be ideal, if this is possible?

Since I am obviously not the only one striking this, is it possible that something needs to be tweaked in the standard docker manager update script invoked from forum websites to avoid this error for other users?

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 ?

I’ve idea is to remove the after_ssl line and unindent the others.

If you’ll add my ssh key with

ssh-import-id-gh pfaffman

And email me, I’ll see what I can do

Thanks! @pfaffman

Just emailed you now

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.

2 Likes

I’m seeing this problem as well. I’ll let you know if I’m able to fix.

My DISCOURSE_HOSTNAME is www.textkit.com. I’m doing the opposite of nzarchitecture.net.nz and adding a hostname without www to my cert. This worked for me:

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

I can’t say why @pfaffman and nzarchitecture.net.nz would be having a problem with his version, though maybe the hostname ordering in mine is related.

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!

3 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

A few moving parts here. It worked for me on that rebuild, I’ll report back here if that situation changes!

1 Like

The PR to allow cert renewals hasn’t yet been merged – that part’s still pending.

Once merged though, that should allow for a much more simplified app.yml

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?

No, it isn’t. There isn’t much difference between the instances (similar themes / plugins / config), except one instance is quite a bit older than the other one.

Well, hopefully this is just academic.

1 Like