Deploying Let’s Encrypt on an Amazon Linux AMI EC2 Instance
Are you experiencing migraines trying to install Let’s Encrypt on your Amazon Linux AMI EC2 Instance?
You’re not alone!
The Anticipation
Let’s Encrypt announced its public beta on a bitter cold day in December, 2015. I was attending the inaugural WordCamp US in Philadelphia, PA alongside about 1,800 peers whose personal livelihoods are built on the internet. The mood was electric. Google had been signaling that they favor HTTPS sites in search rankings for some time. “Finally, free SSL Certificates for all!” presenters throughout the morning enthusiastically exclaimed. By lunchtime dozens of developers had collected in the hallways, fervently entering commands into their terminal windows, all racing to implement this divine gift bestowed upon the world by an obscure acronym.
The Reality
As the day wore on I inquisitively approached a group of people I overheard discussing Let’s Encrypt. The consensus? Not one of them had successfully generated a valid SSL certificate for their site using the Let’s Encrypt software. A rather disheartening inception indeed! Not to be deterred, over the following months I gathered everything I could find about implementing Let’s Encrypt SSL certificate generation and management on my own AWS EC2 instance running Amazon Linux AMI and Apache. What follows is my process, and since there’s currently very little documentation of this niche implementation online if this saves just one other person some grief then the time spent will have been worth it.
Blindly follow me into the promised land!
Shameful admission: I’m adapting this documentation from step-by-step notes taken during my own install over three months ago, so please excuse any hazy details and certainly leave feedback if anything is unclear so I can make improvements!
(In)Compatibility with Amazon Linux AMI
At the time of writing the Let’s Encrypt Certbot still isn’t technically supported for deployment on the Amazon AMI flavor of Linux. It still works, though*! At this point it’s also worth it to note that Amazon itself also offers a free service, although I haven’t tried it because as I always say: “with just a little coffee and foolhardy perseverance you too can start generating and managing SSL Certificates yourself, for free!” Plus, think of the bragging rights.
* As long as you use the--debug
option on all commands
So without further ado…
The Install
1. Install Python:
$ yum install python27-devel git
2. Install Let’s Encrypt by cloning the github repository into /opt/letsencrypt
and running the Let’s Encrypt installer:
$ git clone https://github.com/letsencrypt/letsencrypt /opt/letsencrypt$ /opt/letsencrypt/letsencrypt-auto --debug
2a. If you’re running Amazon Linux 2 on your EC2 follow these additional steps (thanks @andrenakkurt!) before continuing.
3. Make a configuration file (/etc/letsencrypt/config.ini
) that will be used to sign all future certificates and renewals with your private key and email address:
$ echo "rsa-key-size = 4096" >> /etc/letsencrypt/config.ini$ echo "email = ________@____.com" >> /etc/letsencrypt/config.ini
Certificate Generation
1. Request a certificate the naked domain (_______.com
) and www subdomain (www._______.com
), using a “secret file” generated in a directory (.well-known
) in your website’s root folder (/var/www/_______
)
$ /opt/letsencrypt/letsencrypt-auto certonly --debug --webroot -w /var/www/_______ -d _______.com -d www._______.com --config /etc/letsencrypt/config.ini --agree-tos
Certificate files (cert.pem
, chain.pem
, fullchain.pem
, and privkey.pem
) are generated in an individual folder for each domain in /etc/letsencrypt/live/
(e.g. /etc/letsencrypt/live/_______.com/
)
- cert.pem: server certificate only.
- chain.pem: root and intermediate certificates only.
- fullchain.pem: combination of server, root and intermediate certificates (replaces
cert.pem
andchain.pem
). - privkey.pem: private key (do not share this with anyone!).
Take a note of your expiration date and other important information displayed on the confirmation screen.
2. Remove the now-empty “secret file” directory, if desired (for cleanliness)
$ rmdir /var/www/______/.well-known
Certificate Renewal — Manual
Let’s Encrypt includes a script to check and renew your certificates:
/opt/letsencrypt/letsencrypt-auto --no-bootstrap renew
Troubleshooting:
One common issue experienced on Amazon Linux AMI is receiving the following error:
Traceback (most recent call last):
File "/usr/local/bin/virtualenv", line 7, in <module>
from virtualenv import main
ImportError: No module named virtualenv
…or similarly:
/opt/letsencrypt/letsencrypt-auto: line 666: virtualenv: command not found
To resolve this, install/reinstall the python package “virtualenv” using PIP
$ sudo easy_install pip
$ sudo pip install virtualenv
Certificate Renewal — Automated
The easiest way to automate the above certificate renewal process is to add it to your cron process.
$ sudo nano /etc/crontab
Enter the following for a once-a-day check. Make sure you also refresh Apache, newly renewed certificates won’t be recognized otherwise!
# Renew SSL Certs
0 13 * * * ec2-user /opt/letsencrypt/letsencrypt-auto --no-bootstrap renew# Refresh Server
10 13 * * * root apachectl -k restart > /dev/null 2>&1
If your certificates fail to renew automatically see “Troubleshooting” under Certificate Renewal — Manual, many times it’s the virtualenv package failing to execute during the auto-renew process as well, a reinstall of that package should fix it.
Certificate Implementation
Adding your newly generated SSL Certificates to your website just requires making some additions to your virtual host configuration files.
$ sudo nano /etc/httpd/conf.d/_____.com.conf
If you want to force SSL (a good idea) add the following to the TOP of the config file before anything else:
# Force SSL
<IfModule mod_rewrite.c>
RewriteEngine On
RewriteCond %{HTTPS} !=on
RewriteRule ^/?(.*) https://%{SERVER_NAME}/$1 [R=301,L]
</IfModule>
Then add the port 443 (SSL) configuration below:
Listen 443
<VirtualHost *:443>
ServerAdmin ________@____.com
DocumentRoot /var/www/_______.com
ServerName _______.com
ServerAlias www._______.com # Logs
ErrorLog /var/www/logs/_______.com-ssl_error_log
CustomLog /var/www/logs/_______.com-ssl_access_log common # Certificates
SSLEngine on
SSLCertificateFile /etc/letsencrypt/live/___.com/cert.pem
SSLCertificateKeyFile /etc/letsencrypt/live/___.com/privkey.pem
SSLCertificateChainFile /etc/letsencrypt/live/___.com/chain.pem
SSLProtocol All -SSLv2 -SSLv3
SSLHonorCipherOrder on
SSLCipherSuite "EECDH+ECDSA+AESGCM EECDH+aRSA+AESGCM EECDH+ECDSA+SHA384 EECDH+ECDSA+SHA256 EECDH+aRSA+SHA384 EECDH+aRSA+SHA256 EECDH+aRSA+RC4 EECDH EDH+aRSA !RC4 !aNULL !eNULL !LOW !3DES !MD5 !EXP !PSK !SRP !DSS"
</VirtualHost>
Refresh Apache for the changes to take effect:
$ sudo apachectl graceful
Certificate Validity Audit
Here are a couple of methods to use to ensure your new certificate is configured properly and to check an existing certificate’s expiry date:
HTTP response:
$ curl -sIv https://_______.com |& grep expire
Direct file read:
$ sudo openssl x509 -noout -dates -in /etc/letsencrypt/live/_______.com/cert.pem
The following online tools are indispensable for checking and debugging invalid certificate issues:
- SSL Shopper’s SSL Checker
- In-depth certificate analysis on Why No Padlock
…and that’s it!
Further Reading
My own journey would have been impossible without the sages who blazed the untamed trail before me, to which I owe my sincere gratitude:
- Let’s Encrypt on EC2 — Ivo Petkov ← terse but invaluable resource
- Install Let’s Encrypt to Create SSL Certificates — Linode
<3/>