In this article, I want to share with you a way to create an SSL certificate for your web application running on Docker, as I couldn't find a similar solution in the Russian-speaking part of the internet.

Read more below.
We had Docker v.17.05, Docker Compose v.1.21, Ubuntu Server 18, and a clean Let’s Encrypt setup. It’s not necessarily required to run production on Docker, but once you start getting into Docker, it becomes hard to stop.
So to begin with, I will provide the standard settings we had during the dev stage, i.e., without port 443 and SSL in general:
docker-compose.yml
version: '2'
services:
php:
build: ./php-fpm
volumes:
- ./StomUp:/var/www/StomUp
- ./php-fpm/php.ini:/usr/local/etc/php/php.ini
depends_on:
- mysql
container_name: "StomPHP"
web:
image: nginx:latest
ports:
- "80:80"
- "443:443"
volumes:
- ./StomUp:/var/www/StomUp
- ./nginx/main.conf:/etc/nginx/conf.d/default.conf
depends_on:
- php
mysql:
image: mysql:5.7
command: mysqld --sql_mode=""
environment:
MYSQL_ROOT_PASSWORD: xxx
ports:
- "3333:3306"
nginx/main.conf
server {
listen 80;
server_name *.stomup.ru stomup.ru;
root /var/www/StomUp/public;
client_max_body_size 5M;
location / {
# try to serve file directly, fallback to index.php
try_files $uri /index.php$is_args$args;
}
location ~ ^/index.php(\/|$) {
fastcgi_pass php:9000;
fastcgi_split_path_info ^(.+.php)(\/.*)$;
include fastcgi_params;
fastcgi_param SCRIPT_FILENAME $realpath_root$fastcgi_script_name;
fastcgi_param DOCUMENT_ROOT $realpath_root;
fastcgi_buffer_size 128k;
fastcgi_buffers 4 256k;
fastcgi_busy_buffers_size 256k;
internal;
}
location ~ .php$ {
return 404;
}
error_log /var/log/nginx/project_error.log;
access_log /var/log/nginx/project_access.log;
}
Next, we actually need to implement SSL. To be honest, I studied the .com zone for about 2 hours. All the suggested options there are interesting, but at the current stage of the project, we (the business) needed to quickly and reliably implement SSL Let’sEncrypt to nginx for the container and nothing more.
First of all, we installed on the server certbot
sudo apt-get install certbot
Next, we generated wildcard certificates for our domain
sudo certbot certonly -d stomup.ru -d *.stomup.ru --manual --preferred-challenges dns
after executing certbot, it will provide us with 2 TXT records that need to be specified in the DNS settings.
_acme-challenge.stomup.ru TXT {theKeyThatCertBotGaveYou}
And press enter.
After that, certbot will check for these records in DNS and create certificates for you.
if you added the certificate, but certbot couldn't find it — try running the command again in 5-10 minutes..
Well, here we are, proud owners of a Let’sEncrypt certificate for 90 days, but now we need to integrate it into Docker.
To do this, we simply link the directories in the docker-compose.yml file under the nginx section.
Example docker-compose.yml with SSL
version: '2'
services:
php:
build: ./php-fpm
volumes:
- ./StomUp:/var/www/StomUp
- /etc/letsencrypt/live/stomup.ru/:/etc/letsencrypt/live/stomup.ru/
- ./php-fpm/php.ini:/usr/local/etc/php/php.ini
depends_on:
- mysql
container_name: "StomPHP"
web:
image: nginx:latest
ports:
- "80:80"
- "443:443"
volumes:
- ./StomUp:/var/www/StomUp
- /etc/letsencrypt/:/etc/letsencrypt/
- ./nginx/main.conf:/etc/nginx/conf.d/default.conf
depends_on:
- php
mysql:
image: mysql:5.7
command: mysqld --sql_mode=""
environment:
MYSQL_ROOT_PASSWORD: xxx
ports:
- "3333:3306"
Linked? Great — let's continue:
Now we need to modify the config nginx to work with 443 the port and SSL in general:
Example main.conf config with SSL
#
server {
listen 443 ssl http2;
listen [::]:443 ssl http2;
server_name *.stomup.ru stomup.ru;
set $base /var/www/StomUp;
root $base/public;
# SSL
ssl_certificate /etc/letsencrypt/live/stomup.ru/fullchain.pem;
ssl_certificate_key /etc/letsencrypt/live/stomup.ru/privkey.pem;
ssl_trusted_certificate /etc/letsencrypt/live/stomup.ru/chain.pem;
client_max_body_size 5M;
location / {
# try to serve file directly, fallback to index.php
try_files $uri /index.php$is_args$args;
}
location ~ ^/index.php(/|$) {
#fastcgi_pass unix:/var/run/php7.2-fpm.sock;
fastcgi_pass php:9000;
fastcgi_split_path_info ^(.+.php)(/.*)$;
include fastcgi_params;
fastcgi_param SCRIPT_FILENAME $realpath_root$fastcgi_script_name;
fastcgi_param DOCUMENT_ROOT $realpath_root;
fastcgi_buffer_size 128k;
fastcgi_buffers 4 256k;
fastcgi_busy_buffers_size 256k;
internal;
}
location ~ .php$ {
return 404;
}
error_log /var/log/nginx/project_error.log;
access_log /var/log/nginx/project_access.log;
}
# HTTP redirect
server {
listen 80;
listen [::]:80;
server_name *.stomup.ru stomup.ru;
location / {
return 301 https://stomup.ru$request_uri;
}
}
So after these manipulations, we go to the directory with Docker-compose, type docker-compose up -d. And check the SSL functionality. Everything should be up and running.
Just don't forget that the Let’sEncrypt certificate is issued for 90 days, and you will need to renew it using the command sudo certbot renew, and then restart the project with the command docker-compose restart
As an option — add this sequence to crontab.
In my opinion, this is the simplest way to connect SSL to a Docker Web app.
P.S. Please note that all scripts presented in the text are not final; the project is currently in deep development, so I ask you not to criticize the configs — they will change many times.
Source: habr.com
