I am using Let’s Encrypt certificates for several services with great success.
It is easy, reliable and very straightforward service. I will share with you my personal setup used to secure AWStats statistics page as a simple example.
Step 1
Create letsencrypt
system user using /srv/letsencrypt
directory to store relevant data.
$ sudo useradd --system --create-home --home-dir /srv/letsencrypt --shell /bin/bash letsencrypt
Create ssl
directory to store certificate files.
$ sudo mkdir -p /srv/letsencrypt/ssl
Deny other
users except www-data
from accessing this directory.
$ sudo chown letsencrypt:www-data /srv/letsencrypt/ssl
$ sudo chmod 750 /srv/letsencrypt/ssl
Step 2
Switch to letsencrypt
user and change working directory to /srv/letsencrypt
.
$ sudo -u letsencrypt -i
Download acme-tiny
utility.
letsencrypt@debian:~$ git clone https://github.com/diafygi/acme-tiny.git
Cloning into 'acme-tiny'... remote: Counting objects: 232, done. remote: Total 232 (delta 0), reused 0 (delta 0), pack-reused 232 Receiving objects: 100% (232/232), 46.93 KiB | 0 bytes/s, done. Resolving deltas: 100% (124/124), done. Checking connectivity... done.
Create acme-challenge
directory to host challenge files.
letsencrypt@debian:~$ mkdir acme-challenge
Generate Let’s Encrypt account private key
.
letsencrypt@debian:~$ openssl genrsa 4096 > account.key
Secure generated key.
letsencrypt@debian:~$ chmod 400 account.key
Step 3
Configure nginx
web-server by adding the following /.well-known/acme-challenge/
location block to the virtual host
listening on port 80
configuration you want to secure.
allow
server itself, as the script will verify that the challenge file is in place.server { listen 80; listen [::]:80; server_name statistics.sleeplessbeastie.eu; location /.well-known/acme-challenge/ { allow 111.222.111.99/32; # allow self IPv4 allow 1a01:2a02::3a03:4a04:5a05:6a06; # allow self IPv6 allow 66.133.109.36/32; # allow outbound1.letsencrypt.org allow 64.78.149.164/32; # allow outbound2.letsencrypt.org deny all; # deny everything else alias /srv/letsencrypt/acme-challenge/; try_files $uri =404; } location / { return 301 https://$host$request_uri; } }
Reload nginx
configuration.
$ sudo systemctl reload nginx
Step 4
Download intermediate certificate
.
letsencrypt@debian:~$ curl --output ssl/intermediate.crt --silent https://letsencrypt.org/certs/lets-encrypt-x3-cross-signed.pem
Generate domain private key
for sleeplessbeastie.eu
domain.
letsencrypt@debian:~$ openssl genrsa 4096 > ssl/sleeplessbeastie.eu.key
Generate certificate signing request
for statistics.sleeplessbeastie.eu
domain.
letsencrypt@debian:~$ openssl req -new -sha256 -key ssl/sleeplessbeastie.eu.key -subj "/CN=statistics.sleeplessbeastie.eu" > ssl/statistics.sleeplessbeastie.eu.csr
Request and store certificate
.
letsencrypt@debian:~$ python acme-tiny/acme_tiny.py --account-key ./account.key --csr ./ssl/statistics.sleeplessbeastie.eu.csr --acme-dir acme-challenge/ > ./ssl/statistics.sleeplessbeastie.eu.crt
Parsing account key... Parsing CSR... Registering account... Already registered! Verifying statistics.sleeplessbeastie.eu... statistics.sleeplessbeastie.eu verified! Signing certificate... Certificate signed!
Concatenate intermediate certificate
with the signed
one.
letsencrypt@debian:~$ cat ssl/statistics.sleeplessbeastie.eu.crt ssl/intermediate.crt > ssl/statistics.sleeplessbeastie.eu_chained.crt
Step 5
Configure nginx
web-server by specifying ssl certificate
and private key
inside the secured virtual host
configuration.
server { listen 443 ssl http2; listen [::]:443 ssl http2; server_name statistics.sleeplessbeastie.eu; ssl on; ssl_certificate_key /srv/letsencrypt/ssl/sleeplessbeastie.eu.key; ssl_certificate /srv/letsencrypt/ssl/statistics.sleeplessbeastie.eu_chained.crt; ssl_dhparam dhparams.pem; ssl_ciphers AESGCM:HIGH:!aNULL:!MD5; ssl_prefer_server_ciphers On; [...] }
dhparam -out dhparam.pem 4096
command to generate Diffie-Hellman parameter file.Reload nginx
configuration.
$ sudo systemctl reload nginx
Step 6
Use the following code to automatically renew
certificate on the first day of the month 23:30 hour using crontab
.
$ cat << EOF | sudo tee -a /etc/cron.d/letsencrypt 30 23 01 * * root sudo -u letsencrypt python /srv/letsencrypt/acme-tiny/acme_tiny.py --account-key /srv/letsencrypt/account.key --csr /srv/letsencrypt/ssl/statistics.sleeplessbeastie.eu.csr --acme-dir /srv/letsencrypt/acme-challenge/ > /srv/letsencrypt/ssl/statistics.sleeplessbeastie.eu.crt && cat /srv/letsencrypt/ssl/statistics.sleeplessbeastie.eu.crt /srv/letsencrypt/ssl/intermediate.crt > /srv/letsencrypt/ssl/statistics.sleeplessbeastie.eu_chained.crt && systemctl reload nginx EOF
nginx
configuration can be easily simplified by using include
directive to apply dynamically generated code.Additional notes
Do not forget to test nginx
configuration before reloading it.
$ sudo nginx -t nginx: the configuration file /etc/nginx/nginx.conf syntax is ok nginx: configuration file /etc/nginx/nginx.conf test is successful