Archive
This post is archived and may contain outdated information. It has been set to 'noindex' and should stop showing up in search results.
Using HTTPS with Amazon S3 and Your Domain
Sep 4, 2016Web DevelopmentComments (8)
One of the cool things about Amazon S3 (and most other cloud storage services) is that you can map your own domain or subdomain to your bucket using a CNAME, so it looks like resources are being served by your website. The downside is it doesn't work with HTTPS.

For example: Say your main website is www.mywebsite.com and you have mapped your subdomain i.mywebsite.com to your Amazon S3 bucket named "i.mywebsite.com". You can now make calls to resources in your bucket like this:

http://i.mywebsite.com/myimage.jpg
But if you try to do it with HTTPS, it will not respond:

https://i.mywebsite.com/myimage.jpg
You can access your bucket directly using HTTPS and it works though:

https://s3-myregion.amazonaws.com/i.mywebsite.com/myimage.jpg
The reason for this is that Amazon's hosts have valid SSL certificates, while your i.mywebsite.com subdomain does not.


Getting an SSL Certificate and CloudFront


Amazon offers free SSL certificates using the AWS Certificate Manager, but there's no way to assign one to an S3 bucket. You can only assign SSL certificates to an Amazon Elastic Load Balancer or CloudFront distribution.

CloudFront
The solution then is to put your S3 bucket behind a CloudFront distribution, assign the SSL certificate to the CloudFront distribution, and map your domain to your CloudFront distribution URL using a CNAME. It sounds complicated, but setup is pretty easy.

Note About Pricing
Pricing for bandwidth and requests between S3 and CloudFront is similar, though CloudFront can get more expensive if you have a lot of users outside of North America and Europe. You can view S3 pricing and CloudFront pricing to compare them. If you're worried about pricing to remote regions, you can set the "Price Class" to only use US, Canada, and Europe. Or you could also run it all through CloudFlare, which will offload a lot of bandwidth and requests.

Step 1: Get Your Domain ready
You need to be able to receive email at the domain you plan to create an SSL certificate for, so Amazon can verify your domain ownership.

Example: If you plan to create an SSL cert for "i.mywebsite.com", you must be able to receive email at one of any of these addresses:

administrator@i.mywebsite.com
webmaster@i.mywebsite.com
hostmaster@i.mywebsite.com
postmaster@i.mywebsite.com
admin@i.mywebsite.com

As well as the email address in your WHOIS lookup for the domain. If you're using WHOIS privacy, that won't be too useful though, so you'll have to make sure you have a valid email at one of the above addresses.

Step 2: Create SSL Certificate
Navigate to Certificate Manager in your AWS console and click "Request a Certificate". Type in the domain/subdomain you'll be using. Hit "Review and request", then "Confirm and request" on the next page. Amazon will send you an email. Go check it and confirm ownership following its directions.

Step 3: Create CloudFront Distribution
Navigate to CloudFront in your AWS console and click "Create Distribution". Click "Get Started" under the Web option (not the RTMP). You'll arrive on the Create Distribution page. Here you need to change three things:

  1. Click inside the input field for "Origin Domain Name". A list of your Amazon S3 buckets should pop up. Select the S3 bucket you want to use.
  2. Scroll to the "Alternate Domain Names (CNAMEs)" field and enter your domain/subdomain you're using (example: i.mywebsite.com).
  3. Scroll down to SSL Certificate and change the option to "Custom SSL Certificate", then select the certificate you just created in the drop-down list. Scroll the rest of the way down and click "Create Distribution".

Step 4: Change Domain CNAME
Your CloudFront "Domain Name" is what you use to access the S3 bucket behind CloudFront. It will look like this:

dpx37t3iha46a.cloudfront.net
You can find the CloudFront Domain Name on either your CloudFront dashboard, or after clicking into one of your distributions. Once you have it, change the CNAME for your i.mywebsite record to it. Be sure to wait until your CloudFront distribution's State is "Enabled" though. It will sit as "In Progress" for a few minutes after your create it before it will work.

Once all done, all of these links will point to the same resource in your S3 bucket, and HTTPS will work as intended:

https://s3-myregion.amazonaws.com/i.mywebsite.com/myimage.png
https://dpx37t3iha46a.cloudfront.net/myimage.jpg
https://i.mywebsite.com/myimage.jpg
Comments (8)
Add a Comment
Tom A   Dec 21, 2019
Gil, thank you for that note about needing to be in US East. I tried US East (Ohio) and it didn't work. It wasn't until I switch it to Virginia that it worked. I think the easiest solution is to click the "Request or Import a Certificate with ACM" button and it will auto-set the region.
Gil Poulsen   Oct 06, 2018
Thank you for this! Worked great once I realized my one error, so thought I would mention it in case it helps someone else. I created the cert, it was approved and I started setting up the distribution in CloudFront but no matter what I did, I could not select the radio button to use the cert I just created. After logging in and out and trying some other things, I finally realized that I had somehow created my cert in the US West region, and CloudFront cannot use certs created anywhere but in US East. So I went back to the Certificate Manager, made sure I was logged into US East and not Global or US West, and recreated the cert. Went back to create the CloudFront distribution again and this time I was able to choose my cert, and all worked perfectly from that point forward. Thanks again!
Jacqui   Aug 08, 2018
Is this still the case 2 years later - that Amazon S3 doesn't support domain/subdomain mapping using a CNAME, with HTTPS? I am trying to configure a Wordpress plugin to use S3 to serve my assets, and there is a setting to replace site's hostname with a CNAME, but I am running into an apparent security issue: NET::ERR_CERT_COMMON_NAME_INVALID Subject: *.s3.amazonaws.com I don't want to use CloudFront if i don't have to, especially since we're still in the dev stage. But will that really be the only solution when we go live?
Jeremy   Apr 11, 2018
This is great thank you very much for the excellent tutorial! Two notes: 1) In Step 1, AWS also supports domain validation with a CNAME record. I find this easier than trying to configure email on a subdomain. 2) In Step 3.1, AWS will offer a list of buckets, but they will default to the generic S3 URL (*.s3.amazonaws.com). If you don't want to wait forever for your changes to take effect, you should use the regional URL for your Origin Domain Name instead that is, i.example.com.s3-us-west-2.amazonaws.com instead of i.example.com.s3.amazonaws.com.
Terje Dahl   Dec 13, 2017
Very nice. Worked well. One sticking point: SSL Certificate, see: https://stackoverflow.com/questions/28609262/unable-to-select-custom-ssl-certificate-stored-in-aws-iam#28735773 For me, that simply meant using this URL for creating the certificate: https://console.aws.amazon.com/acm/home?region=us-east-1#/wizard/ It then appeared almost immediately. PS. Keep in mind that CloudFont is a web-caching system. That means that you won't see changes to content for a while unless you either adjust the TTL-times under Behavior/Default Cache Behavior, or you do invalidations of files or folders - either manually under Invalidations, or by CLI (from a deploy-script) as part of the deploy. Ex.: aws cloudfront create-invalidation --distribution-id XXX --paths /x/y /z/* /etc.
Kevin Chandler   Jun 07, 2017
Great post! I'll add that you may need to set the "Default Root Object" on your CloudFront Distribution if you'd like the root url to render, say, index.html
William Strachan   Mar 14, 2017
This is a solid write up. Thanks for sharing! Yakir, I'm sure you've figured it out by now, but basically you need to create a CNAME or an A record ALIAS in Route53 that points to your new distribution's Domain Name (i.e. the ***.cloudfront.net thingy).
Yakir Gagnon   Feb 18, 2017
Great post, but I'm really strugling with one sentence in these instructons: "Once you have it, change the CNAME for your i.mywebsite record to it." I managed to follow everyhting up to that point, but not sure how exactly and which CNAME I shoudl change..? In Route 53, in the hosted zone for my website, should I create a new record set, for the ***.cloudfront.net thingy..? Would really appreciate any additional details or help!