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
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.
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.
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.
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.
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 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:
- 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.
- 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
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
andwww.example.com
. - Default Root Object: index.html or whichever file that you need to be
served when the user accesses
/
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.
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.