Friday, 3 June 2016

Recipe - Docker, web apps and Lets Encrypt


If you're after easy hosting of dockerized web services with automatic certificate enrolment using Lets Encrypt, then the solution is to use 2 docker containers - nginx as a web proxy and Lets Encrypt Companion to handle certificates. LE Companion can provide either LIVE or STAGING certificates, depending on configuration, but you can run only one at a time.

Container definitions below are in a docker-compose format and the recipe below contains absolutely no security hardening of the Docker installation - this is something you need to consider separately

Web proxy

  image: 'jwilder/nginx-proxy:latest'
    - '80:80'
    - '443:443'
    - '/etc/letsencrypt:/etc/nginx/certs:ro'
    - /etc/nginx/vhost.d
    - /usr/share/nginx/html
    - '/var/run/docker.sock:/tmp/docker.sock:ro'
    - 'DEFAULT_HOST=default.vhost.tld'

TLSproxy is nginx based reverse proxy that automatically discovers and configures virtual hosts running on the same machine. See image description on docker hub for details. TL;DR simple approach is:

docker run -d -e VIRTUAL_HOST=blog.domain.tld ghost

Please note, the DEFAULT_HOST variable - it's quite useful to have it set right :-)

TLS support

Staging certs are issued from another ACME_CA_URI different to the default one, which is defined as environment variable for the container:


  image: 'jrcs/letsencrypt-nginx-proxy-companion:latest'
    - 'ACME_CA_URI='
    - '/etc/letsencrypt:/etc/nginx/certs'
    - '/var/run/docker.sock:/var/run/docker.sock:ro'
    - TLSproxy


  image: 'jrcs/letsencrypt-nginx-proxy-companion:latest'
    - '/etc/letsencrypt:/etc/nginx/certs'
    - '/var/run/docker.sock:/var/run/docker.sock:ro'
    - TLSproxy

Starting the web app

Before you start, make sure the hostname you want to use points to the actual IP address - do the DNS config first and make sure it works (wildcard DNS entries FTW!). As an example, let's run a Ghost based blog over HTTPS with automatic redirect HTTP->HTTPS:

  docker run -d -e VIRTUAL_HOST=blog.domain.tld \
     -e LETSENCRYPT_HOST=blog.domain.tld \
     -e LETSENCRYPT_EMAIL=my.mail@domain.tld \
That's all... you can watch in separate terminal windows as things get set up, just run docker logs -f TLSproxy and docker logs -f TLSproxy-LE-agent before starting the first container. LE agent will renew certs for you as well as long as the backend web service (here Ghost) is running. Keep in mind that the certificates persist on the host - in my example in /etc/letsencrypt directory.


This is very simplistic solution and will do just well for many of us, however if you have more specific needs I suggest you review the documentation for jwilder/nginx-proxy and jrcs/letsencrypt-nginx-proxy-companion docker images.

That's all folks!