Docker web stack securing with Lets Encrypt

Oct 22, 2017

updated at: Oct 26, 2017

0 comments

In my last post I showed how to scale with Docker swarm and Vagrant. Now I will build upon this and add SSL encryption to my Nginx with Lets Encrypt, also with a Docker of course, image used: kvaps/letsencrypt-webroot.

My Docker web-stack:

version: '3'

networks:
  webproxy:
    driver: overlay

services:

    php:
        restart: always
        image: php:7-fpm
        ports:
            - "9000:9000"
        volumes:
            - /http:/http
        deploy:
            replicas: 15

    nginx:
        hostname: sevaho.io
        restart: always
        image: nginx:alpine
        ports:
            - "80:80"
            - "443:443"
        volumes:
            - /conf.d:/etc/nginx/conf.d
            - /http:/http
            - /tmp/letsencrypt:/tmp/letsencrypt
            - /etc/letsencrypt:/etc/letsencrypt
        environment:
            - LE_RENEW_HOOK=docker kill -s HUP @CONTAINER_NAME@
        links:
            - php
        deploy:
            replicas: 15

    letsencrypt:
        restart: always
        image: kvaps/letsencrypt-webroot
        volumes:
            - /var/run/docker.sock:/var/run/docker.sock
            - /etc/letsencrypt:/etc/letsencrypt
            - /tmp/letsencrypt:/tmp/letsencrypt
            - /http:/http
        links:
             - nginx
        environment:
             - DOMAINS=sevaho.io www.sevaho.io
             - EMAIL=sebastiaan@sevaho.io
             - WEBROOT_PATH=/http
             - EXP_LIMIT=30
             - CHECK_FREQ=30

    redis:
        restart: always
        image: redis:alpine
        ports:
           - '6379:6379'
        deploy:
            replicas: 3
        links:
            - nginx

NOTE: I use the alpine image of Nginx because this is smaller and is a little bit faster. I want to use the alpine image of PHP but I experience problems with PHP sessions so I keep the default. Also the Redis service is also added but you can leave it out if you don't use it. Also launch PHP before Nginx otherwise Nginx will say it can't find PHP socket.

2 new directories:

And the Nginx:

server {

    listen 80;

    server_name sevaho.io;

    location ^~ /.well-known/ { # needed for Lets encrypt (acme-challenge)

        root /http;

    }

    location / { # always load the https version

        return 301 https://$server_name$request_uri;

    }

}

server {

    listen 443 ssl default_server;
    listen [::]:443 ssl default_server;

    server_name sevaho.io;

    root <>; # add your root folder here

    ssl_protocols TLSv1 TLSv1.1 TLSv1.2;

    ssl_certificate /etc/letsencrypt/live/sevaho.io/fullchain.pem;
    ssl_certificate_key /etc/letsencrypt/live/sevaho.io/privkey.pem;

    index index.html index.php index.htm index.nginx-debian.html;

    error_page 404 /404.html;
    error_page 500 502 503 504 /50x.html;

    location / {

        try_files $uri $uri/ /index.php?$query_string; # I use a Laravel application here

    }

    location ~ \.php$ {

        try_files $uri =404;
        fastcgi_split_path_info ^(.+\.php)(/.+)$;
        fastcgi_pass php:9000; # connection with the php container
        fastcgi_index index.php;
        include fastcgi_params;
        fastcgi_param SCRIPT_FILENAME $document_root$fastcgi_script_name;
        fastcgi_param PATH_INFO $fastcgi_path_info;

    }

}

It took some try and error to figure it all out, but at the end I got it all working ;).

1