Add https to Amazon S3 hosted website

First word: always make sure you understand the costs of using the following cloud services.

In this tutorial, I’m going to show you how to add a certificate to a site hosted on Amazon S3 with a custom domain, so that your site will be accessed like https://your_site.something. For this article we’ll use ‘Let’s encrypt‘ to get the certificate. Later on, I will add an article on how to do this with the new Amazon Certificate Manager, who promises to issue free certificates and automatic renewals. Until then, let’s roll.
We assume you already have a static site hosted on Amazon S3 and you serve it using a custom domain on Route 53.

Usually, to generate a certificate with Let’s Encrypt, you need to have access to the server who’s serving you website so that Let’s Encrypt could verify the domain and issue the certificate. That’s not the case with Amazon S3, where we have the access to a bucket, not the server itself. So we have to ‘simulate’ the server on our local machine when we do the request.

First, install the Certbot (former letsencrypt-auto) program on your local machine. Since I did it on an osx machine, I used [shell]brew certbot[/shell] as a breeze. Once installed, we need to send the request to Let’s Encrypt to ask for certificate. We do that with the command [shell]sudo certbot certonly –manual –server -d[/shell]. You’ll be asked for the password of your user by the machine to execute the sudo command, then you get prompt if you are ok with storing the machine ip for the cert issue. After that you’ll get a text as following:


Make sure your web server displays the following content at before continuing:


If you don’t have HTTP server configured, you can run the following command on the target server (as root):

mkdir -p /tmp/certbot/public_html/.well-known/acme-challenge cd /tmp/certbot/public_html printf “%s” UiZ36DufCQCnrnxyxyxyxyxyxyxyPsGwE.nfU54PpxyxyxyxyxyxyxyxyxyxyyxxUb3cl4-xqrynk0 > .well-known/acme-challenge/UiZ36DufCQCnrnxyxyxyxyxyxyxyxyxyxyxyxyxysGwE # run only once per server: $(command -v python2 || command -v python2.7 || command -v python2.6) -c \ “import BaseHTTPServer, SimpleHTTPServer; \ s = BaseHTTPServer.HTTPServer((”, 80), SimpleHTTPServer.SimpleHTTPRequestHandler); \ s.serve_forever()”
——————————————————————————-Press Enter to Continue[/shell]

Do not press Enter until the next step.

At this point, the challenge is open (meaning the verification for your domain started). Next step is to create a file on your local machine with the name shown on the line
[shell][/shell]. Use only the name [shell]UiZ36DufCQCnrnxyxyxyxyxyxyxyxyxyxyxy1rcPsGwE[/shell], not the entire path, no extension. Next, copy/paste the line [shell]UiZ36DufCQCnrnxyxyxyxyxyxyxy1rcPsGwE.nfU54PpVrxyxyxyxyxyxyuYMZUb3cl4-xqrynk0[/shell] as content of the page.
Now, you have the file, we need to upload it on a specific place on your S3 bucket where Let’s encrypt will search for it and hopefully validate the domain. On the root of your bucket create the folder [shell].well-known[/shell], then inside create the folder [shell]acme-challenge[/shell], then inside of this one upload the file created.

All done, now press enter on the terminal where you left off the previous step. If all went well, you’ll get a message like:

[shell]Waiting for verification… Cleaning up challenges Generating key (2048bits): /etc/letsencrypt/keys/0000_key-certbot.pem Creating CSR: /etc/letsencrypt/csr/0000_csr-certbot.pem/
IMPORTANT NOTES: – Congratulations! Your certificate and chain have been saved at /etc/letsencrypt/live/ Your cert will expire on 2017-07-17. To obtain a new or tweaked version of this certificate in the future, simply run certbot again. To non-interactively renew *all* of your certificates, run “certbot renew” – If you like Certbot, please consider supporting our work by:

Donating to ISRG / Let’s Encrypt:
Donating to EFF:          [/shell]

At this point we have the certificate on the local machine and we need to upload it to Amazon Cert Manager. But first, we have to be able to read and copy the content. The certificates and the private key are stored locally on [shell]/etc/letsencrypt/live/[/shell]. Those are only simlinks to the actual files, used on the actual server (remember all this is supposed to be done on actual server). To see the path to actual file from a simlink run [shell]readlink nameoffile.ext[/shell]. The files that we need are: [shell]etc/letsencrypt/archive/[/shell],[shell]etc/letsencrypt/archive/[/shell] and [shell]etc/letsencrypt/archive/[/shell]. Open them with cat or whatever editor you like. If at some point you get Permission denied when accessing a folder, run [shell]sudo chmod -R 755 /etc/letsencrypt/archive[/shell] to gain permission. (ATTENTION! Always be careful where you copy or expose your private keys).

Now that we have the files open, let’s go to AWS Cert Manager. Click ‘Get started‘ -> ‘Import a certificate‘.
On ‘Certificate body‘ copy/paste the first certificate from [shell]fullchain1.pem[/shell] starting from [shell]—–BEGIN CERTIFICATE—–[/shell] to [shell]—–END CERTIFICATE—–[/shell] included. On ‘Certificate private key‘ copy paste the private key from [shell]privkey1.pem[/shell] from [shell]—–BEGIN PRIVATE KEY—–[/shell] to [shell]—–END PRIVATE KEY—–[/shell] included. On ‘Certificate chain‘ copy/paste the first certificate from [shell]chain1.pem[/shell] from [shell]—–BEGIN CERTIFICATE—–[/shell] to [shell]—–END CERTIFICATE—–[/shell] included (this one is needed since it’s not a self signed cert).

Then click import and your cert should be imported and ready to use.

Now, the only way at this point to have a certificate added to your S3 hosted site is by using the Amazon CloudFront CDN. So now we go to ClodFront -> Create Distribution. Next step is assuming you are creating a CloudFront distribution, if you have one already, just select the certificate to be used on it.
On the origin part, click on “Origin Domain Name” input field to have a list of your S3 buckets and choose
the one you want. Add or create identity as needed. On the Cache Behavior choose the right settings for you, open the info if something not clear. On the distribution settings check the added Custom SSL certificate you added and set the other options as you wish. Then hit ‘Create Distribution‘ and wait until is created (up to a half hour normally). Do not forget to put your domain on ‘Alternate Domain Names (cnames) : and to complete your ‘Default Root Object’ : index.html or whatever the object you want to point at by default. At the end, you’ll have a domain name in the form of If you acces you should see your page on the browser.

When all is done on CloudFront, take the address generated on domain name and go to the Route 53 (supposed you add CloudFront, if you already have it and just add certificate, then you’re done). Delete your old alias on the domain you want to route to CloudFront, then create a new one. If ipv6 is enabled on your CloudFront, you have to add two aliases, one for ipv4 one for ipv6. Check ‘Alias‘ ‘Yes‘, then choose from drop down the CloudFront distribution you created. If is not listed there, copy the domain name from CloudFront. Let ‘Routing Policy‘ ‘Simple‘ and ‘Evaluate Target Healt‘ : ‘No‘ (not possible on CloudFront).

This was your final step, go to browser and enter ‘‘ on the address bar and you should be served with a https page.

Don’t forget that Let’s encrypt certificates have a validity of 3 months. To renew, redo the steps on this article. Have fun 🙂

Leave a Reply

Your email address will not be published. Required fields are marked *