letsencrypt-service
Docker image that creates Let's Encrypt certificates and checks them daily. Implemented using dehydrated with lexicon for DNS verification.
Environment
STAGING
: Iftrue
, use the letsencrypt staging endpoints.LEXICON_ENV
: The path to the environment file containing lexicon secrets. Default:/run/secrets/lexicon_env
BASEDIR
: The path to the dehydrated working directory. Default:/var/lib/dehydrated
OUTDIR
: The path to the output directory for certificates. Default:/etc/ssl/private
Volumes
In swarm mode, these volumes should not be shared across nodes. See the FAQ.
-
/var/lib/dehydrated
($BASEDIR
)Ensures Let's Encrypt accounts and CA chains are maintained across containers.
-
/etc/ssl/private
($OUTDIR
):Contains the produced certificates and private keys. As certificates approach expiration, new ones will be generated. The active certificate and key will always be symlinked to:
/etc/ssl/private/$cert/fullchain.pem /etc/ssl/private/$cert/privkey.pem
Lexicon Secrets
The file pointed at by $LEXICON_ENV
variable must define (and export) the
environment variables needed for authenticating with your DNS provider.
For example:
export PROVIDER=cloudflare
export LEXICON_CLOUDFLARE_USERNAME=...
export LEXICON_CLOUDFLARE_TOKEN=...
Certificates
Via domains.txt
If you prefer to provide your own domains.txt file, copy or mount it into
/etc/dehydrated/domains.txt
. If that file exists, it is used, otherwise
certificates must be configured by environment variables.
Via Environment Variables
Each certificate must be given an alias, which will used as the subdirectory
under $OUTDIR
. The list of aliases goes in the $CERTS
environment variable:
CERTS='mail www'
This will produce two certificates, stored in $OUTDIR/mail/
and
$OUTDIR/www/
. Use environment variables prefixed with DOMAIN_
to declare
the primary hostname for each certificate alias:
DOMAIN_mail='mail.example.com'
DOMAIN_www='example.com'
Use environment variables prefixed with ALTS_
to declare alternate hostnames
as needed:
ALTS_www='www.example.com www2.example.com'
Note: Because the $DOMAIN_xxx
environment variable is required, the
certificate alias must not contain characters that are invalid in environment
variable names.
FAQ
How do I use the hostname of my swarm node in my certificate?
Because environment variables allow Go templates, your
docker-compose.yml
can pass in the node hostname to the container:
environment:
CERTS: mx
DOMAIN_mx: {{ .Node.Hostname }}.example.com
ALTS_mx: mx1.example.com mx2.example.com
What is the recommended service configuration?
This service should run in global
mode, so that each swarm node produces its
own certificates and private keys. Additionally, in case of failure, it's best
to delay restart on failure to avoid hammering ACME services. Here is a good
starting point:
deploy:
mode: global
restart_policy:
delay: 10m
The $LEXICON_ENV
file, which defaults to /run/secrets/lexicon_env
, is
designed to be used with a docker secret configuration:
secrets:
- lexicon_env
# later in the file
secrets:
lexicon_env:
file: $HOME/.docker-secrets/lexicon.env
How can I reload my services when certificates change?
Whenever a certificate is updated, the $OUTDIR
directory is touched with a
new modification time. If your service keeps a .pid file, a simple healthcheck
will restart your service when needed:
healthcheck:
interval: 10s
retries: 1
test: test /etc/ssl/private -ot /var/run/myservice.pid