Running NGINX with Docker with Let’s Encrypt certificates outside of the container

In this post I want to explain briefly how I solved the problem to run NGINX with docker but keep the let’s encrypt certificates outside of the Docker image. Some approaches include the certificates into the container during the build, i.e. they are generated in the docker image. I wanted to decouple certificates and NGINX. Here’s my approach.

It assumes you have docker and certbot (Let’s Encrypt) already installed.

1. Get the certificates

Just generate your certificates like in every let’s encrypt tutorial. $ sudo certbot certonly --standalone --preferred-challenges http -d mydomain.tld -d www.mydomain.tld

2. Let NGINX in Docker container access the certificates

The nginx.conf inside the NGINX container expects the certificates as usual in /etc/letsencrypt/live/mmydomain.tld/ (path inside container, not inside host system!). In docker-compose.yml we make sure to have the following volumes configured:

volumes:
      # for error.log (choose any volume path you want)
      - .my_docker_compose_volume/nginx:/var/log/nginx
      # nginx.conf expects ssl files here
      - /etc/letsencrypt/live/:/etc/letsencrypt/live
      - /etc/letsencrypt/archive:/etc/letsencrypt/archive
      # DH params (needs to be generated first, see e.g.: `openssl dhparam -out /etc/ssl/dhparam.pem 2048`
      - /etc/ssl/:/etc/ssl

That’s it.

3. Example configuration files

docker-compose.yml

version: '3.7'

services:
  # main nginx : reverse proxy for ssl
  nginx:
    restart: always
    container_name: nginx
    image: phip1611/nginx:latest
    ports:
      - 80:80
      - 443:443
    volumes:
      - .docker_compose_volume/nginx:/var/log/nginx
      # Volumes we need for TLS
      - /etc/ssl:/etc/ssl # dhparams file
      - /etc/letsencrypt/live:/etc/letsencrypt/live # current certificate
      - /etc/letsencrypt/archive:/etc/letsencrypt/archive # all certificates (symlinks from /live points here)

nginx.conf (only SSL part)

worker_processes auto;

# to get access to additional modules from "nginx-extra" package
include /etc/nginx/modules-enabled/*.conf;

events {
  worker_connections 1024;
}

http {
  gzip            on;
  gzip_min_length 1000;
  gzip_proxied    expired no-cache no-store private auth;
  gzip_types      text/plain text/css text/xml
                  application/javascript application/json application/xml application/rss+xml image/svg+xml;

  # neccessary for many server{}-blocks
  server_names_hash_bucket_size 64;

  access_log /var/log/nginx/access.log;
  error_log /var/log/nginx/error.log;

  more_clear_headers 'server';

  # Common TLS Config
  ssl_certificate     /etc/letsencrypt/live/mydomain.tld/fullchain.pem;
  ssl_certificate_key /etc/letsencrypt/live/mydomain.tld/privkey.pem;
  ssl_dhparam         /etc/ssl/dhparam.pem;
  ssl_protocols       TLSv1.2 TLSv1.3;
  ssl_session_cache   shared:SSL:10m;
  ssl_session_timeout 10m;
  ssl_ciphers         "EECDH-AESGCM:EDH+ESGCM:AES256+EECDH:AES256+EDH";
  ssl_prefer_server_ciphers on;
  add_header          Strict-Transport-Security "max-age=31557600; includeSubdomains" always;

  server {
    listen 80 default_server;
    listen [::]:80 default_server;
    return 301 https://$host$request_uri;
  }

  server {
      server_name mydomain.tld;
      
      listen 443 ssl http2;
      listen [::]:443 ssl http2;
  
      location / {
        proxy_pass http://some-service-running-inside-docker:8080;
        
        # container needs to know it doesn't run on "http://some-service-running-inside-docker" 
        proxy_set_header 'X-Forwarded-Host' mydomain.tld;
        proxy_set_header 'X-Forwarded-Proto' https;
        proxy_set_header 'X-Forwarded-For' $remote_addr;
        proxy_set_header 'X-Forwarded-IP' $remote_addr;
      }
    }
}

Dockerfile (to build nginx)

FROM nginx:1.17.5
# to get nginx_more_headers
RUN apt-get update && apt-get install -y nginx-extras
RUN rm /etc/nginx/conf.d/default.conf
COPY nginx.conf /etc/nginx
VOLUME /var/log/nginx

Any more questions? Feel free to ask!

Philipp Schuster

Ich bin Philipp, studiere Informatik an der TU Dresden und arbeite als Werkstudent im Bereich Software-Entwicklung bei T-Systems MMS. Ich bin 22 Jahre alt und beschäftige mich in meiner Freizeit gerne mit meinem Blog, Programierung, Technik, aber auch mit Joggen und vielen anderen Dingen. Get To Know Me oder schreibt mich an!

Das könnte Dich auch interessieren …

Schreibe einen Kommentar

Deine E-Mail-Adresse wird nicht veröffentlicht. Erforderliche Felder sind mit * markiert.