docker-compose-certbot

A Docker-first solution to running NGINX reverse proxy with automatically updated Let’s Encrypt SSL certificates using nginx-proxy and acme-companion

In a previous blog post, I presented a solution to use docker-compose to obtain and renew a Let’s Encrypt SSL certificate and configure NGINX to use it. The solution depended on using two docker-compose files, one for the initialisation and the second for operation, as well as a cron job, and a couple of very simple shell scripts.

In this blog post, I will present a solution that was developed by Jason Wilder that is entirely docker-based and that eliminates the need for the shell scripts and the cron job. The docker images nginx-proxy and acme-companion are both open-source projects initiated and maintained by Jason Wilder and are hosted on GitHub under https://github.com/nginx-proxy/nginx-proxy and https://github.com/nginx-proxy/acme-companion respectively.

For the sake of simplicity and comparison, I will use the same example I used for the in the previous related blog post, which involved deploying an instance of Matomo. Let’s start with the docker-compose.yaml we developed in that post, and introduce nginx-proxy and acme-companions.

version: "3"

services:
  matomo:
    image: matomo
    container_name: matomo
    restart: always
    depends_on:
      - db
    volumes:
      - ./matomo:/var/www/html
  db:
    image: mariadb 
    container_name: db 
    command: --max-allowed-packet=64MB
    restart: always
    environment:
      - MARIADB_DATABASE=matomo
      - MARIADB_USER
      - MARIADB_PASSWORD
      - MARIADB_ROOT_PASSWORD
    volumes:
      - ./db:/var/lib/mysql
  nginx:
    container_name: nginx
    image: nginx:latest
    restart: unless-stopped
    environment:
      - DOMAIN
    depends_on:
      - matomo
    ports:
      - 80:80
      - 443:443
    volumes:
      - ./etc/nginx/templates:/etc/nginx/templates:ro
      - ./etc/letsencrypt:/etc/letsencrypt:ro
      - ./certbot/data:/var/www/certbot
  certbot:
    container_name: certbot
    image: certbot/certbot:latest
    depends_on:
      - nginx
    command: >-
             certonly --reinstall --webroot --webroot-path=/var/www/certbot
             --email ${EMAIL} --agree-tos --no-eff-email
             -d ${DOMAIN}
    volumes:
      - ./etc/letsencrypt:/etc/letsencrypt
      - ./certbot/data:/var/www/certbot

Now we need to replace Nginx, and Certbot with nginx-proxy and acme-companion. Changes must be made also to the Matomo service where some necessary environment variables must be added. Changes are highlighted in the following code block.

version: "3"
services:
  matomo:
    image: matomo
    container_name: matomo
    restart: always
    environment:
      VIRTUAL_HOST: ${THE_DOMAIN_NAME}
      VIRTUAL_PORT: ${THE_PORT_MATOMO_IS_LISTENING_FOR}
      LETSENCRYPT_HOST: ${THE_DOMAIN_NAME}
      LETSENCRYPT_EMAIL: ${THE_EMAIL_USED_FOR_LETS_ENCRYPT}
    depends_on:
      - db
    volumes:
      - matomo:/var/www/html
  db:
    image: mariadb 
    container_name: db 
    command: --max-allowed-packet=64MB
    restart: always
    environment:
      - MARIADB_DATABASE=matomo
      - MARIADB_USER
      - MARIADB_PASSWORD
      - MARIADB_ROOT_PASSWORD
    volumes:
      - db:/var/lib/mysql

  proxy:
    image: nginxproxy/nginx-proxy:alpine
    restart: always
    ports:
      - 80:80
      - 443:443
    labels:
      com.github.jrcs.letsencrypt_nginx_proxy_companion.nginx_proxy: "true"
    volumes:
      - certs:/etc/nginx/certs:ro
      - vhost.d:/etc/nginx/vhost.d
      - html:/usr/share/nginx/html
      - /var/run/docker.sock:/tmp/docker.sock:ro
    networks:
      - proxy-tier
      - default

  letsencrypt-companion:
    image: nginxproxy/acme-companion
    restart: always
    volumes:
      - certs:/etc/nginx/certs
      - acme:/etc/acme.sh
      - vhost.d:/etc/nginx/vhost.d
      - html:/usr/share/nginx/html
      - /var/run/docker.sock:/var/run/docker.sock:ro
    networks:
      - proxy-tier
    depends_on:
      - proxy

networks:
  proxy-tier

volumes:
  matomo
  db:
  certs:
  acme:
  vhost.d:
  html:

The environment variables in the WebApp backend, in this case matomo, are necessary for nginx-proxy, and acme-companion to obtain the ssl certificate from Let’s Encrypt and to setup the reverse proxy the the WebApp:

environment:
  VIRTUAL_HOST: your_matomo_server.com
  VIRTUAL_PORT: 80
  LETSENCRYPT_HOST: your_matomo_server.com
  LETSENCRYPT_EMAIL: email@your_matomo_server.com

That’s it. Now it is only the matter of running docker compose.

$ docker-compose up -d

This solution is much simple for the end user than the one suggested in my previous post, on the expense of clarity and control, and the additional risk of running code maintained by a person rather than an organisation.