Zero to HTTP/2 with AWS and Hugo

A step-by-step guide to building your own hacker blog.

6 minutes read

Those who subscribe to Node Weekly may have seen a post in early 2017 from Ivan Jovanovic titled Running Express, Koa And Hapi On HTTP/2. In his post Ivan gives a brief overview of the new HTTP protocol and describes some of the HTTP/2 key advantages, such as speed.

Ivan goes on to share code snippets for implementing HTTP/2 in several popular Node-based web servers, something JS developers (especially fans of JSPM) might enjoy, but entirely unnecessary if you’re using CloudFront—which announced HTTP/2 support in September 2016—to serve static websites like those generated with Hugo.

In this post you will learn how to go from Zero to HTTP/2 with AWS and Hugo, the fastest static site generator in existence.

And here’s what your blog will look like, save for theme advancements and your personal customizations (click to view live example):

After Dark theme for Hugo screenshot

When you’re ready to get your hands dirty, continue on for the full set of step-by-step instructions on how to go from Zero to HTTP/2 with AWS and Hugo.

Get started with AWS and Hugo

First, create an AWS account. If this is your first time using AWS you will benefit from a free year of service (after that it’s cheaper than Digital Ocean). If you already have an AWS account, proceed to the next step.

Next, install After Dark, a hacker theme I created for Hugo. The instructions assume you’re using macOS, though other platforms are supported as well.

Install s3_website

s3_website is a RubyGem utilizing the AWS-CLI that can be used to automatically configure your website on AWS, and deploy it to CloudFront in a matter of seconds from your local machine. See the README for installation and usage instructions.

Note: Be sure you install version 3.0.0 or better to take advantage of the HTTP/2 configuration settings for CloudFront distributions.

Configure s3_website

If you followed the instructions, you should now have a S3 bucket for your website, automatically created or updated by s3_website, with your After Dark site deployed. If you really followed the instructions you will also have a CloudFront distribution configured to use HTTP/2, all wired up to your S3 bucket and ready to go.

Here’s what my current configuration looks like for Hack Cabin, which also uses After Dark:

s3_id: <%= ENV['S3_ACCESS_KEY_ID'] %>
s3_secret: <%= ENV['S3_SECRET_KEY'] %>

site: public

index_document: index.html
error_document: 404.html

  "videos/*": 2629000
  "js/*": 2629000
  "*": 300

  - .html
  - .mp4
  - .xml

s3_reduced_redundancy: true

cloudfront_distribution_id: <%= ENV['CLOUDFRONT_DISTRIBUTION_ID'] %>

    min_ttl: <%= 60 * 60 * 24 %>
  http_version: http2
    quantity: 1

And here’s an example .env file to accompany it:


You’re done! Well, almost…

Sites served over CloudFront allow HTTPS by default, meaning you do not have to do anything to enjoy SSL. However, if you’re using a custom domain (which you can purchase starting at $12 per year via Route 53 in the AWS Console) you need to do a little more work.

Configure HTTPS on a custom domain

This part requires some manual work in the AWS Console, but nothing too extravagant. And though some may encourage you to Setup Let’s Encrypt SSL Certificate on Amazon CloudFront it has been my personal experience using the AWS Certificate Manager is much easier to manage over time.

To obtain a custom SSL certificate using the Certificate Manager you need to configure SES to receive email.

Configure SES to receive email

The reason this is needed is because the certificate authority must be able to verify you own your domain name. I’ve linked to instructions on how to do this in my post titled Serverless Email with SES and Lambda.

Note: Skip the majority of the instructions you see and focus only on receiving email with SES.

Once you’ve finished you will have a new S3 bucket capable of receiving emails at your custom domain and can now request a custom SSL cert using the Certificate Manager.

Request Certificate using Certificate Manager

First, access Certificate Manager from the AWS Console and choose Request a certificate. Then enter the domain name or names for which you’d like to request a certificate for, e.g.:

  • *

Form there choose Review and request followed by Confirm and request. This will kick off several verification emails to SES, which will store them in the related S3 bucket set-up in the last step.

Confirm Certificate Request

To confirm the request of the SSL Certificate open the S3 Bucket collecting emails, open one of the emails received at the time of the request, and look for the verification URL. Copy and paste the verification URL into a browser and navigate to the page to verify domain ownership.

You can watch the status of the verification from the Certificate Manager. If too much time elapses and the request is not verified the certificate request will become invalid and you will need to re-request.

Configure CloudFront

Now that you’ve successfully obtained your SSL certificate it’s time to hook it up to your CloudFront distribution. This is also a good time to enable HTTPS by default.

To use your custom cert do:

  1. Navigate to CloudFront in the AWS Console and choose your distribution.
  2. Choose Edit from the General tab and select Custom SSL certificate.
  3. Select the certificate you just created from the selection dropdown.
  4. Scroll to the bottom of the page and choose Yes, Edit.

To enable HTTPS by default do:

  1. Navigate to CloudFront in the AWS Console and choose your distribution.
  2. Navigate to the Behaviors tab, select the “Default” behavior and choose Edit.
  3. Under Viewer Protocol Policy choose Redirect HTTP to HTTPS
  4. Scroll to the bottom of hte page and choose Yes, Edit.

Appreciate your hard work

Navigate to your website’s custom domain name and ensure it is being served over HTTPS. Verify the HTTP to HTTPS redirection is working as expected by entering a URL starting with HTTP (it should 301 to HTTPS). And, finally, use HTTP/2 Test Tool to verify HTTP/2 is functioning as expected.

HTTP/2 Test Proof

That’s it. You’re finished. This time for real.

You’ve just gone from Zero to HTTP/2 with AWS and Hugo. Please feel free to share your success stories or battle cries in the comments section below.


PageSpeed benchmarks assume you are not putting images above the fold or using JavaScript widgets like Google Analytics, which will immediately start to decrease your scores.

Mobile interactive pages measured using WebPageTest taking median of RUM First Paint of First View Only metric from San Jose (0.506s), Manchester (0.694s), Buenos Aires (0.940s), Singapore (0.585s) and Japan (1.110s) at mobile LTE connection speed (12 Mbps/12 Mbps 70ms RTT) on the Chrome browser.

Page generation speed measured in Feb ‘17 with Hugo v0.18 on a MacBook Pro with 2.5 GHz Intel Core i7 with 500GB Flash Storage running macOS Sierra (10.12.3) using the content from

Leave a Comment