My current wild-cart SSL certificate will expire in a couple of days and I decide to try Let's Encrypt beta and move this website to Amazon S3 and CloudFront.
Until today, I hosted this website on DigitalOcean. Service that they provided was always great, but I don't use most of sub-domains configured on that server any more, this website is static HTML generated with Middleman and I have no longer need for any Server-Side work. Basically, I now only need to host static files somewhere, but with secure connection. Apparently Google, values HTTPS sites more than standard HTTP now and if you care about your page rank, you need to use secure connection.
What is Let's Encrypt?
According to their about page: "Let’s Encrypt is a free, automated, and open certificate authority (CA), run for the public’s benefit". You can get free SSL certificate, valid for three months (they suggest renewal every 2 months), just by using command line utility (letsencrypt client) and easily setup certificate renewal. You'll also need to prove that domain is yours by solving ACME challenge.
I'm big fan of AWS, with exception of how they (re)name things, but that is a story for another time I guess. Here is complete architecture of the site:
- Whole site is made of static files and only HTTP method needed is GET, so S3 is perfect for hosting.
- Unfortunately, HTTPS is not supported on S3, but I can use CloudFront (read: Amazon CDN) with my own certificate.
- I also decided to mode DNS from afraid.org to Amazon Route 53, but after everything else work correctly.
I will not go into details of creating everything on AWS, just list all steps involved:
- Create S3 bucket.
- Enable "Static web hosting" for that bucket and name 'index.html' as 'Index Document'.
- Upload all files into bucket and make them public.
- Create CloudFront distribution:
- Point 'origin' field to your S3 bucket.
- Add your domain in 'CNAMEs' field.
- Enable both HTTP and HTTPS.
- Wait until distribution is created by AWS.
- Check if everything works correctly using URL for your distribution.
- Point your domain to your CloudFront distribution. If you are on Amazon Route 53, just create alias. Otherwise, you can use CNAME.
Installing Let's Encrypt
letsencrypt has to run on the server where SSL certificate have to be installed. In this case is that CloudFront and only way to do that is to use API's. There is already tool to do that, letsencrypt-s3front. Both this tool and official Let's Encrypt library are written in Python programming language and installable with
pip. If you are on GNU/Linux, you probably have both Python and pip installed. On OS X, you will have Python, but without pip. I installed it with
sudo easy_install pip.
I tried to fallow instruction on letsencrypt-s3front README, but did not manage to install it correctly. It appears that
pip try to uninstall some Python libraries and even if you run
pip with sudo it does not work on OS X. I should probably try to install
pyenv (fork of
rbenv for Python) and install local version of Python and try it that way. Unfortunately, my lack of any Python knowledge (one of the few programming languages I never touched in my life) prevented me to do that at this point. There is a chance that there is obvious solution if you know Python.
At the end, I was following instructions on 'letsencrypt' github page:
$ git clone https://github.com/letsencrypt/letsencrypt $ cd letsencrypt $ ./letsencrypt-auto
letsencrypt-auto quit on me, telling me that OS X support is experimental and that I need to ran with
letsencrypt-auto is a wrapper around
letsencrypt command, that also checks for updates and. After running with
letsencrypt-auto started to install some packages using 'homebrew'. I'm quiet sure that I had 'libxml' already installed ('nokogiri' ruby gem uses that), but I saw it between installed packages. After homebrew part,
letsencrypt-auto failed big time trying to install yet another Python package using
pip. Then I run same command with sudo and package got installed, but yet another error was generated (uninstall package thing again). After all that I was able to use
letsencrypt-auto to generate SSL certificate with following:
$ sudo ./letsencrypt-auto certonly --debug -a manual -d www.simplify.ba
certonly option will just generate SLL certificate. If I used
apache option, Let's encrypt client will also try to install certificate in Apache web server. In my case,
certonly is exactly what I need.
I had to do this three times. First time it failed because of domain validation. During the process, they ask you to place specific file (.well-knows/acme-challenge/(some-hash-as-file-name)) with another longer hash inside it. I forgot to change mime type of that file to 'text/plain'. Personally, I think that they need to add alternative to this file placement, for example adding TXT record into DNS. Maybe there is, with plug-ins.
Can't remember what was the problem second time, but after third try SSL certificates are generated into
/etc/letsencrypt/live/www.simplify.ba/. Let's Encrypt tries to use the best security standards, and makes directories with SSL certificates available only to 'root' user. Another frustrating thing if you are on OS X (run
sudo su to become 'root' user and get access to certificates).
Placing SSL certificate into CloudFront
The easiest way seem to be using
aws utility. Another Python, install with
pip thing… Run
sudo pip install awscli. I got an error running that (another uninstall thing) but
aws utility was installed.
I placed SSL certificate in CloudFront with:
$ aws iam upload-server-certificate --server-certificate-name www.simplify.ba-ssl --certificate-body file://cert1.pem --private-key file://privkey1.pem --certificate-chain file://chain1.pem --path /cloudfront/prod/
After that, SSL certificate with name 'www.simplify.ba-ssl' appeared in CloudFront distribution settings and I was able to select it. Just don't forget to set
AWS_SECRET_ACCESS_KEY in your ENV.
This is most frustrating thing I did in a last few months. I know that Lets's Encrypt is still in beta and things will change with time and after other clients emerge, but right now it's barely working on OS X. It's clear that their focus now is on GNU/Linux servers and that they expect that you run
letsencrypt on same machine where SSL certificate needs to be installed. I think that if I had any Python knowledge things would go faster.
I'm going to investigate better ways to do this (using
pyenv, run on GNU/Linux or on a small Vegrant vm or even better option, to try alternative client) and most importantly find a way to automatically renew certificate every two or three months. Apparently, you can use AWS Lambda to do that, so I'll maybe give it a try soon.
UPDATE: 2016-02-23: Found a much better solution.