Evan X. Merz

musician / technologist / human being

Tagged "aws"

How to host a static site on AWS

In this post, I'm going to show you how you can put up a simple html webpage on AWS using resources that are usually free. It's probably the cheapest way to set up a website.

Prerequisites

There are a few things you need to do ahead of time.

  1. Sign up for AWS
  2. Create a webpage

For the first one, head on over to https://aws.amazon.com/console/ and create a new account.

For the second one, you will probably need to learn a little coding to make it happen, but I'll give you something simple to start with.

<!DOCTYPE html>
<html>
  <head>
    <title>My Webpage</title>
  </head>
  <body>
    <main>
      <h1>My Webpage</h1>
      <p>
        This is a simple html webpage hosted on AWS S3 and AWS Cloudfront.
      </p>
      <p>
        This was built based on <a href="https://evanxmerz.com/post/how-to-host-a-static-site-on-aws" target="_blank">a tutorial at evanxmerz.com/post/how-to-host-a-static-site-on-aws</a>.
      </p>
    </main>
  </body>
</html>

There are some optional prerequisites that I'm intentionally omitting here. If you want to host your site on your own domain, then you'll need to purchase that domain from a domain registrar, such as AWS Route 53. Then you would also need to get an SSL certificate from a certificate authority such as AWS Certificate Manager.

Create a public S3 bucket

For your site to exist on the internet, it must be served by a computer connected to the internet. To make this possible, we need to upload your html file to "the cloud" somehow. Don't worry, "the cloud" is simply a marketing term for a web server. In this tutorial, our cloud storage service is AWS S3.

First you need to create a bucket.

  1. Browse to the AWS S3 service
  2. Click "Create Bucket". A bucket is a container for files. You might use a different bucket for each of your websites.
  3. Enter a name for your bucket. I name my static site buckets after the site they represent. So empressblog.org is in a bucket called empressblog-org. I named my bucket for this tutorial "static-site-tutorial-1-evanxmerz-com" because I am going to connect it to static-site-tutrial-1.evanxmerz.com.
  4. Next, select the AWS region for your bucket. The region is not really important, but you must write down what you select, because you will need it later. I selected "us-west-1".
  5. Under "Object Ownership" select "ACLs enabled". This will make it easier for us to make this bucket public.
  6. Under "Block Public Access settings for this bucket", unselect "Block all public access", then click the checkbox to acknowledge that you are making the contents of this bucket public.
  7. Then scroll to the bottom and click "Create Bucket".

Next, you need to allow hosting a public website from your bucket.

  1. Locate your bucket in the bucket list in S3, then click it.
  2. You should now be looking at the details for your bucket. Click the "Properties" tab, then scroll down ti "Block all public access" and click "Edit".
  3. Click "Enable", then under "Index document", enter "index.html". Then click "Save changes".
  4. Click the "Permissions" tab for your bucket. Scroll down to "Access control list (ACL)" and click "Edit". Next to "Everyone (public access)", click the box that says "Read". Then click the box that says "I understand the effects of these changes on my objects and buckets" and click "Save changes".

Create your index page

This step assumes that you have already created an html page that you want to make public. You can also upload other pages, css files, and javascript, using this same procedure.

  1. Find the "Objects" tab for your bucket on S3.
  2. Click "Upload".
  3. Click "Add files".
  4. Browse to your index.html
  5. Scroll down to the "Permissions" accordion and expand it.
  6. Click "Grant public-read access" and the checkbox to say that you understand the risk.
  7. Then click "Upload".

Now your page is on the internet. You can go to the objects tab for your bucket, then click on your file. That should display a link called "Object URL". If you click that link, then you should see your page. My link is https://static-site-tutorial-1-evanxmerz-com.s3.us-west-1.amazonaws.com/index.html.

Why to make a CloudFront distribution

Now you have seen your file on the web. Isn't that enough? Isn't this tutorial over? No. There are several problems with using S3 alone.

  1. Your files will be served from S3, which is not optimized for worldwide distribution. Your files have a home on a server in the region you selected. If that region is in the US, then people in Asia are going to have a much slower download experience.
  2. Your site will not work if there are errors. Your index page works fine, but what happens if you entered an incorrect link, and someone ends up at indec.html? You will get a nasty error message from AWS, rather than being redirected to a page on your site.

The final problem is the URL. This can be solved by setting up a domain in Route 53, but it's much wiser to set up a CloudFront distribution, then connect your domain to that.

Set up a CloudFront distribution

AWS CloudFront is a Ccontent Distribution Network (CDN). A CDN is a network of servers all over the world that are close to where people live. So people in Asia will be served by a copy of your page on a server in Asia.

  1. Find the CloudFront service on AWS.
  2. Click "Create distribution".
  3. In the "Origin domain" field you must enter your S3 bucket's Static Website Hosting Endpoint as the CloudFront origin. You can find this on the "Properties" tab of your S3 bucket. So for me, that was "static-site-tutorial-1-evanxmerz-com.s3-website-us-west-1.amazonaws.com".
  4. Then scroll all the way down to "Alternate domain name (CNAME)". This is where you would enter a custom domain that you purchased from AWS Route 53 or another registrar. For instance, if you want to set up your site on mystore.com, then you would enter "*.mystore.com" and "mystore.com" as custom domains. I entered "static-site-tutorial-1.evanxmerz.com" as my custom domain because that's where I'm putting up this tutorial.
  5. Then go to the "Custom SSL certificate" field. If you do not have your own domain, then you can ignore this. But if you have your own domain, then you will need your own SSL certificate. The SSL certificate is what enables private web browsing using the "https" protocol. Go set up a certificate using AWS Certificate Manager before setting up CloudFront if you want to use a custom domain.
  6. Finally, click "Create distribution"

Then you need to modify the distribution to act more like a normal web server. So we will redirect users to index.html if they request an invalid url.

  1. Find your distribution on CloudFron and click it.
  2. Click the "Error pages" tab.
  3. Click "Create custom error response".
  4. Under "HTTP error code" select "400: Bad Request".
  5. Under "Customize error response" click "Yes".
  6. Under "Response page path" enter "/index.html".
  7. Under "HTTP Response code" select "200: OK".
  8. Click "Create custom error response".
  9. Repeat these steps for 403 and 404 errors.

Then, if you have a custom domain, you need to go to AWS Route 53 and enable it.

  1. Go to Route 53 and select the hosted zone for your domain.
  2. Click "Create record".
  3. Create an A record for your domain or subdomain.
  4. Under "Route traffic to" click "Alias".
  5. Click "Alias to CloudFront distribution" and select your distribution.
  6. Click "Create records".

Now if you visit your custom domain, you should see your page. Here's mine: https://static-site-tutorial-1.evanxmerz.com/

Congratulations!

Congratulations! You've erected your first website using AWS S3 and AWS CLoudFront! Let's review the basic architecture here.

  1. Files are stored in a cloud file system called AWS S3.
  2. Files are served by a Content Distribution Network (CDN) called AWS CloudFront.
  3. Optionally, domains are routed to your CloudFront distribution by AWS Route 53.
  4. Optionally, CloudFront uses an SSL certificate from AWS Certificate Manager.

This is about the simplest and cheapest architecture for hosting a fast static site on the internet.

It's important to note that this is also the simplest way for hosting ANY static site. If you generated a static site using React, Gatsby, or Next, then you could host them in the same way.

IT's also important to note that this architecture fails as soon as you need to make decisions server side. This architecture works fine for websites that are frontend only websites, where you don't interact with private data. Once you need private data storage, an API, or custom logic on a page, then you will need a server in some variety. There are multiple solutions in that case, from the so-called "serverless" AWS Lambda, or the more old-fashioned AWS EC2, which is simply a server farm.

But you are now ready to start exploring those more complex options.

Why to stick with Heroku, or make the switch

One question I hear a lot lately is when a company should stick with Heroku or switch to something else. In this article I'm going to lay out the pros and cons for Heroku, and compare it with the typical alternative, AWS.

Three reasons to stick with Heroku

Don't fall victim to thinking that "the grass is always greener on the other side." That hot new technology on AWS or Azure may look cool now, but Heroku offers a lot of great features that should fit the bill for many growing companies.

Heroku supports easy scaling with sticky sessions

Horizontally scaling any web application is hard. In a traditional web app, you must optimize your code so that it runs in parallel. You must deal with race conditions that arise when multiple servers are trying to interact with a shared resource such as a cache or a database. You must find a way to balance load across multiple servers while sharing state across all instances.

Session data is visitor-specific data that is stored on the server. If a visitors's session is stored on one server, but their request is routed to another server, then that server won't know about anything they've done in the current session. It may not know if they're logged in or not. It may not have the browsing filters that they've configured.

Session affinity, also known as sticky sessions, is one solution to the problem of sharing session across servers. With session affinity enabled, all of a visitor's requests will always be routed to the same instance. There are some drawbacks to session affinity, but the benefit of being able to scale horizontally before having to tackle some parallelization problems may outweigh the drawbacks in your use case.

Many services offer session affinity, but none are as easy to set up as Heroku. With literally two clicks you can enable session affinity and start scaling out. Don't let hype distract you from an approach that may reap benefits for your web property.

Heroku provides zero down time deploys and upgrades

One of the best features of Heroku is that their technology and support teams handle deploys and upgrades. They make it so that your dev team doesn't have to worry about keeping the servers up during deploys or running migrations during upgrades.

The preboot feature allows you to keep the old version of your app running during a deploy. This means that users will only ever be routed to a server that has booted up and is running your app, and that means that you aren't turning away customers in that 30 second window where the new version of your app is loading.

Heroku also supports seamless upgrades for the most popular add-ons, such as REDIS. When I switched my company from Heroku REDIS to AWS REDIS we were surprised that our site went down a few weeks after the switch. AWS may force upgrade your technology without providing a way to seamlessly switch to the new version. So AWS forces you to track each upcoming patch and ensure that your team is ready for the switch.

Heroku is cheaper than the alternative because anyone can use it

Heroku seems very expensive when the bills come due, but in my experience it's cheaper than the alternative. Heroku is so easy to use that anyone can use it. With a few clicks or commands a backend developer can enable sticky sessions. With a few clicks or commands they can enable preboot. With a few clicks or commands they can add REDIS or PostGreSQL or any of the many add-ons provided by Heroku.

To use all those different products on a less managed product, such as AWS or Azure, you must retain a dedicated DevOps specialist. These people have very specialized skills and are not cheap. In my experience, using Heroku saves the cost of around one expensive employee. So as long as your Heroku bill is less than the cost of one employee, it's probably the more affordable option.

Three reasons to switch

There are many good reasons to stick with Heroku, but it certainly has limits. Here are the reasons why I've moved services from Heroku to somewhere else in the past.

Heroku is dangerous because anyone can use it

When you're on Heroku, you may not need to hire dedicated staff to manage your web infrastructure. This is a significant cost savings, but it means that the DevOps tasks are going to be offloaded on your web programmers. So you must ensure that you hire the skills on your team to understand Heroku. Heroku may not be as complex as AWS, but it still requires a foundational understanding of how the web works, linux, and logging. If your programmers are exploring the features in Heroku without the requisite experience or training then they may make mistakes that harm your business.

Heroku offers fewer options for international support

Heroku lacks flexible support for internationalized websites. As it says in the regions documentation, each "Private Space exists in a single region, and all applications in the Private Space run in that region.". This may sound confusing, but it ultimately means that each project in Heroku can only run in one region. If you want to support another region, then it must be in a separate project and hosted at a separate domain or subdomain. So if you want to internationalize your website using subdirectories, which is advantageous because it inherits the existing search reputation of your domain, then you can't do that with geographically distributed servers on Heroku.

Heroku offers fewer vertical scaling options

Heroku dynos come in six different flavors as of this writing. If you need anything outside of those six options then you are out of luck. The beefiest dyno is the performance-l machine, which offers 14Gb of RAM. If you need more than that, then you need to switch to another platform. What if you're using very little memory, but you want to use many CPU cores? The only option is to pay for the most expensive dynos. This lack of flexibility means that if your web service is a pretty standard website or API, then Heroku probably won't serve your needs very well.

How to decide whether to stick with Heroku or to switch

In this article I've listed some reasons to stick with Heroku and some reasons to switch, but the final decision is largely dependent on your use case. If you are making a pretty standard website or API, then Heroku is probably fine even when horizontally scaling. There are three main scenarios where you should strongly consider switching to a more complex cloud hosting service.

  1. Your service need more flexible options for internationalization
  2. Your service doesn't match the requirements common to most web apps and APIs
  3. Your service is scaling exponentially