Publishing a Static Website Using Amazon S3

This website is written in reStructuredText, rendered to HTML using Sphinx, and then published into an Amazon S3 bucket with a command-line script.

Here are the steps I use to rebuild and publish my website:

# rebuild my website
make html

# publish to S3.
aws s3 sync --delete --acl public-read build/html/ s3://www.abstrys.com

Simple, eh?

Publishing a website using this method is easy and fast, but there’s a little bit of setup first. It involves two AWS Services: Amazon S3 and Route53. I use the AWS CLI to work with AWS.

Prerequisites

To follow these steps, you’ll need a couple of things in advance:

  • A domain for your website. While this isn’t strictly necessary, having a website name like http://crazy-kittens.s3-website-us-east-1.amazonaws.com/ is both difficult for your website users to remember, and if you ever want to move your website out of an S3 bucket, you’ll need to come up with a new name, which is sad.
  • An Amazon Web Services (AWS) account.
  • The AWS CLI. Again, you don’t strictly need this, but all the steps here are going to use it. If you really hate the command-line, you can probably follow along using the AWS Console. Just adapt the steps I’ve written here for console use (or follow the official documentation).
  • Configure the CLI using your AWS credentials. Make sure to set an AWS region, and remember where it is. Your website can be accessed most quickly in the region you choose, so choose carefully!

Setting up an S3 bucket to host a static website

Create an s3 bucket

First, you’ll need to create a bucket for your website and set it up to host a static website.

Note

A static website is one that doesn’t require any server-side processing. If you requiree a full-blown blog engine like WordPress or use some other software to serve your website (This site previously ran on DokuWiki), you won’t be able to serve it using S3.

I recommend using a bucket that’s named after your website (if you use Route53 to route traffic, you’ll need to do this anyway). Here’s how:

aws s3 mb s3://www.my-domain-name.com

That’s an example value. Use your own domain name in place of my-domain-name, or choose some suitably unique name.

Give your website some content

Next, provide some content for your bucket. To begin, you might just want to create a simple page and upload it to the bucket. Here’s a good test page:

<html>
    <body>
        <h1>Hello, My Awesomely Static Website!</h2>
    </body>
</html>

Just type (or cut/paste) it into a file called index.html and then send it to your bucket like this:

aws s3 cp --acl public-read index.html s3://www.my-domain-name.com

The --acl public-read option makes sure that all the files in my website can be accessed by anyone. By default, S3 copies files privately, so only you have permission to view the files you’ve copied. While it’s sort of cool to have a website that only you can view, it’s also a bit lonely.

Set up your bucket as a website

Now you can set up your bucket as a website by giving it a website configuration:

aws s3 website s3://www.my-domain-name.com --index-document index.html

That’s all it takes. Amazon S3 gives your website a URL such as http://www.my-domain-name.com.s3-website-us-west-2.amazonaws.com, where the bit before s3-website is your bucket name, and us-west-2 is the region that you created the bucket in.

Note

By default, the AWS CLI uses us-west-2 as the default region. If you didn’t set a region when setting up your AWS CLI configuration, that’s where you’ll find it.

I highly recommend using a region that’s close to you geographically! You can find a list of AWS regions and endpoints for S3 on the AWS Regions and Endpoints page.

If you’ve followed all the steps so far, type the URL of your website in your web browser’s address bar, and take a look at your site!

_images/awesomely-static-website.png

Setting up Route53 to route traffic to your website

You can either use your own domain registrar (if they support setting DNS records for your domain) or you can use Amazon Route53 to do it. I’m going to assume you’re starting from scratch and will be setting up your domain DNS using Route53.

If you have a registrar that provides its own DNS server, you can skip ahead to Add resource records to point to your S3 website, though you won’t be using the AWS CLI to set up resource records that point to your domain. Use the method that your registrar provides.

Set up a hosted zone

Before you can add DNS records that route domain traffic to your website, you will need to create a Route53 hosted zone.

To create a hosted zone using the AWS CLI, type:

aws route53 create-hosted-zone --name my-domain-name.com. --caller-reference "some unique string"

Use your own domain name in place of my-domain-name.com. The argument to --caller-reference can be any short string that uniquely identifies the request.

To create resource records in your hosted zone, you’ll need to get its AWS ID. This is a unique text string that identifies your hosted zone. You can get the ID by using the route53 list-hosted-zones command:

aws route53 list-hosted-zones

This will typically output a JSON structure that lists any hosted zones you’ve created, along with their configuration values and an “Id” attribute, which looks somewhat like this:

{
    "Name": "my-domain-name.com.",
    "Id": "/hostedzone/EXAMPLE00000ID"
}

The part after “/hostedzone/” in the returned Id value is your hosted zone ID. In this example, it’s “EXAMPLE00000ID”. Take note of your own hosted zone ID. You’ll use it in the next section.

Add resource records to point to your S3 website

To route traffic to your S3 website, you’ll need to create an Alias (A) resource record that points to your S3 bucket when an internet user tries to access your website.

Creating (or updating) a resource record set for a hosted zone with the AWS CLI requires that you provide a JSON-formatted file that describes the changes that you want to make to your hosted zone.

The AWS CLI can create a “skeleton” file for you to edit, using the following command:

aws route53 change-resource-record-sets >hosted-zone-config.json

The file hosted-zone-config.json file will contain a blank JSON template that you can fill in.

To create an alias record that directs traffic from your website address to your S3 bucket, open the file and edit the following values within it, replacing them with the values specific to your website.

{
    "Changes": [
        {
            "Action": "CREATE",
            "ResourceRecordSet": {
                "AliasTarget": {
                    "HostedZoneId": "EXAMPLE00000ID",
                    "DNSName": "s3-website-us-west-2.amazonaws.com.",
                    "EvaluateTargetHealth": false
                },
                "Name": "www.my-domain.com",
                "Type": "A"
            }
        }
    ],
    "Comment": "Creating an alias for www.my-domain.com",
}

Important

Set the DNSName field with only the domain portion of the S3 URL used to access the site. Amazon Route53 assumes that the address will be the same as the value of the Name field.

Now, you can create your alias record using the following command:

aws route53 change-resource-record-sets --hosted-zone-id EXAMPLE00000ID \
--change-batch file://hosted-zone-config.json

Assuming that you’ve also configured Amazon Route53 as your name server, you should now be able to access your static S3 site using the web URL of your domain (http://www.my-domain.com in this example).

Publishing the website

I use the AWS CLI to publish my website, since I can do it with a single command, it’s fast, and it automatically takes care of things like files that I’ve removed/renamed.

Let me explain the command that I showed at the beginning of this page:

aws s3 sync --delete --acl public-read build/html/ s3://www.my-domain-name.com

Although I could use s3 copy --recursive` here, I prefer the s3 sync command because it:

  • Transfers only the changed/new files. This makes updating my website very fast.
  • Automatically handles (using the --delete switch) removing files from the server that no longer exist in your website (in other words, its no problem if you remove/rename a file, move things around, change your .css or .js files or fonts, or any other such changes).
  • The website I test on my machine is the same one that will be shown on the web.

The path build/html represents the path where your website content lives. Use the actual path to your own website files.

Again, I use --acl public-read to make sure that my pages are visible to the general public.

The final argument is the S3 bucket to sync the files to. Use your own domain/bucket name here.

Note

the s3 sync command has many other uses, and is also featured in file archival using glacier.

For more information

The Amazon S3 documentation has much more information about setting up an S3 website than I’ve explained here. If you’re hungry for more information, go ahead and see Hosting a Static Website on Amazon S3 for more information.

The Amazon Route53 documentation is a great resource for discovering what services Route53 provides and how to navigate the murky waters of setting up a correct DNS configuration. The section Configuring DNS to Route Traffic will shed light on the murky waters I’ve touched upon in this article.