Introduction

letsencrypt-nginx-proxy-companion is a lightweight companion container for nginx-proxy. It handles the automated creation, renewal and use of Let's Encrypt certificates for proxied Docker containers. So its makes easy to deploy container with reverse proxy with SSL Automatically with features like :

  • Automated creation/renewal of Let's Encrypt (or other ACME CAs) certificates using acme.sh.
  • Let's Encrypt / ACME domain validation through http-01 challenge only.
  • Automated update and reload of nginx config on certificate creation/renewal.
  • Support creation of Multi-Domain (SAN) Certificates.
  • Creation of a Strong Diffie-Hellman Group at startup.
  • Work with all versions of docker.
Required read if you use the latest version : the recent v2.0.0 release of this project mark the switch of the ACME client used by the Docker image from simp.le to acme.sh. This switch result in some backward incompatible changes, so please read this issue and the updated docs for more details before updating your image. The single most important change is that the container now requires a volume mounted to /etc/acme.sh in order to persist ACME account keys and SSL certificates. The last tagged version that uses simp_le is v1.13.1.

Prerequisites

In order to follow this guide, you’ll need the following:

  • Your host must be publicly reachable on both port 80 and 443.
  • Check your firewall rules and do not attempt to block port 80 as that will prevent http-01 challenges from completing.
  • For the same reason, you can't use nginx-proxy's HTTPS_METHOD=nohttp.
  • The (sub)domains you want to issue certificates for must correctly resolve to the host.
  • Your DNS provider must answer correctly to CAA record requests.
  • If your (sub)domains have AAAA records set, the host must be publicly reachable over IPv6 on port 80 and 443.

Step 1 - nginx-proxy

Start nginx-proxy with the three additional volumes declared:

$ docker run --detach \
    --name nginx-proxy \
    --publish 80:80 \
    --publish 443:443 \
    --volume /etc/nginx/certs \
    --volume /etc/nginx/vhost.d \
    --volume /usr/share/nginx/html \
    --volume /var/run/docker.sock:/tmp/docker.sock:ro \
    jwilder/nginx-proxy

Binding the host docker socket (/var/run/docker.sock) inside the container to /tmp/docker.sock is a requirement of nginx-proxy.

Three writable volumes must be declared on the nginx-proxy container so that they can be shared with the letsencrypt-nginx-proxy-companion container:

  • /etc/nginx/certs to store certificates, private keys and ACME account keys (readonly for the nginx-proxy container).
  • /etc/nginx/vhost.d to change the configuration of vhosts (required so the CA may access http-01 challenge files).
  • /usr/share/nginx/html to write http-01 challenge files.

Step 2 - letsencrypt-nginx-proxy-companion

Start the letsencrypt-nginx-proxy-companion container, getting the volumes from nginx-proxy with --volumes-from:

$ docker run --detach \
    --name nginx-proxy-letsencrypt \
    --volumes-from nginx-proxy \
    --volume /var/run/docker.sock:/var/run/docker.sock:ro \
    --volume /etc/acme.sh \
    --env "DEFAULT_EMAIL=mail@yourdomain.tld" \
    jrcs/letsencrypt-nginx-proxy-companion

The host docker socket has to be bound inside this container too, this time to /var/run/docker.sock.

Albeit optional, it is recommended to provide a valid default email address through the DEFAULT_EMAIL environment variable, so that Let's Encrypt can warn you about expiring certificates and allow you to recover your account.

Additionally, a fourth volume must be declared on the letsencrypt-nginx-proxy-companion container to store acme.sh configuration and state: /etc/acme.sh.

Step 3 - proxied container(Ghost & MySQL)

Once both nginx-proxy and letsencrypt-nginx-proxy-companion containers are up and running, create and run the   docker-compose.yaml file.

Run  docker-compose up -d, wait for it to initialize completely, and visit  http://localhost:8080, or http://host-ip:8080 (as appropriate).

docker-compose.yaml

# by default, the Ghost image will use SQLite (and thus requires no separate database container)
# we have used MySQL here merely for demonstration purposes (especially environment-variable-based configuration)

version: '3.1'

services:

  ghost:
    image: ghost:3-alpine
    restart: always
    environment:
      # see https://docs.ghost.org/docs/config#section-running-ghost-with-config-env-variables
      database__client: mysql
      database__connection__host: db
      database__connection__user: root
      database__connection__password: example
      database__connection__database: ghost
      VIRTUAL_HOST : example.com  #your domain & sub domain
      VIRTUAL_PORT : 2368
      LETSENCRYPT_HOST : example.com # your domain & sub domain 
      url: http://localhost:2368
    volumes:
      - some-ghost-data:/var/lib/ghost/content:rw

  db:
    image: mysql:5.7
    restart: always
    environment:
      MYSQL_ROOT_PASSWORD: example
    volumes:
      - db-data:/var/lib/mysql:rw
      #give Path for your host volume on left side

VIRTUAL_HOST control proxying by nginx-proxy and LETSENCRYPT_HOST control certificate creation and SSL enabling by letsencrypt-nginx-proxy-companion.

If the proxied container listen on and expose another port than the default 80, you can force nginx-proxy to use this port with the VIRTUAL_PORT environment variable.

Certificates will only be issued for containers that have both VIRTUAL_HOST and LETSENCRYPT_HOST variables set to domain(s) that correctly resolve to the host, provided the host is publicly reachable.

Repeat Step 3 for any other container you want to proxy.