/letsencrypt-service

Docker image that creates Let's Encrypt certificates and checks them daily

Primary LanguageShellMIT LicenseMIT

letsencrypt-service

Docker image that creates Let's Encrypt certificates and checks them daily. Implemented using dehydrated with lexicon for DNS verification.

Environment

  • STAGING: If true, 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