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.
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:
<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>
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
ProxyPass /.well-known !
This will prevent apache from sending ACME protocol requests to your proxied site.
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.
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
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.
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
systemctl start le-renew.service