How to setup SSL on Amazon Web Services with Nginx
If you wanted to enable SSL
for your website, it is the best time to do it - "Let's Encrypt" provides SSL
certificates for free. This article describes how to setup SSL
using certificate issued by "Let's Encrypt" for the Amazon EC2
instance and Amazon S3
bucket.
Part 1. Setting up SSL for the Amazon EC2 instance
The first thing you should do is to prepare your machine.
-
Install
Python 2.7
and header libs:$ sudo yum install python27 python27-devel
-
Update symlink to the
Python
installation:$ ln -sfn /usr/bin/python2.7 /etc/alternatives/python
-
Install
PIP
:$ sudo curl https://bootstrap.pypa.io/get-pip.py | python2.7
-
Or update
PIP
if you already have it installed:$ pip install --upgrade pip
-
Update Virtual Environment:
$ pip install --upgrade virtualenv
-
Create new virtual environment:
$ virtualenv -p /usr/bin/python27 venv27
-
Activate virtual environment:
$ . venv27/bin/activate
-
If you don't have Git installed on your machine, install it:
$ yum install git
-
Clone "Let's Encrypt" repo and go to the
letsencrypt
folder:$ git clone https://github.com/letsencrypt/letsencrypt && cd letsencrypt/
-
If you have
Nginx
server running, stop it:$ service nginx stop
-
Run
standalone
plugin to issue the certificate. Please note, that runningstandalone
plugin requires port80
to be free (that is whyNginx
was stopped in the previous step) since this plugin will run the temporary server on it:$ ./letsencrypt-auto certonly --debug --standalone -d <domain-name>
-
After last step you'll find 4 files in the
/etc/letsencrypt/live/<domain-name>
:
cert.pem
: Your domain's certificatechain.pem
: The Let's Encrypt chain certificatefullchain.pem
: cert.pem and chain.pem combinedprivkey.pem
: Your certificate's private key
-
Now you need to edit
Nginx
configuration file, setup certificate and write a rule to redirect fromhttp
to thehttps
version of your site:server { listen 80; server_name <your_server_name>; return 301 https://$server_name$request_uri; } server { listen 443 ssl; server_name your_server_name; ... add_header Strict-Transport-Security "max-age=31536000"; ssl_certificate /etc/letsencrypt/live/<domain-name>/fullchain.pem; ssl_certificate_key /etc/letsencrypt/live/<domain-name>/privkey.pem; ssl_protocols TLSv1 TLSv1.1 TLSv1.2; ssl_prefer_server_ciphers on; ssl_ciphers 'EECDH+AESGCM:EDH+AESGCM:AES256+EECDH:AES256+EDH:AES256+ECDHE'; ... }
-
Open port
443
in the security group for theEC2
instance you are using in the EC2 management console. -
Great, now you can start the server and enjoy using
SSL
:$ service nginx start
-
Test the server for the
SSL
configuration on the SSL Labs website. Probably, your mark will beB
. This is because your server is vulnerable to theLogjam
attack (more reading here, but this issue can be solved easily. All you need to do is just to generate strong Diffie-Hellman group:$ openssl dhparam -out dhparams.pem 2048
And use it in the
Nginx
configuration:server { ... ssl_dhparam {path to dhparams.pem} ... }
-
Re-test the site using SSL Labs, now you should have
A+
rating. -
Please note, that certificates issued by "Let's Encrypt" are valid for 3 months, so every 3 months you should renew them. You can take a look at the official guide for the details.
Part 2. Setting up SSL for the Amazon S3
If you are hosting static files on the Amazon S3
and would like to access the bucket using SSL
with you domain name, this part is for you (please note, that by default Amazon S3
already provides SSL
support for the buckets by using address https://<bucket-name>.<region>.amazonaws.com
). For this part you'll have to use Amazon CloudFront
service, please check the pricing.
-
Since you have no access to the
Amazon S3
server, you need to usemanual
plugin to generate the certificate (you should haveDNS
record with statics sub-domain pointing to theAmazon S3
bucket):$ ./letsencrypt-auto certonly --manual -d <your-subdomain-name>
By using this plugin you'll be asked to place special file with a special string in the bucket. After verification is completed, you'll get the same 4 files as in previous part.
-
Install
Amazon Web Services CLI
:$ pip install awscli
-
Log in to the
Amazon IAM
console. Now you need to create a user, just clickUsers
->Create New Users
. After user is created, save the file with its credentials (it will containAccess Key Id
andSecret Access Key
), then click on its name and copyUser ARN
. -
The next thing you should do is to create the policy to upload the certificate. For this you can use policy generator:
Policies
->Create Policy
-> SelectPolicy Generator
-> SelectAWS Identity and Access Management
in theAWS Service
dropdown and checkUploadServerCertificate
in theActions
dropdown. In theAmazon Resource Name (ARN)
pasteARN
from the previous step. After the policy is created, attach it to the user. -
Configure
Amazon Web Services CLI
:$ awscli configure
Paste
Access Key Id
andSecret Access Key
you've got on the step 3, other fields can be skipped. -
Upload certificate to the
AWS
:$ sudo aws iam upload-server-certificate --server-certificate-name <certificate-name> --certificate-body file:///etc/letsencrypt/live/<subdomain-name>/cert.pem --private-key file:///etc/letsencrypt/live/<subdomain-name>/privkey.pem --certificate-chain file:///etc/letsencrypt/live/<subdomain-name>/chain.pem --path /cloudfront/certs/
-
Log in to the
Amazon CloudFront
console. Click on theCreate Distribution
button ->Web
distribution. -
The fields you should change/fill:
Origin Domain Name
: click and selectS3
bucket.Origin ID
: type some unique name.View Protocol Policy
:HTTPS only
, but you can leave it as is if you want -HTTP and HTTPS
.Alternate Domain Names (CNAMEs)
: type your sub-domain name.SSL Certificate
: clickCustom SSL Certificate
and choose the one you've uploaded at the step 6.Custom SSL Client Support
: SelectOnly Clients that Support Server Name Indication (SNI)
. It is very important to choose this option, otherwise you'll be charged for ~600$ per month.
-
Click
Create distribution
. After that you'll be given a link like<hash>.cloudfront.net
. Please note, that it will take some time for the distribution to be created. -
Open console of your
DNS
registrar and createCNAME
record with your sub-domain pointing to theCloudFront
address you've got at the previous step. That is it, now you have workingSSL
forAmazon S3
bucket with your sub-domain name.
Part 3. Troubleshooting
-
ERR_SSL_VERSION_OR_CIPHER_MISMATCH
(Chrome)/ssl_error_no_cypher_overlap
(Firefox) error while trying to access resource on theAmazon S3
bucket using my sub-domain.Probably, you didn't fill correctly
Alternate Domain Names (CNAMEs)
field for theCloudFront
distribution. -
Website cannot be opened because of timeout error.
Probably, you forgot to open port 443 in the security group of the
EC2
instance. -
Running
letsencrypt-auto
returnsImportError: No module named OpenSSL
error.Old Amazon AMIs have outdated
virtualenv
, that is why you have to update it.OpenSSL
module will be installed tolib64
folder and this path is not correctly handled byvirtualenv
. See https://github.com/letsencrypt/letsencrypt/issues/1680#issuecomment-170641501. You can check whereOpenSSL
is installed by running:$ find ./ -type d | grep -i openssl