Let's encrypt with Nginx
In this article, I will share the way of using nginx, let’s encrypt and docker/docker-compose to deploy ssl with automatically cert-renew.
Let’s Encrypt + Nginx + Docker
Nginx is a web server that I used to replace Apache. Since I have to deploy my application which will provide SSL connection through the internet, I utilize Let’s Encrypt, a certificate authority that provides free X.509 certificates for Transport Layer Security (TLS) encryption.
Apart from that, docker and docker-compose will be used to setup my environment which is really really convenient tools for deployment. I guess you should already know what this items are so I am not going to explain how to use these tools here.
Given the directory structure like this:
/
|- certs
|- certs-data
|- conf.d
|- log
|- renew
|- nginx
|- www
Nginx
Create a docker-compose.yml file under root directory.
version: '3'
services:
nginx:
container_name: nginx
image: nginx:latest
restart: always
volumes:
- ./www:/usr/share/nginx/html
- ./conf.d:/etc/nginx/conf.d
- ./log:/var/log/nginx
- ./certs:/etc/letsencrypt
- ./certs-data:/var/lib/letsencrypt
environment:
TZ: Asia/Hong_Kong
ports:
- 80:80
- 443:443
Configure files for Nginx
Create and configure Nginx configure in cond.d directory.
You can apply proxy_pass in location if you need.
Configure 1
normal.conf
server {
listen 80;
server_name <url>;
#charset koi8-r;
access_log /var/log/nginx/host.access.log main;
location / {
rewrite ^ https://$host$request_uri? permanent;
}
location ^~ /.well-known/acme-challenge/ {
default_type "text/plain";
root /data/letsencrypt;
}
#error_page 404 /404.html;
# redirect server error pages to the static page /50x.html
#
error_page 500 502 503 504 /50x.html;
location = /50x.html {
root /usr/share/nginx/html;
}
# pass the PHP scripts to FastCGI server listening on 127.0.0.1:9000
#
#location ~ \.php$ {
# root html;
# fastcgi_pass 127.0.0.1:9000;
# fastcgi_index index.php;
# fastcgi_param SCRIPT_FILENAME /scripts$fastcgi_script_name;
# include fastcgi_params;
#}
# deny access to .htaccess files, if Apache's document root
# concurs with nginx's one
#
#location ~ /\.ht {
# deny all;
#}
}
Configure 2
ssl.conf
server {
listen 443 ssl http2;
listen [::]:443 ssl http2;
server_name <url>;
ssl on;
add_header Strict-Transport-Security "max-age=31536000" always;
ssl_session_cache shared:SSL:20m;
ssl_session_timeout 10m;
ssl_protocols TLSv1 TLSv1.1 TLSv1.2;
ssl_prefer_server_ciphers on;
ssl_ciphers "ECDH+AESGCM:ECDH+AES256:ECDH+AES128:!ADH:!AECDH:!MD5;";
ssl_stapling on;
ssl_stapling_verify on;
resolver 8.8.8.8 8.8.4.4;
ssl_certificate /etc/letsencrypt/live/<url>/fullchain.pem;
ssl_certificate_key /etc/letsencrypt/live/<url>/privkey.pem;
ssl_trusted_certificate /etc/letsencrypt/live/<url>/chain.pem;
access_log /dev/stdout;
error_log /dev/stderr info;
# other configs
location / {
root /usr/share/nginx/html;
index index.html index.htm;
}
# proxy the PHP scripts to Apache listening on 127.0.0.1:80
#
#location ~ \.php$ {
# proxy_pass http://127.0.0.1;
#}
}
Let's Encrypt
Sign Cert
Navigate to the root directory and run the following command to sign the certificate from Let’s Encrypt.
sudo docker run -it --rm \
-v $PWD/certs:/etc/letsencrypt \
-v $PWD/certs-data:/var/lib/letsencrypt deliverous/certbot certonly\
--webroot --webroot-path=/var/lib/letsencrypt -d <domain>
Note! You have to use full path in Volume Mirror
Renew
If you want to automatically renew the cert, you can use crontab to do the schedule job. You can use contab -e
to do the job but this will only apply in the user-level. I would recommend you to do this in system-level — edit the config directly in /etc/crontab
.
這個『 crontab -e 』是針對使用者的 cron 來設計的,如果是『系統的例行性任務』時, 該怎麼辦呢?是否還是需要以 crontab -e 來管理你的例行性工作排程呢?當然不需要,你只要編輯 /etc/crontab 這個檔案就可以啦!有一點需要特別注意喔!那就是 crontab -e 這個 crontab 其實是 /usr/bin/crontab 這個執行檔,但是 /etc/crontab 可是一個『純文字檔』喔!你可以 root 的身份編輯一下這個檔案哩! - 鳥哥的 Linux 私房菜 — 第十五章、例行性工作排程(crontab)
You can use following script to schedule the task. it will run every 15 days.
Note! Cert can only be renewed within last 30 days.
0 0 */15 * * docker run -it --rm -v /root/nginx/certs:/etc/letsencrypt -v /root/nginx/certs-data:/var/lib/letsencrypt -v /root/nginx/letsencryptlog:/var/log/letsencrypt deliverous/certbot renew --webroot --webroot-path=/var/lib/letsencrypt >> renew_log.log && docker kill -s HUP nginx >/dev/null 2>&1
The renew command will take a look at all active certificates and renew those who are close to expiring — which is currently defined as 30 days before the expiration date. If your certificates aren’t due for renewal yet, the client won’t renew them. The reason why a daily cronjob is recommended is in order to avoid issues caused by service downtime on Let’s Encrypt’s end, or any issues your server might have. If you, for example, run the cronjob just once every month or every two months, and the service just happens to be down during those times, you’ll end up with an expired certificate eventually. By doing it daily instead, Let’s Encrypt would have to be down for 30 consecutive days for that to happen, which is rather unlikely. - [SOLVED] How often to renew?
References
Last updated