Let's face it; in today's world, it's much easier to make a case for setting up SSL/TLS support on your website then to not. And no, Self-Signed certificates don't count. That's fine for your home router or one-man OwnCloud site, but if you care about the data being served up, get yourself some (properly signed) SSL certs!
The problem used to be that if you wanted SSL certs, you had to pay, sometimes a lot. Verisign/Symantec certs can start in the $400 range and go up from there. Conversely Comodo SSL certs start at $79.95. Now, we won't go into the "market topology" of why Verisign is more expensive than Comodo, but to some extent you get what you pay for.
LetsEncrypt aims to change that. They are currently (June2016) offering certificates for free (valid for 90 days). Period. This coalition (most notably backed by Mozilla, Cisco, EFF, and others) are aiming to put an SSL cert into the hands of anybody who wants one.
There will be a TLDRScript™ at the end of this, but keep in mind, the initial setup with certbot requires answering to interactive prompts, so you can't truly script it. Additionally, use that script with caution, it will add custom configs to your apache setup, and that may not be what you want, Caveat emptor.
Setup
Depending on which set of directions you follow from the letsencrypt website, the client (certbot-auto) might be able to obtain and install your certificate in one fell swoop, automatically. Depending on your web server setup and its complexity, that may be completely fine for you. In the setup below, we will have an Apache web server that will be acting both a traditional web server hosting up static content, as well as a reverse proxy for some other applications (maybe even a blog)! As usual, the following assumptions are made:
- CentOS 7.latest (7.2.1511 at the time of writing)
- Apache 2.4 (latest)
- mod_ssl (latest)
- Apache installed and running with typical vhost style configuration
- SELinux enabled
- FirewallD enabled
Getting the warez
First thing we need to do is download certbot-auto from EFF and put it in your path:
wget https://dl.eff.org/certbot-auto
chmod a+x ./certbot-auto
mv certbot-auto /usr/local/sbin/.
Laying down configs
From here, you'll need to lay down your Apache config and create the necessary directories. Take note that all of these commands/configs should be used on your forward most web server (proxy or otherwise), as that is the web server that will be providing the SSL connection to your clients. Let's make some directories:
mkdir /var/www/acme/
restorecon -vr /var/www/acme/
chown apache.apache /var/www/acme/
And laydown an Apache config:
/etc/httpd/conf.d/000-zeroent.net.conf
<VirtualHost *:443>
ServerName zeroent.net
SSLEngine On
SSLProtocol all -SSLv2 -SSLv3
SSLHonorCipherOrder On
SSLCipherSuite ECDH+AESGCM:DH+AESGCM:ECDH+AES256:DH+AES256:ECDH+AES128:DH+AES:ECDH+3DES:DH+3DES:RSA+AESGCM:RSA+AES:RSA+3DES:!aNULL:!MD5:!DSS:!RC4
DocumentRoot /var/www/html
#SSLCertificateChainFile /etc/letsencrypt/live/zeroent.net/chain.pem
#SSLCertificateFile /etc/letsencrypt/live/zeroent.net/cert.pem
#SSLCertificateKeyFile /etc/letsencrypt/live/zeroent.net/privkey.pem
SSLCertificateFile /etc/pki/tls/certs/localhost.crt
SSLCertificateKeyFile /etc/pki/tls/private/localhost.key
</VirtualHost>
<VirtualHost *:80>
ServerName zeroent.net
DocumentRoot /var/www/html
RedirectMatch 301 ^/((?!\.well-known).*)$ https://zeroent.net
Alias /.well-known/ "/var/www/acme/.well-known/"
<Directory "/var/www/acme/.well-known/">
Options FollowSymLinks
AllowOverride None
Require all granted
</Directory>
</VirtualHost>
The Alias
statement sends any requests for the .well-known
directory to a separate location, the same location we'll specify in the certbot-auto
command. This allows you to not touch your web application and still have certbot work. Additionally, if you're trying to do this for a reverse proxied site, add the following to the config (near the proxy
line):
ProxyPass /.well-known !
This will prevent apache from sending ACME protocol requests to your proxied site.
The RedirectMatch
statements lets everything get redirected to your HTTPS site page except the .well-known
directory, which the ACME protocol (used by certbot-auto) uses to put answers to the challenge-response queries. It is important to note, this directory must never get auto-redirected to an HTTPS site, with or without a valid SSL cert; the letsencrypt.org ACME server will barf and your cert creation/renewal will fail.
Note
The SSL portion of that config can be obtained from Mozilla's SSL configuration generator. They'll make best-practice recommendations on which ciphers to allow and which ones to omit. Want to verify your config? Head over to SSLLabs to test your website.
At this point, we should [re]start/enable Apache, and add some firewall exception:
systemctl start httpd
systemctl enable httpd
firewall-cmd --add-service=http --permanent
firewall-cmd --add-service=https --permanent
firewall-cmd --reload
Running certbot-auto
Let't get some certs! Note that the -auto
version of the certbot
script will automatically install any packages necessary for it to successfully run using your system's package manger (in our case YUM).
certbot-auto certonly --webroot -w /var/www/acme -d zeroent.net
If you want to get multiple domains covered by a single cert (with Subject Name Alternatives), you can use multiple -d
arguments like so:
certbot-auto certonly --webroot -w /var/www/acme -d zeroent.net -d blag.zeroent.net -d www.zeroent.net
Note that the first specified domain will be the "primary" domain on the cert.
Once you run the certbot-auto
command, it will go through requesting the certs, it will prompt you for an e-mail address to register them to so in the event that they need to contact you (certs coming close to expiring, need to be revoked, etc.), they have a means of contacting you. If you are setting this up in a production/enterprise environment, I'd recommend using an alias like [email protected]
rather than [email protected]
; nothing is more embarrassing than having your production SSL certs expire and not knowing it was going to happen.
Assuming everything goes successfully, you'll see a message like this
IMPORTANT NOTES:
- Congratulations! Your certificate and chain have been saved at
/etc/letsencrypt/live/zeroent.net/fullchain.pem. Your cert
will expire on 2017-03-25. To obtain a new or tweaked version of
this certificate in the future, simply run certbot-auto again. To
non-interactively renew *all* of your certificates, run
"certbot-auto renew"
- If you like Certbot, please consider supporting our work by:
Donating to ISRG / Let's Encrypt: https://letsencrypt.org/donate
Donating to EFF: https://eff.org/donate-le
Using the new certificates.
Now that you have the new certs, you need to get Apache to use them. Simply comment out the lines pointing to localhost
and point to the new cert files created by certbot:
SSLCertificateChainFile /etc/letsencrypt/live/zeroent.net/chain.pem
SSLCertificateFile /etc/letsencrypt/live/zeroent.net/cert.pem
SSLCertificateKeyFile /etc/letsencrypt/live/zeroent.net/privkey.pem
#SSLCertificateFile /etc/pki/tls/certs/localhost.crt
#SSLCertificateKeyFile /etc/pki/tls/private/localhost.key
Now, lets move on to sustainment.
Certificate Renewal
Any process worth doing is worth automating, and that's just what we're going to do here. Because we're cool and use SystemD (instead of a cronjob), we'll lay down SystemD service and timer units that will check your certificates to determine if they need renewal, and if so, renew them. Note, by default, certbot renews the certs when they are 30 days from expiring. So if something goes wrong with automation, you have some breathing room to get your certs in order.
The service that executes the certbot - /etc/systemd/system/le-renew.service
[Unit]
Description=LetsEncrypt certificate renew job
Wants=le-renew.timer
[Service]
Type=simple
ExecStart=/usr/local/sbin/certbot-auto renew --post-hook "systemctl restart httpd"
[Install]
WantedBy=basic.target
The timer that runs that service twice a day at 1 AM and PM - /etc/systemd/system/le-renew.timer
[Unit]
Description=LetsEncrypt Renew 2/day timer
[Timer]
OnCalendar=*-*-* 1,13:19:45
Persistent=true
Unit=le-renew.service
[Install]
WantedBy=basic.target
Once you've gotten those unit files in place, poke SystemD to recognize them and start the timer.
systemctl daemon-reload
systemctl enable le-renew.timer
systemctl start le-renew.timer
If you need to check the status of the last run (determine if any certificates were renewed, any errors occurred, etc.), use the friendly JournalD to see the logs.
journalctl -u le-renew.service -e
If you ever want to manually trigger a certbot-auto run, you can just start the le-renew.service
systemctl start le-renew.service