LetsEncryptSetup
Let's Encrypt!
Let's Encrypt is a free certificate authority that was launched earlier this year. What that means is you no longer have to choose between self-signed certificates or buying certificates to secure your web site and other services. Buying certificates could cost $20-$50 per domain, and it was always a hassle to renew them. Now, you can use the Let's Encrypt tools to create certificates and automate renewals. Using these certificates also means an end to annoying 'untrusted site' popups for your users.
My Setup
I have a CentOS 6 box running apache for a webmail interface. This machine also uses sendmail to send and receive mail for the domain, and supports encrypted imap via dovecot. My goal was to use the same certificate (named mail.example.com
) to encrypt all three.
Getting Started
First, I followed the guide to download and install certbot, the Let's Encrypt client. Highlights:
# mkdir /root/bin # cd /root/bin # wget https://dl.eff.org/certbot-auto # chmod a+x certbot-auto # /root/bin/certbot-auto --apache --email letsencrypt@example.com --agreetos --domain mail.example.com certonly
Note that I used the certonly
option to only generate the certificates, not install them in apache. I initially let certbot automatically configure my apache, but it got all confused about my virtual host setup. It still worked, but ultimately it seemed simpler to do the config file editing myself.
The other options bypass the questions in the automated installer. The address you give the --email
should be a valid address which can receive mail. The --domain
argument specifies the domain you are creating the certificate for. This confused me at first, because I thought I was supposed to use the actual dns domain (example.com
). What you actually need to put here is the name your webserver presents to the outside world, in this case mail.example.com
. This name will be used to generate your SSL certificates and any service using it will have to use the same name. Wildcard certificates are not supported. In my case this wasn't a problem because apache, sendmail, and dovecot all run on the same box as mail.example.com
. Obviously if your services run under different dns names then you will need to call certbot with multiple domain arguments to generate certs for each one.
Certbot will validate that your webserver actually is authoritative for your domain, and then it will issue you a certificate. Once that process is done, your new certificate is in /etc/letsencrypt/live/mail.example.com
.
Setting Up Apache
I have one virtual host in apache, and it's serving the Squirrelmail webmail client. I of course want to encrypt all traffic to and from this webserver because potentially sensitive information is involved (user mail). To make that happen, I configured my VirtualHost entries in /etc/httpd/conf/http.conf
as follows:
<VirtualHost *:443> ServerName mail.example.com ServerAdmin webmaster@example.com DocumentRoot /usr/share/squirrelmail ErrorLog /var/log/httpd/mail.example.com-mail-error_log CustomLog /var/log/httpd/mail.example.com-mail-combined_log combined SSLEngine on SSLCertificateChainFile /etc/letsencrypt/live/mail.example.com/chain.pem SSLCertificateKeyFile /etc/letsencrypt/live/mail.example.com/privkey.pem SSLCertificateFile /etc/letsencrypt/live/mail.example.com/cert.pem </VirtualHost> <VirtualHost *:80> ServerName mail.example.com RedirectMatch permanent ^/(.*) https://mail.example.com/$1 </VirtualHost>
The virtual host on port 80 redirects all traffic to port 443 to force https. The server on port 443 uses my Let's Encrypt certificates to ssl-encrypt all connections.
Once I restarted my apache server, I found that everything worked automatically and all my web traffic was now encrypted. So far so good.
Setting Up Dovecot
I use dovecot as an imap server so that users can read mail externally with a client like thunderbird. Again, this needs to be encrypted. Previously I had been using self-signed certificates. To fix that, all I had to do was edit my /etc/dovecot/dovecot.conf
and point it at my new certificates:
ssl = required ssl_cert = </etc/letsencrypt/live/mail.example.com/fullchain.pem ssl_key = </etc/letsencrypt/live/mail.example.com/privkey.pem
After I restarted dovecot, I found that imap clients could connect on port 993 and use the new Let's Encrypt certificate with no problems.
Setting Up Sendmail
Yes, I realize everyone will tell me to use postfix, but this is an old linux installation and I've never gotten around to converting. So, I've got to figure out how to set up the latest version of sendmail to use my certifcate. Since I'm not insane, I don't hand-edit sendmail.cf
, I use /etc/mail/sendmail.mc
. Here are the changes I made to that file:
define(`CERT_DIR', `/etc/letsencrypt/live/mail.example.com') define(`confCACERT_PATH', `CERT_DIR') define(`confCACERT', `CERT_DIR/cert.pem') define(`confSERVER_CERT', `CERT_DIR/cert.pem') define(`confSERVER_KEY', `CERT_DIR/privkey.pem') define(`confCLIENT_CERT', `CERT_DIR/cert.pem') define(`confCLIENT_KEY', `CERT_DIR/privkey.pem')
After that, I ran make
in /etc/mail
and restarted sendmail. However, it didn't work! Sendmail printed the message
sendmail[28624]: STARTTLS=server: file /etc/letsencrypt/live/mail.example.com/privkey.pem unsafe: World readable file
and refused to use the certificates. I did a bunch of unsatisfactory googling about this, and the consensus was that sendmail was more paranoid about file and directory permissions than Let's Encrypt. I made two changes. First, I added the following to sendmail.mc
:
define(`confDONT_BLAME_SENDMAIL',`groupreadablekeyfile')dnl
and then I restricted permissions on the key file (/etc/letsencrypt/archive/mail.example.com/privkey1.pem
) to mode 640. The combination of those two things seemed to do the trick, and sendmail stopped complaining on startup.
Automated Renewals
The final part of the puzzle was to set up automated renewals. Let's Encrypt certificates expire in 90 days, so you have to be prepared to renew them frequently. Fortunately, certbot makes this easy. I created a script /etc/cron.daily/certbot
with the following:
#!/bin/sh # auto-renew letsencrypt certificates /root/bin/certbot-auto renew --quiet --no-self-upgrade
and made that script mode 700 (owned by root). Since it's in the cron.daily
directory, it gets run every day. It's fine to run it every day because certbot won't actually do anything until it's time to renew the certificate.
Conclusion
That's all there was to it! My server is now using an offically signed certifcate for web, imap, and mail traffic. My users get a better experience, and I don't have to ever worry about renewing certifcates. Overall I'm pretty impressed with Let's Encrypt.