20 September 2020

Hosting a Jekyll Static Website from an AWS S3 Bucket, Pt. 1

by egfraz

Websites can run the full gamut of complexity: from vast, distributed applications to a simple web presence of a view pages. Larger applications have many processes working under the hood and can consume enough resources to warrant a full (or many) server. However if you just want a few pages for a portfolio or a company basic site, static site generators can create the flat resources you need to serve out of alternative resource like an AWS Simple Storage Service (S3) bucket. This series of posts covers the process of creating a Jekyll static site and uploading it to and AWS S3 bucket for public access over the Internet.

What is Jekyll?

Simply put, Jekyll is a Ruby package (called a Gem) for taking content you write in Markdown, and creating web pages by dynamically injecting your content into HTML/CSS templates.

What is AWS S3?

AWS Simple Storage Service (S3) is a cloud platform service for remote storage accessible over the Internet, but it also has an additional feature for website hosting. It does not allow for connecting to backend databases or services, so a dynamic site like WordPress would not be a good fit, but it can serve static HTML and CSS files without issue. So the overall goal is to set up a workflow where you:

  1. Add content to your site as Markdown (local)
  2. Use Jekyll to your content compile into HTML/CSS (local)
  3. Upload the site to the S3 bucket for hosting (remote)

This blog series is divided into the following sections to get you up and running:

  1. Create your AWS Infrastructure
  2. Create your local development environment
  3. Create your content and compile the site code
  4. Deploy the site

Create your AWS Infrastructure

As noted above, AWS S3 is the core component for this site, but there are other services that are involved as well. The full list of services you will be working with are:


If you already have an IAM user set up for your AWS account, then you can skip this section (if you run into permission issues with completing the rest of this tutorial, adjust the permissions on the user). However, if you are still logging in with the root user you created when you were signed up for the AWS account (where your username is your email address), then you should create a separate IAM user. This is a security best practice (working with least privilege). For simplicity, AWS has a preset permission policy called AdministratorAccess that you can apply to the user. This will allow you work with all AWS services and resources, but if the IAM user credentials are compromised, the attacker will not have access to account-level billing information. Directios on creating an IAM user are found here.


The Domain Name System (DNS) is a topic that could take up an entire post itself, but for the purposes of this specific task you just need to know that it is the mechanism by which a request for a specific domain name is routed to a specific network resource (web server, S3 bucket, etc.). Put another way your domain name is the phone number, DNS is a telephone directory and your website is a speciifc phone in your house. AWS’s Route53 is a service for registering domain names and managing DNS.

Log into your AWS console and click the Services button in the upper right hand corner. Search for and click Route53. If you do not have a registered domain name, you can start the process of purchasing one. If you usually register domains from another provider, you would just need to follow the instructions for that provider, then return to your AWS console when the domain registration is ready. Then go to the “Hosted Zones” section of the Route53 service in the AWS console. Create a new hosted zone for your domain. By default the zone file will generate with two records already in place, an NS (Nameserver) record and a SOA (Start of Authority) record.

The SOA record contains information about the zone itself including the name of its primary nameserver, who has authority over the zone, how long before other nameservers should query it, etc. Under most hosting/domain transfer scenarios you should not have to edit this record. It is just there to present information to other DNS system entities.

The NS records are the ones of interest. These are also not records that you will need to edit, but you will need to copy the four nameserver hostnames in the record and provide them to your domain registrar (assuming the domain is registered somewhere other than AWS). There is usually a form field in a domian registrar’s admin section where you can just paste this information in.

Once you have the zone file successfully created, we will leave Route53 for a little bit to create the actual S3 bucket from which the site will be served. Once that is configured, you will come back here to create the record that will actually point your domain to the bucket.


Now that you have set up proper access to your AWS account and laid the routing groundwork with Route53, now you will create the actual bucket.

Using the Services search in the upper right hand corner, search for and click on S3. Once in the S3 service console click “Create Bucket”. A wizard will open up and take you through a few pages of options, but the ones that matter for this project are:

As you may have noticed, we set the bucket to be publicly accessible. Without this, when someone on the Internet uses their browser client to request the contents of your site, they will get a permission denied error. Since everything in the bucket will be public, the code you publish there should not have any sensitive information in it.

Now that you have created the bucket and given it correct permissions, we need to enable the feature that will allow it to serve a website. From the S3 service console, click on your new bucket. Then click on the properties tab and look for “Static Website Hosting.” Enable this feature with the option “Use this bucket to host a website.” For “Index document” type in “index.html.” That way, S3 knows that if an index.html exists in the root of the bucket, serve that page when a browser client requests the website root. At the top of that settings page there is an endpoint URL. You can use this to view the bucket site before you point your domain’s DNS to it. Save that URL for later.

Go back to the Overview tab of the bucket. Create a text file on your local computer called “index.html.” Put whatever text you want in it (it is just to test that the system works) and upload the file to your bucket. In the permissions section of the wizard that pops up, look for the setting “Manage public permissions” and set this to “Grant public read access to this object.” The rest of the settings you can leave as default.

Now load the bucket website endpoint URL in a separate tab and you should see the index file text being served from the S3 bucket. Once you have confirmed that, go back to Route53 and load the zone file for your domain. You will create a new record with the following settings:

Within five minutes you should be able to load your domain and see the contents of the index.html file. Congratulations! Your site is now live.

The next post will cover setting up a development environment for Jekyll, the static site generator that dynamically creates HTML/CSS/JS files that you can upload to your S3 bucket.