5

I'm trying to add automatic TLS/SSL termination to an Nginx in a docker-compose deployed through the docker-machine (DigitalOcean).

I found a few nice resources [humankode/how-to-set-up..., medium/nginx-and-lets-encrypt...] on how to do it through the docker-compose but they both are saying from the perspective of being on the server. I really want to avoid that. I'd love to do it locally, on my laptop, bundle it all together, and send it off. Or, even do it remotely without doing any ssh.

A few attempts failed but it feels like they were close. The main obstacle seems to be with files/volumes. Following the medium/nginx-and-lets-encrytp... guide I'm having problems with saving OpenSSL privkey.pem. The other tutorial (humankode), to me knowledge, does everything on the server and that's where the volumes live.

My latest attempt was to set up certificates on the machine through the DigitalOcean tutorial and try to include these through in my docker-compose build. No luck.

There were many modifications but my settings are similar to:

docker-compose.yml

version: '3.7'

services:
  nginx:
    image: nginx:1.15.9-alpine
    container_name: nginx
    build:
      context: ./nginx
      dockerfile: Dockerfile
    restart: always
    volumes:
      - /etc/letsencrypt
      - /var/www/certbot
    ports:
      - "80:80"
      - "443:443"
    command: "/bin/sh -c 'while :; do sleep 6h & wait $${!}; nginx -s reload; done & nginx -g \"daemon off;\"'"

  certbot:
    image: certbot/certbot
    restart: unless-stopped
    volumes:
      - "/etc/letsencrypt"
      - "/var/www/certbot"
    entrypoint: "/bin/sh -c 'trap exit TERM; while :; do certbot renew; sleep 12h & wait $${!}; done;'"

nginx/Dockerfile

FROM nginx:1.15.9-alpine

RUN rm /etc/nginx/conf.d/default.conf
COPY prod.conf /etc/nginx/conf.d/

nginx/conf.d

# PRODUCTION
server {
    listen 80;
    listen [::]:80;
    server_name example.site;

    location ~ /.well-known/acme-challenge {
        allow all;
        root /usr/share/nginx/html;
    }

    location / {
        return 301 https://$host$request_uri;
    }
}

server {
    listen 443 ssl;
    server_name example.site;

    ssl_certificate /etc/letsencrypt/live/example.site/fullchain.pem;
    ssl_certificate_key /etc/letsencrypt/live/example.site/privkey.pem;

    include /etc/letsencrypt/options-ssl-nginx.conf;
    ssl_dhparam /etc/letsencrypt/ssl-dhparams.pem;
Dawid Laszuk
  • 1,773
  • 21
  • 39

1 Answers1

1

I would need further details on errors you are receiving, but basically everything is more or less ok in your configuration. I see a possible error in the volumes part. But step by step because you are asking a couple of interesting questions:

  1. You can test everything locally but I am afraid (or I could not find the way) that you cannot do it with Let's encrypt automatically because certbot find a suitable available domain in the internet (so locally is unreachable). What I did is to generate the certificates (I have validated ones) and then modify the hosts on your machine with the domain pointing to localhost (or Docker toolbox IP in the case of Windows) you are selecting with valid certificates. It is a workaround but it can work.

  2. In the Medium example, volumes are created as host volumes for both containers:

     volumes:
        - ./data/certbot/conf:/etc/letsencrypt
        - ./data/certbot/www:/var/www/certbot
    

    This means that the certificates must be placed in the folder ./data/certbot/conf or /path/to/host of the docker host machine and they are mapped to /etc/letsencrypt folder in the container. You are using anonymous volumes (I had problems in the past when I use them). Check this stackoverflow question for further explanation about the type of volumes.

Finally if you prefer another more dynamic solution which automatically includes https you can check an stackoverflow answer on how to use nginx as reverse proxy in order to ease your deployment. There is also available a docker compose ELK deployment example

Carlos Cavero
  • 3,011
  • 5
  • 21
  • 41
  • No error, just trying to do something different and didn't work. Eventually I have done the manual bootstrap, i.e. log into the remote host, scp credentials and put them into docker (https://personalprogress.site). However, this is only a single project from many to come and I'd like to avoid doing that every time. Your other approach is interesting but I don't want to couple project. Was hoping that there's an automatic way to retrieve credentials. Besides, I'd like to store Let's Encrypt certificate somewhere and don't want to put it into the GitHub. – Dawid Laszuk Oct 26 '19 at 00:04
  • Yes there is an automatic way. Lets encrypt is integrated with nginx including the renewal process. In a couple of days I will edit the answer with the automated solution for 1). – Carlos Cavero Oct 26 '19 at 08:17