Free SSL Certificates with LetsEncrypt and Docker
Everyone loves security, yeah?!
Up until recently, it's cost a fair whack of money to use SSL certificates on your website. This has been a barrier for a lot of smaller website, which subsequently leaves them vulnerable to common attacks such as man in the middle.
Then comes letsencrypt, a free, crowdfunded way to get valid https certificates, like the one used on this website! In order to keep costs down (you know, as its free) they rely a lot on automated scripts and domain validation, which can be a little fiddly. I also have to do this for lots, and lots of microservices and websites that I host - so I wanted to encapsulate all of these concerns into a simple container which was generic, and did it all for me.
docker-nginx-letsencrypt
I created this docker container which is an NGINX reverse proxy, which will front your microservice with a valid HTTPS certificate without you having to do much at all!
Lets take this website, karlstoney.com as an example. The blog is actually a ghost nodejs application, which serves up http on port karlstoney.www.svc.cluster.local:2368
. However, I want to expose that to the world on karlstoney.com. I could use the following docker-compose
file to do just that:
version: '2'
services:
nginx:
image: stono/docker-nginx-letsencrypt
restart: always
volumes:
- ./certs:/etc/letsencrypt/live
environment:
- HOST_WEBSITE1=karlstoney.com,karlstoney.www.svc.cluster.local:2368,default_server
ports:
- 443
- 80
That's it, watch what happens when the container boots on my server:
Generating self signed certificate for karlstoney.com
Generating a 4096 bit RSA private key
................................................++
.............++
writing new private key to 'key.pem'
-----
Writing nginx config for karlstoney.com with an upstream of karlstoney.www.svc.cluster.local:2368
server {
listen 80;
server_name karlstoney.com;
location ~ /.well-known {
allow all;
break;
}
location / {
return 301 https://$host$request_uri;
}
}
server {
listen 443 default_server;
server_name karlstoney.com;
ssl on;
ssl_certificate /etc/letsencrypt/live/karlstoney.com/fullchain.pem;
ssl_certificate_key /etc/letsencrypt/live/karlstoney.com/key.pem;
ssl_session_cache builtin:1000 shared:SSL:10m;
ssl_protocols TLSv1 TLSv1.1 TLSv1.2;
ssl_ciphers HIGH:!aNULL:!eNULL:!EXPORT:!CAMELLIA:!DES:!MD5:!PSK:!RC4;
ssl_prefer_server_ciphers on;
access_log /var/log/nginx/karlstoney.com.access.log;
set $upstream_endpoint_host_karlstoney http://karlstoney.www.svc.cluster.local:2368;
resolver 10.37.80.10;
resolver_timeout 5s;
location / {
proxy_set_header Host $host;
proxy_set_header X-Real-IP $remote_addr;
proxy_set_header X-Forwarded-For $proxy_add_x_forwarded_for;
proxy_set_header X-Forwarded-Proto $scheme;
proxy_http_version 1.1;
proxy_set_header Upgrade $http_upgrade;
proxy_set_header Connection "upgrade";
proxy_set_header Host $host;
proxy_pass $upstream_endpoint_host_karlstoney;
proxy_redirect http://karlstoney.www.svc.cluster.local:2368 https://karlstoney.com;
proxy_read_timeout 90;
}
}
nginx: the configuration file /etc/nginx/nginx.conf syntax is ok
nginx: configuration file /etc/nginx/nginx.conf test is successful
Starting Nginx
2016/12/30 21:06:31 [notice] 26#0: using the "epoll" event method
2016/12/30 21:06:31 [notice] 26#0: nginx/1.11.5
2016/12/30 21:06:31 [notice] 26#0: built by gcc 4.8.5 20150623 (Red Hat 4.8.5-11) (GCC)
2016/12/30 21:06:31 [notice] 26#0: OS: Linux 4.4.21+
2016/12/30 21:06:31 [notice] 26#0: getrlimit(RLIMIT_NOFILE): 1048576:1048576
2016/12/30 21:06:31 [notice] 26#0: start worker processes
2016/12/30 21:06:31 [notice] 26#0: start worker process 28
Nginx started with pid 26
Running simp_le letsencrypt for karlstoney.com
2016-12-30 21:06:34,455:INFO:simp_le:1211: Generating new account key
10.37.64.1 - - [30/Dec/2016:21:06:36 +0000] "GET /.well-known/acme-challenge/h_rKjS1mbLjzs9d0bw6yDfk7M8RBr7_FVkPprVD_wkE HTTP/1.1" 200 87 "-" "python-requests/2.12.4"
2016/12/30 21:06:36 [info] 28#0: *1 client 10.37.64.1 closed keepalive connection
2016-12-30 21:06:36,648:INFO:simp_le:1305: karlstoney.com was successfully self-verified
2016-12-30 21:06:36,861:INFO:simp_le:1313: Generating new certificate private key
10.37.64.1 - - [30/Dec/2016:21:06:37 +0000] "GET /.well-known/acme-challenge/h_rKjS1mbLjzs9d0bw6yDfk7M8RBr7_FVkPprVD_wkE HTTP/1.1" 200 87 "-" "Mozilla/5.0 (compatible; Let's Encrypt validation server; +https://www.letsencrypt.org)"
2016-12-30 21:06:39,370:INFO:simp_le:391: Saving account_key.json
2016-12-30 21:06:39,371:INFO:simp_le:391: Saving fullchain.pem
2016-12-30 21:06:39,383:INFO:simp_le:391: Saving key.pem
2016/12/30 21:06:39 [notice] 26#0: signal 1 (SIGHUP) received, reconfiguring
2016/12/30 21:06:39 [notice] 26#0: reconfiguring
2016/12/30 21:06:39 [notice] 26#0: using the "epoll" event method
2016/12/30 21:06:39 [notice] 26#0: start worker processes
2016/12/30 21:06:39 [notice] 26#0: start worker process 40
2016/12/30 21:06:39 [notice] 28#0: gracefully shutting down
2016/12/30 21:06:39 [notice] 28#0: exiting
2016/12/30 21:06:39 [notice] 28#0: exit
2016/12/30 21:06:39 [notice] 26#0: signal 17 (SIGCHLD) received
2016/12/30 21:06:39 [notice] 26#0: worker process 28 exited with code 0
2016/12/30 21:06:39 [notice] 26#0: signal 29 (SIGIO) received
You can view the full repo here