I was excited to hear the other day that the beta of the lets encrypt project had gone live. For those of you that don’t know this is a great project that provides free SSL certificates to any website with the aim of finally moving much of the internet to SSL. However it’s not quite as easy to use as I had hoped, so I documented the process and the issues I ran in to below with the aim of helping some other people out that are wanting to do the same. My setup is apache on linux ubuntu but it should be true for most other flavours of linux.
Firstly, I downloaded and installed letsencrypt on my server as per the instructions:
git clone https://github.com/letsencrypt/letsencrypt
cd letsencrypt
I had thought that simply running their advised command of:
./letsencrypt-auto --apache
would convert my apache setup to use https and provide a certificate for each domain on my server. It doesn’t. Whilst it’s a great tool it is still in beta and even after that I’m not sure if the auto configuration functionality would be included. My first issue was that it presented a long list of all the domians in my apache config; some of which were live and some wern’t. You have to select which you want to get a certificate for. However if you select any that are not accessible or not supported (i18n domains ie those beginning xn--
or wildcard domains) then the process dies with an error and you have to restart selecting which domains you want. This is clearly an issue they could fix pretty simply in the code and hopefully that will happen before long. Also, you have to renew the SSL certs every three months and I believe that you have to go through this same process again each time rather than just hitting a renew button.
Another issue that I ran against which is probably more of a design issue is the idea that it issues you one certificate per server. This is fine if you are just hosting one set of domains; however if you have multiple virtual host entries or host multiple sites that are logically separate you probably don’t want to go down this route.
So, because of these issues I gave up on the automatic apache client and wrote a little script that gets a certificate for each virtual server configuration file and excludes i18n domain names, wildcard, localhost and optionally any others. You should be able to just run this script once every few months and it will automatically regenerate all your SSL certificates without having to change any of your config:
for conf in /etc/apache2/sites-enabled/*; do
cmd=$(perl -nE 'next unless /Server(Name|Alias)/i; next if /xn--|\*|localhost|127|my-other-nonregistered-domain.com.../i; $d=(split " ", $_)[1]; print "-d $d "' $conf)
if [ ! -z "$cmd" ]; then
echo $conf
/root/letsencrypt/letsencrypt-auto certonly --apache $cmd
fi
done
Just save that to a file like /etc/apache2/regen_ssl.sh
and run it with bash
, or paste it directly into your shell and you will then get a load of directories under /etc/letsencrypt/live/
with your certificates in. Each directory should be called after the first ServerName
configuration option in the particular virtual host configuration file.
To get the certificates auto-renewing you want to edit the crontab to execute this every few months:
# Refetch all certificates every 2 months
4 4 1 */2 * bash /etc/apache2/regen_ssl.sh
BUT, the process doesn’t end there – you have to set up apache for each domain you want to enable ssl on. First, enable SSL globally:
a2enmod ssl
service apache2 restart
Also make sure to update your firewall to allow HTTPS (port 443) traffic. Then for each virtual host you should change the header line from:
<VirtualHost *:80>
to
<VirtualHost *:80 *:443>
Then you need to enable SSL and specify the certificates:
SSLEngine on
SSLCertificateFile /etc/letsencrypt/live/mark.zealey.org/cert.pem
SSLCertificateKeyFile /etc/letsencrypt/live/mark.zealey.org/privkey.pem
SSLCertificateChainFile /etc/letsencrypt/live/mark.zealey.org/fullchain.pem
A service apache2 graceful
should then mean you can access your site via https.
If you want to force traffic to use HTTPS there are a number of different routes; the correct way is to use HSTS; however if for some reason you discover that your site doesn’t work correctly using HTTP (eg you have iframes or javascript that is not on SSL-enabled servers) you want to be able to quickly revert to not force clients to use SSL. For the initial deployment then I used the amazing apache2 mod_rewrite to handle this:
RewriteEngine On
RewriteCond %{HTTPS} !=on
RewriteRule ^/?(.*) https://%{SERVER_NAME}/$1 [R,L]
If you are running a blog and you just want to force areas where secure information is transferred (eg user login page) to use SSL so people can’t snoop on your password, you could use something like this (for drupal)
RewriteEngine On
RewriteCond %{HTTPS} !=on
RewriteCond %{REQUEST_URI} ^/(user|admin)/
RewriteRule ^/?(.*) https://%{SERVER_NAME}/$1 [R,L]
If you’re running a site where you have some mobile or legacy clients accessing your API, but you want new web clients forced to use SSL, you could have some config like this:
RewriteEngine On
RewriteCond %{HTTPS} !=on
RewriteCond %{REQUEST_URI} !^/api/.*
RewriteRule ^/?(.*) https://%{SERVER_NAME}/$1 [R,L]