Let’s Encrypt Subdomains HOWTO
OK. Here is my situation. I want to use HTTPS everywhere, for the main site and also all subdomains. Because it’s secure. And allegedly you get higher ranks in Google.
See also HOWTO for Let’s Encrypt wildcard certificate for subdomains.
TL;DR
I’m an expert, spare me the details.
Here you are:
- Copy over and adapt configuration files for Bind and Nginx. Restart Bind right away, restart Nginx after Certbot.
- Command to run:
certbot --installer=nginx --authenticator webroot -w /home/myrtana_sk/current/public -d myrtana.sk,projects.myrtana.sk,kittydemo.myrtana.sk,www.myrtana.sk,ww.myrtana.sk,starz.myrtana.sk,light.myrtana.sk,legends.myrtana.sk,library.myrtana.sk
- Adding more subdomains later:
certbot --expand --installer=nginx --authenticator webroot -w /home/myrtana_sk/current/public -d myrtana.sk,projects.myrtana.sk,kittydemo.myrtana.sk,www.myrtana.sk,ww.myrtana.sk,starz.myrtana.sk,light.myrtana.sk,legends.myrtana.sk,library.myrtana.sk,new.myrtana.sk
Pick the correct web root and list all domains and subdomains that should go into the certificate. List existing + new domains when adding later.
And for others, here is more detailed guide…
Give Me More Details
The existing setup consists of Bind as DNS and Nginx as Web Server. Nothing else really matters.
Let’s get to work then. I use real config files crafted for my headquarters, myrtana.sk.
The strategy is following:
- DNS: set up wildcard A, AAAA and CAA records for root domain and subdomains. Everything (every subdomain) needs to hit our web server.
- Nginx: Set up HTTPS virtual host, all needs to be accepted and processed by the web server.
- Let’s Encrypt: use certbot to generate all certificates for main site and subdomains. Let’s Encrypt doesn’t support wildcard certificates, therefore subdomains needs to be known beforehand. Why not.
DNS
There are A (IPv4) and AAAA (IPv6) records for root domain (@) and all subdomains (*.). Also there are CAA records which say only letsencrypt.org can issue certificates for our domain.
; /etc/bind/db.myrtana
;
; BIND reverse data file for local loopback interface
;
$TTL 3600
@ IN SOA ns1.myrtana.sk. root.myrtana.sk. (
2017020701 ; Serial
1h ; Refresh
10m ; Retry
4w ; Expire
1h ) ; Negative Cache TTL
;
@ IN NS ns1.myrtana.sk.
@ IN NS ns2.myrtana.sk.
@ IN MX 10 starz.myrtana.sk.
@ IN A 37.205.11.69
*.myrtana.sk. IN A 37.205.11.69
@ IN AAAA 2a03:3b40:100::1:80
*.myrtana.sk. IN AAAA 2a03:3b40:100::1:80
@ IN TXT "v=spf1 mx -all"
@ IN CAA 0 issue "letsencrypt.org"
*.myrtana.sk. IN CAA 0 issue "letsencrypt.org"
Nginx
I enabled HTTP/2, because Passenger supports it and TLS connection is reused, so the site response should be faster. It is not mandatory.
# /etc/nginx/local/ssl_settings
# last check 2018/02/09
# setup from mozilla tls generator + http headers from cipherli.st
ssl on;
# certs sent to the client in SERVER HELLO are concatenated in ssl_certificate
ssl_session_timeout 1d;
ssl_session_cache shared:SSL:50m;
ssl_session_tickets off;
# modern configuration. tweak to your needs.
ssl_protocols TLSv1.2;
ssl_ciphers ECDHE-ECDSA-AES256-GCM-SHA384:ECDHE-RSA-AES256-GCM-SHA384:ECDHE-ECDSA-CHACHA20-POLY1305:ECDHE-RSA-CHACHA20-POLY1305:ECDHE-ECDSA-AES128-GCM-SHA256:ECDHE-RSA-AES128-GCM-SHA256:ECDHE-ECDSA-AES256-SHA384:ECDHE-RSA-AES256-SHA384:ECDHE-ECDSA-AES128-SHA256:ECDHE-RSA-AES128-SHA256;
ssl_prefer_server_ciphers on;
# HSTS (ngx_http_headers_module is required) (15768000 seconds = 6 months)
add_header Strict-Transport-Security "max-age=15768000; includeSubDomains; preload";
add_header X-Frame-Options DENY;
add_header X-Content-Type-Options nosniff;
add_header X-XSS-Protection "1; mode=block";
add_header X-Robots-Tag none;
# OCSP Stapling ---
# fetch OCSP records from URL in ssl_certificate and cache them
ssl_stapling on;
ssl_stapling_verify on;
resolver 127.0.0.1 [::1] valid=300s;
# /etc/nginx/sites-enabled/myrtana.sk
server {
listen 80 default_server;
listen [::]:80 default_server;
client_max_body_size 64M;
server_name .myrtana.sk;
access_log /var/log/nginx/myrtana.sk.access.log combined;
error_log /var/log/nginx/myrtana.sk.error.log;
# Redirect non-https traffic to https
if ($scheme != "https") {
return 301 https://$host$request_uri;
} # managed by Certbot
}
server {
listen 443 ssl http2;
listen [::]:443 ssl http2;
include local/ssl_settings;
ssl_certificate /etc/letsencrypt/live/projects.myrtana.sk/fullchain.pem; # managed by Certbot
ssl_certificate_key /etc/letsencrypt/live/projects.myrtana.sk/privkey.pem; # managed by Certbot
## verify chain of trust of OCSP response using Root CA and Intermediate certs
ssl_trusted_certificate /etc/letsencrypt/live/projects.myrtana.sk/fullchain.pem;
access_log /var/log/nginx/myrtana.sk.access.log combined;
error_log /var/log/nginx/myrtana.sk.error.log;
client_max_body_size 64M;
server_name .myrtana.sk;
access_log /var/log/nginx/myrtana.sk.access.log combined;
error_log /var/log/nginx/myrtana.sk.sk.error.log;
# ~2 seconds is often enough for most folks to parse HTML/CSS and
# retrieve needed images/icons/frames, connections are cheap in
# nginx so increasing this is generally safe...
keepalive_timeout 7;
# path for static files
root /home/myrtana_sk/current/public;
passenger_ruby /home/myrtana_sk/.rbenv/shims/ruby;
passenger_enabled on;
passenger_app_env production;
}
Just put a new configuration here, but don’t restart Nginx as paths to the certificate don’t exist yet and the restart will fail. Certbot will update the paths automatically.
Certbot (letsencrypt)
First install python-certbot-nginx
package.
apt-get install python-certbot-nginx
For Apache use python-certbot-apache
and the setup is similar and the “installer” is apache.
Steps:
- Run
certbot --installer nginx
. - Select webroot authentication.
- Select your domain (extractedby certbot from Nginx configs).
- Enter root of the web application - it will put a file here and access from the outside, look into Nginx config for the path, i.e.
/home/myrtana_sk/current/public
. certbot
will add paths to new certificates and also add redirect from HTTP to HTTPS. And will refresh certificates automatically (and reload nginx, because certs are loaded only once).- Add additional domains, i.e. subdomains:
certbot --expand -d myrtana.sk,projects.myrtana.sk,kittydemo.myrtana.sk,www.myrtana.sk,ww.myrtana.sk,starz.myrtana.sk,light.myrtana.sk,legends.myrtana.sk,library.myrtana.sk --installer=nginx
BONUS
All this can be done with one command at once. Use with ‘–expand’ to update the certificate, but all domains must still be here along with new ones.
certbot --installer=nginx --authenticator webroot -w /home/myrtana_sk/current/public -d myrtana.sk,projects.myrtana.sk,kittydemo.myrtana.sk,www.myrtana.sk,ww.myrtana.sk,starz.myrtana.sk,light.myrtana.sk,legends.myrtana.sk,library.myrtana.sk
Conclusion
Now you have your web server using only HTTPS protocol. HTTP is redirected to HTTPS. HTTP/2 is enabled.
SSL/TLS settings adapted from Mozilla TLS configuration generator and cipherli.st* ensures the best practices in 2018. To support older clients, you might want to allow TLSv1 and TLSv1.1, but TLSv1.2 is supported in a really large portion of clients.
Also HSTS HTTP header is sent, so a typical web browser will refuse to load the site without HTTPS and without a valid certificate.
CAA record in DNS ensures that only chosen certificate authorities can issue certificates for our domain.
Postfix and Dovecot can also use the certificate for SMTP and POP3/IMAP connections. But don’t forget to add mailserver subdomain to the certificate.
Things that can be improved: HTTP configuration needs another improvements and redirect www and ww subdomains to root domain for SEO reasons (deduplicate content). Also that redirect from Certbot is good for public websites, but is awkward for private and secure APIs. In these cases it should redirect only to root domain and discard the rest of URI. myrtana.sk is all public so far.
The process wasn’t entirely straightforward in my case, because I didn’t set up HTTPS virtual host in Nginx at first, so I had to run command again to reinstall certificates. Actually I messed up like three times.
Don’t forget to test your configuration.
https://www.ssllabs.com/ssltest/analyze.html?d=myrtana.sk
https://www.ssllabs.com/ssltest/analyze.html?d=kittydemo.myrtana.sk
If you have any questions or any feedback, contact me.
Feel free to link, share, copy and remix.
TODO: fix stapling issue: 2018/02/10 01:01:55 [warn] 31122#31122: "ssl_stapling" ignored, issuer certificate not found
Detailed Process
Details are very helpful when you hit a bug, want to see the process beforehand or don’t get something at first and need to compare the outputs.
There are some long dead subdomains and weird administration interfaces. Also a few old PHP services should be disabled now, just to be sure xD
root@starz:/etc/bind# certbot --installer nginx
Saving debug log to /var/log/letsencrypt/letsencrypt.log
How would you like to authenticate with the ACME CA?
-------------------------------------------------------------------------------
1: Place files in webroot directory (webroot)
2: Spin up a temporary webserver (standalone)
-------------------------------------------------------------------------------
Select the appropriate number [1-2] then [enter] (press 'c' to cancel): 1
Which names would you like to activate HTTPS for?
-------------------------------------------------------------------------------
1: devart.sk
2: ww.devart.sk
3: www.devart.sk
4: myrtana.sk
5: amigood.myrtana.sk
6: blackbody.myrtana.sk
7: piwik.myrtana.sk
8: posta.myrtana.sk
9: webmail.myrtana.sk
10: workingcat.myrtana.sk
11: ww.myrtana.sk
12: www.myrtana.sk
-------------------------------------------------------------------------------
Select the appropriate numbers separated by commas and/or spaces, or leave input
blank to select all options shown (Enter 'c' to cancel):4
Starting new HTTPS connection (1): acme-v01.api.letsencrypt.org
Obtaining a new certificate
Performing the following challenges:
http-01 challenge for myrtana.sk
Select the webroot for myrtana.sk:
-------------------------------------------------------------------------------
1: Enter a new webroot
-------------------------------------------------------------------------------
Press 1 [enter] to confirm the selection (press 'c' to cancel): 1
Input the webroot for myrtana.sk: (Enter 'c' to cancel):/home/myrtana_sk/current/public
Waiting for verification...
Cleaning up challenges
Generating key (2048 bits): /etc/letsencrypt/keys/0000_key-certbot.pem
Creating CSR: /etc/letsencrypt/csr/0000_csr-certbot.pem
Cannot find a cert or key directive in /etc/nginx/sites-enabled/myrtana.sk for set(['myrtana.sk', 'www.myrtana.sk', 'ww.myrtana.sk']). VirtualHost was not modified.
IMPORTANT NOTES:
- Unable to install the certificate
- Congratulations! Your certificate and chain have been saved at
/etc/letsencrypt/live/myrtana.sk/fullchain.pem. Your cert will
expire on 2018-05-08. To obtain a new or tweaked version of this
certificate in the future, simply run certbot again with the
"certonly" option. To non-interactively renew *all* of your
certificates, run "certbot renew"
Done! You can see Unable to install the certificate. We will handle that with this command:
root@starz:/etc/bind# certbot --installer nginx
Saving debug log to /var/log/letsencrypt/letsencrypt.log
How would you like to authenticate with the ACME CA?
-------------------------------------------------------------------------------
1: Place files in webroot directory (webroot)
2: Spin up a temporary webserver (standalone)
-------------------------------------------------------------------------------
Select the appropriate number [1-2] then [enter] (press 'c' to cancel): 1
Which names would you like to activate HTTPS for?
-------------------------------------------------------------------------------
1: devart.sk
2: ww.devart.sk
3: www.devart.sk
4: myrtana.sk
5: amigood.myrtana.sk
6: blackbody.myrtana.sk
7: posta.myrtana.sk
8: webmail.myrtana.sk
9: workingcat.myrtana.sk
10: ww.myrtana.sk
11: www.myrtana.sk
-------------------------------------------------------------------------------
Select the appropriate numbers separated by commas and/or spaces, or leave input
blank to select all options shown (Enter 'c' to cancel):4
Starting new HTTPS connection (1): acme-v01.api.letsencrypt.org
Cert not yet due for renewal
You have an existing certificate that has exactly the same domains or certificate name you requested and isn't close to expiry.
(ref: /etc/letsencrypt/renewal/myrtana.sk.conf)
What would you like to do?
-------------------------------------------------------------------------------
1: Attempt to reinstall this existing certificate
2: Renew & replace the cert (limit ~5 per 7 days)
-------------------------------------------------------------------------------
Select the appropriate number [1-2] then [enter] (press 'c' to cancel): 1
Keeping the existing certificate
Deployed Certificate to VirtualHost /etc/nginx/sites-enabled/myrtana.sk for set(['myrtana.sk', 'www.myrtana.sk', 'ww.myrtana.sk'])
Please choose whether HTTPS access is required or optional.
-------------------------------------------------------------------------------
1: Easy - Allow both HTTP and HTTPS access to these sites
2: Secure - Make all requests redirect to secure HTTPS access
-------------------------------------------------------------------------------
Select the appropriate number [1-2] then [enter] (press 'c' to cancel): 2
Redirecting all traffic on port 80 to ssl in /etc/nginx/sites-enabled/myrtana.sk
-------------------------------------------------------------------------------
Congratulations! You have successfully enabled https://myrtana.sk
You should test your configuration at:
https://www.ssllabs.com/ssltest/analyze.html?d=myrtana.sk
-------------------------------------------------------------------------------
root@starz:/etc/bind#
Select Attempt to reinstall this existing certificate and it’s done.
Expand certificate with more subdomains:
root@starz:/etc/nginx# certbot --expand --installer=nginx --authenticator webroot -d myrtana.sk,projects.myrtana.sk,kittydemo.myrtana.sk,www.myrtana.sk,ww.myrtana.sk,starz.myrtana.sk,light.myrtana.sk,legends.myrtana.sk,library.myrtana.sk
Saving debug log to /var/log/letsencrypt/letsencrypt.log
Renewing an existing certificate
Performing the following challenges:
http-01 challenge for myrtana.sk
http-01 challenge for projects.myrtana.sk
http-01 challenge for kittydemo.myrtana.sk
http-01 challenge for www.myrtana.sk
http-01 challenge for ww.myrtana.sk
http-01 challenge for starz.myrtana.sk
http-01 challenge for light.myrtana.sk
http-01 challenge for legends.myrtana.sk
http-01 challenge for library.myrtana.sk
Select the webroot for myrtana.sk:
-------------------------------------------------------------------------------
1: Enter a new webroot
-------------------------------------------------------------------------------
Press 1 [enter] to confirm the selection (press 'c' to cancel): 1
Input the webroot for myrtana.sk: (Enter 'c' to cancel):/home/myrtana_sk/current/public
Select the webroot for projects.myrtana.sk:
-------------------------------------------------------------------------------
1: Enter a new webroot
2: /home/myrtana_sk/current/public
-------------------------------------------------------------------------------
Select the appropriate number [1-2] then [enter] (press 'c' to cancel): 2
Select the webroot for kittydemo.myrtana.sk:
-------------------------------------------------------------------------------
1: Enter a new webroot
2: /home/myrtana_sk/current/public
-------------------------------------------------------------------------------
Select the appropriate number [1-2] then [enter] (press 'c' to cancel): 2
Select the webroot for www.myrtana.sk:
-------------------------------------------------------------------------------
1: Enter a new webroot
2: /home/myrtana_sk/current/public
-------------------------------------------------------------------------------
Select the appropriate number [1-2] then [enter] (press 'c' to cancel): 2
Select the webroot for ww.myrtana.sk:
-------------------------------------------------------------------------------
1: Enter a new webroot
2: /home/myrtana_sk/current/public
-------------------------------------------------------------------------------
Select the appropriate number [1-2] then [enter] (press 'c' to cancel): 2
Select the webroot for starz.myrtana.sk:
-------------------------------------------------------------------------------
1: Enter a new webroot
2: /home/myrtana_sk/current/public
-------------------------------------------------------------------------------
Select the appropriate number [1-2] then [enter] (press 'c' to cancel): 2
Select the webroot for light.myrtana.sk:
-------------------------------------------------------------------------------
1: Enter a new webroot
2: /home/myrtana_sk/current/public
-------------------------------------------------------------------------------
Select the appropriate number [1-2] then [enter] (press 'c' to cancel): 2
Select the webroot for legends.myrtana.sk:
-------------------------------------------------------------------------------
1: Enter a new webroot
2: /home/myrtana_sk/current/public
-------------------------------------------------------------------------------
Select the appropriate number [1-2] then [enter] (press 'c' to cancel): 2
Select the webroot for library.myrtana.sk:
-------------------------------------------------------------------------------
1: Enter a new webroot
2: /home/myrtana_sk/current/public
-------------------------------------------------------------------------------
Select the appropriate number [1-2] then [enter] (press 'c' to cancel): 2
Waiting for verification...
Cleaning up challenges
Generating key (2048 bits): /etc/letsencrypt/keys/0003_key-certbot.pem
Creating CSR: /etc/letsencrypt/csr/0003_csr-certbot.pem
Deployed Certificate to VirtualHost /etc/nginx/sites-enabled/myrtana.sk for set(['myrtana.sk', 'www.myrtana.sk', 'kittydemo.myrtana.sk', 'projects.myrtana.sk', 'ww.myrtana.sk'])
Deployed Certificate to VirtualHost /etc/nginx/sites-enabled/myrtana.sk for set(['myrtana.sk', 'www.myrtana.sk', 'kittydemo.myrtana.sk', 'projects.myrtana.sk', 'ww.myrtana.sk'])
Deployed Certificate to VirtualHost /etc/nginx/sites-enabled/myrtana.sk for set(['myrtana.sk', 'www.myrtana.sk', 'kittydemo.myrtana.sk', 'projects.myrtana.sk', 'ww.myrtana.sk'])
Deployed Certificate to VirtualHost /etc/nginx/sites-enabled/myrtana.sk for set(['myrtana.sk', 'www.myrtana.sk', 'kittydemo.myrtana.sk', 'projects.myrtana.sk', 'ww.myrtana.sk'])
Deployed Certificate to VirtualHost /etc/nginx/sites-enabled/myrtana.sk for set(['myrtana.sk', 'www.myrtana.sk', 'kittydemo.myrtana.sk', 'projects.myrtana.sk', 'ww.myrtana.sk'])
Cannot find a VirtualHost matching domain starz.myrtana.sk.
IMPORTANT NOTES:
- Unable to install the certificate
- Congratulations! Your certificate and chain have been saved at
/etc/letsencrypt/live/projects.myrtana.sk/fullchain.pem. Your cert
will expire on 2018-05-10. To obtain a new or tweaked version of
this certificate in the future, simply run certbot again with the
"certonly" option. To non-interactively renew *all* of your
certificates, run "certbot renew"
I know, I messed up again, because forgot to update Nginx configuration. I fixed it with the previous command. And didn’t set webroot, so had to fill it manually like 10 times.
THAT’S ALL GUYS.
Add Comment