Let’s Encrypt with Supervisor
Let’s Encrypt works great with Supervisor, as it provides easy orchestration and some basic scheduling that the certificate management requires. Configuring it is also not rocket science; just identify the environment your app is running in, and choose a suitable workflow. This can even be done with minimal changes to your app, and in a Docker-friendly way.
For automating Let’s Encrypt, you generally need 3 program:
- The app itself (Apache, Node.js, or whatever you use)
- An initial cert issuance script. This will run when you start the server
- A renewal script that handles getting new certificates
supervisord.conf which we’ll customize looks like this:
Depending on the authorization flow you use, the exact parameters and when each program start/stop differ.
The app is to be managed by supervisor. This is usually the case, but for example Apache spawns child processes
and that makes it out of the scope of supervisor. Make sure that
supervisorctl restart app and
supervisorctl stop app
The letsencrypt program handles the initial certificate. It does not autorestart, as it is run only once. The
--keep-until-expiring flag makes sure that if there is an existing certificate, it will use that instead of
getting a new one.
And finally, letsencrypt-renew runs every day and does the renewals. It autorestarts, but does not autostarts, so it needs a kickoff.
Flow #1: Get the certificate before launching the app, shut down during renewal
This is the easiest case. The app runs neither during getting a certificate, nor when a renewal is happening.
Part #1: run letsencrypt then start app
The only program that autostarts is the letsencrypt, and it starts both the app and the letsencrypt-renew.
Do not use
--deploy-hook, as they won’t run if a valid certificate already exists. Instead, use the
... && ... construct, that runs every time after the program is finished.
Part #2: Stop app -> renew -> start app
The other part is to configure how to renew the certificate. In this case, during renewal, the app is not running. To achieve
this, use the
Since it was not defined, renewal also uses the standalone auth.
Flow #2: Start the app, restart on new certificate
If you can configure your app so that Let’s Encrypt can use the webroot auth, then you can start it and only need to restart on new certificates.
Make sure you handle the case when you have no valid certificates, for example, use a self-signed one.
In this case, app and letsencrypt autostarts.
--deploy-hook to restart the app, as most server software won’t pick up a new certificate automatically. And since
the renewal flow works the same, it does not need any parameters.
There is one problem with this setup. A race condition is present between the app and letsencryt, as the latter
needs the former to run. If your app needs more time to start serving static files, you need to start letsencrypt
after that with
supervisorctl start letsencrypt instead of autostarting it.
Another solution is to use a
sleep before letsencrypt, like
sleep 5m && .... But that hardcodes an upper
limit, which is fragile.
A better solution is to use a script that waits for the server to start, like the wait-on that checks a HTTP service:
This will ping the parameter URL and only run letsencrypt when it is alive.