• Using Let's Encrypt with Docker

    Close-up of a silver key on a laptop keyboard

    Note (2026): Consider using Traefik or Caddy — they automatically obtain and renew Let’s Encrypt certificates with zero configuration.

    Who needs all those paid certificate providers while we have such a brilliant project as Let’s Encrypt? It allows a domain owner to obtain a valid certificate for his domain in a matter of seconds without the boring stuff like generating CSR, making DNS verification records or even passing documents to the certificate issuer center. However, paid certificates most often have an expiration time of a year. And free Let’s Encrypt certificates live only for a couple of months. But it’s definitely not a huge problem if there is a way to automate the renewal process. And there it is.

    Let’s assume we are trying to generate a certificate for the awesome-domain.comwith nginx running in project_nginx_1 container.

    To keep nginx running while Let’s Encrypt verifies the domain, we need to serve verification files using it. To do so, add the following lines to nginx config:

    nginx
    location /.well-known/ {
      root /var/www/awesome-domain.com;
    }

    To renew certificate use the following command:

    bash
    mkdir -p /var/www/awesome-domain.com
    docker pull certbot/certbot
    
    docker run -it --rm --name letsencrypt \
      # mount Let's Encrypt main directories to the certbot container
      -v "/etc/letsencrypt:/etc/letsencrypt" \
      -v "/var/lib/letsencrypt:/var/lib/letsencrypt" \
      --volumes-from project_nginx_1 \
      certbot/certbot \
      certonly \
      --webroot \
      --webroot-path /var/www/awesome-domain.com \
      --agree-tos \
      --renew-by-default \
      -d awesome-domain.com \
      --email support@awesome-domain.com
    
    # restart nginx container to use new certs (make sure it's configured to restart!)
    docker kill --signal=HUP project_nginx_1

    Make sure nginx has access to required directories:

    yaml
    nginx:
      restart: unless-stopped
      image: nginx:1.13-alpine
      depends_on:
        - backend
      volumes:
        - /var/www:/var/www
        - /etc/letsencrypt:/etc/letsencrypt
        - ./nginx.conf:/etc/nginx/conf.d/default.conf
      ports:
        - '0.0.0.0:80:80'
        - '0.0.0.0:443:443'

    That’s it! Now you can use certificates from /etc/letsencrypt/live/awesome-domain.com/ directly. Just put the renewal script to cron and enjoy your secure experience.