########################################### Publishing a Static Website Using Amazon S3 ########################################### *This website* is written in reStructuredText_, rendered to HTML using Sphinx_, and then published into an |s3| bucket with a command-line script. Here are the steps I use to rebuild and publish my website: .. code-block:: sh # 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: |S3|_ and Route53_. I use the |awscli|_ 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 |awscli|_. 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 |awsconsole|_. Just adapt the steps I've written here for console use (or follow the :ref:`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: .. code-block:: sh 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: .. code-block:: html

Hello, My Awesomely Static Website!

Just type (or cut/paste) it into a file called :file:`index.html` and then send it to your bucket like this: .. code-block:: sh 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*: .. code-block:: sh aws s3 website s3://www.my-domain-name.com --index-document index.html That's all it takes. |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 |awscli| uses **us-west-2** as the default region. If you didn't set a region when setting up your |awscli| 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! .. image:: 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 |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 :ref:`publish-s3-resource-records`, though you won't be using the |awscli| 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 |awscli|, type: .. code-block:: sh 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: .. code-block:: sh 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: .. code-block:: json { "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. .. _publish-s3-resource-records: 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 |awscli| requires that you provide a JSON-formatted file that describes the changes that you want to make to your hosted zone. The |awscli| can create a "skeleton" file for you to edit, using the following command: .. code-block:: sh aws route53 change-resource-record-sets >hosted-zone-config.json The file :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. .. code-block:: json { "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. |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: .. code-block:: sh 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: .. code-block:: sh aws s3 sync --delete --acl public-read build/html/ s3://www.my-domain-name.com Although I could use :command:`s3 copy --recursive`` here, I prefer the :command:`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 :command:`s3 sync` command has many other uses, and is also featured in :doc:`file archival using glacier `. .. _publish-s3-more-info: 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.