Skip to content

Instantly share code, notes, and snippets.

@vasansr
Last active March 12, 2021 05:00
Show Gist options
  • Save vasansr/4698d685b100df2aef5d0407a57886f0 to your computer and use it in GitHub Desktop.
Save vasansr/4698d685b100df2aef5d0407a57886f0 to your computer and use it in GitHub Desktop.

Setting up a static website using S3 with a custom domain and SSL

Multiple things need to be done for this, the following steps are listed in the order of convenience, that is, things that take time are done first.

Note: If you don't need SSL, the AWS documentation shows you how you can do this quite simply: https://docs.aws.amazon.com/AmazonS3/latest/userguide/website-hosting-custom-domain-walkthrough.html

Register your domain

If the domain is not registered, register it. Which provider you use to register is up to you. AWS itself is one choice which makes things very easy, but this is not a viable option for many. In this page, we will use example.com as the domain name.

Use Route 53 to manage the DNS

If you have used AWS to register your domain, it will manage your DNS by default, so you can skip this section completely. Otherwise, you will have to set up Route 53 to manage the DNS for your domain. You can complete the website setup without doing this, but letting AWS manage it makes verification of SSL certificates a breeze. And, it doesn't make much difference who manages the DNS, so might as well use AWS.

The way to do it is to tell your domain provider (eg, GoDaddy) to resolve DNS requests to your domain using AWS's domain servers.

Create a Hosted Zone for the domain

Using Route 53, create a new Hosted Zone. Specify the domain you have registered during the creation process. This will create a few record sets automatically, one of which will be called NS. It will have 4 name servers, for example:

  • ns-798.awsdns-35.net
  • ns-100.awsdns-12.com
  • ns-1184.awsdns-20.org
  • ns-1922.awsdns-48.co.uk

Go to the domain provider's website where you registered your domain and in the Name Servers section enter the names (you will have to copy-paste from your Hosted Zone, do not use the above names).

Now, you have successfully set AWS as the DNS manager for your domains.

Create an SSL certificate

Use the AWS Certificate Manager and create an SSL certificate. Note that this is free, making S3 based hosting one of the cheapest options. For the domain name, add two domains:

  • *.example.com
  • example.com

The first entry makes the certificate applicable to all sub-domains and the second entry makes the certificate applicable to the domain. Thus, with a single certificate you can host multiple websites.

Verify your Domain

In order to create the certificate, AWS needs to verify that you own the domain. If you do own the domain, then you should be able to add a DNS record that AWS can verify. AWS gives you a random key and asks you to create a CNAME record using this with another random key as the mapped name. AWS will then check that this has been done successfully by making a DNS request.

You could also use the email method of verification, but the DNS method is far simpler, especially if you are using Route 53. If you were not using Route 53 to manage your DNS, you should copy paste the sub-domain that AWS asks you to create a record for, use the CNAME type and the value also copied from the Validation screen.

If you are using Route 53, there will appear buttons which can just be clicked to create the CNAME record -- no need to copy-paste to create these records. Do that and click on Continue to proceed with the verification.

Since DNS records take some time to propagate, the certificate request will stay at "Pending Verification" for 3-5 minutes. You can leave it at this and proceed with the rest of the steps.

Create an S3 bucket and upload the website files

Create an S3 bucket, and name it the same as your website's domain name, for example, www.example.com. To make the files public, couple of things need to be done:

  1. Uncheck all "Block ... ACL ..." checkboxes in the Permissions. You will find 4 such checkboxes. This is so that the next step is not denied permission.
  2. Create a Bucket Policy that allows public access to the entire bucket. This can be done after creation of the bucket in the Permissions -> Bucket Policy tab for the bucket. Add the following lines:
{
    "Version": "2012-10-17",
    "Statement": [
        {
            "Sid": "PublicReadGetObject",
            "Effect": "Allow",
            "Principal": "*",
            "Action": "s3:GetObject",
            "Resource": "arn:aws:s3:::www.example.com/*"
        }
    ]
}

TODO: Is this really required? Won't Cloudfront internally fetch files?

Note that you do not need to enable "Static Website Hosting" in the Properties tab for the bucket, because we won't be using the S3 based hosting, instead, we'll be front-ending it with Cloudfront.

Now you can upload your files. At this point in time your files should be accessible vi the S3 bucket URL, for example, http://www.example.com.s3.amazonaws.com/index.html. Not that it will not translate / to /index.html, you are accessing the bucket's objects directly, not as a website.

If you do enable "Static Website Hosting", you should be able to set your home page as index.html and access it like this: http://www.example.com.s3-website.ap-south1.amazonaws.com

Set up Cloudfront

The next step is to set up a Cloudfront distribution for the bucket. Note that you cannot assign a custom domain to the bucket directly, it has to be done via Cloudfront. This does increase your costs a bit, but it's unavoidable.

This should be quite straightforward, but since there are many options and settings, let me point out a few that you should not miss:

  • Origin: This should show a dropdown, with the S3 bucket called www.example.com.s3.amazonaws.com as an option that you can select.
  • SSL Certificate: Choose custom SSL certificate and use the one that you generated using Certificate Management.
  • Alternate Domain Names: Add both example.com and www.example.com.
  • Default Root Object: index.html or whichever file that you need to be served when the user accesses /

Set up DNS Alias

The final step is to set up the DNS alias. Even though this takes time, we couldn't have done it earlier because the Cloudfront domain is generated only in the previous step. We need it.

Go to Route 53 and add A records for www.example.com and example.com. Set Alias to Yes and in the alias field, you'll find a dropdown. Ensure you choose the Cloudfront endpoint for www.example.com and not the S3 bucket.

Using a CNAME is another way to create an alias, but you can't create one this way for the main domain example.com. You need a A record with an ALIAS.

After the DNS name propagates and starts resolving (you should be able to check this by running the command host www.example.com to see if it resolves), your website should be working, with both SSL and plain-text modes.

Changes

Note that any changes to files or permissions will only take effect after you invalidate the Cloudfront cache. It is a good practice to keep contents of files unchanged. If there is a change, it's better to generate a new file. This of course, won't work for index.html, so for this and a few other files which can change, create invlidations whenever they change.

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment