High Performance Website with AWS, Hugo & Terraform

In this tutorial I want to describe how to create a high performance static website which fulfills the following requirements:

To achieve this goal my research end up with the following providers / toolchain:

tl;dr for Terraform (& Hugo) experienced people

If you already experienced with Terraform and static CMS, you can straight jump to the Boilerplate Code:

Static CMS: Hugo

Hugo is a lightweight and fast static Content-Management-System written in Go/Golang.

Content can be created in Markdown or directly in HTML. Also lot of lightweight Themes are available.

Infrastructure Provider: Amazon AWS

Fot the whole infrastructure i choose AWS. With most of the used Services i have at least some experience. Furthermore is AWS perfectly supported by Terraform and, if necessary more dynamic serverless functionality can be added easily (e.g. AWS Lambda).

With the target of 100% “Serverless Infrastructure” we reduce our AWS cost to a minimum of some few $ per month.

Infrastructure contains:

Infrastructure as Code: Terraform

We want to build our whole infrastructure as code (IoC).

The biggest benefit of IaC is code is that you can easily rollback to previous version of your Infrastructure because your code can be committed into a Version Control System (e.g. Git). No more any heart attacks while “clicking server configurations”

Besides AWS Cloudformation Terraform by HashiCorp gets more and more popular as IoC Software. Terraform Code use its own syntax, named HashiCorp Configuration Language (HCL)

Benefits of Terraform for example:

  • Cloud agnostic (AWS, Azure, Google Cloud..)
  • Declarative, not procedural code
  • Client-only architecture
  • Module paradigm

Here you find a good Terraform vs. CloudFormation comparison

Infrastructure Overview

Overview Infrastructure

Step by Step Tutorial


AWS Account: AWS Signup

Git: How to install Git

Terraform: Download Terraform

Hugo Install Hugo


While creating our Infrastructure we need to validate our ownership of the Domain to create a SSL Certificate. For this make sure you are able to receive E-Mails at least for one of the following adresses:

  • admin@example.com
  • administrator@example.com
  • postmaster@example.com
  • hostmaster@example.com
  • webmaster@example.com

Checkup before we start:

Create our Infrastructure

Create AWS Admin Account

For terraform we need to create an Admin Account in AWS IAM Service (User, Permission, Role Management).

Go to: https://console.aws.amazon.com/iam/home?region=us-east-1#/users

  • Click add User
  • Type in a User name, e.g. tf-admin, check Programmatic Access, click next
  • Select Attach existing policies directly and check AdministratorAccess, click next
  • click next, click Create user

Download / Write down your Access and Secret

Start with Boilerplate

Clone the Boilerplate Repo locally:


# git clone https://github.com/dannylinden/high-performance-seo-website

Edit the config vaiables in inf-code/terraform.tfvars:

/* AWS Access Key for Admin Account */
aws_access_key  = ""

/* AWS Secret Key for Admin Account */
aws_secret_key  = ""

/* Your Domain e.g. www.example.com */
www_domain   = "www.example.com"

/* Your root Domain e.g. example.com */
root_domain = "example.com"

/* Path to your public SSH Key for the Git Repository */
ssh_pub_key = "~/.ssh/id_rsa-pub"

If you dont know how to create a SSH Key, follow this tutorial: https://confluence.atlassian.com/bitbucketserver/creating-ssh-keys-776639788.html

Create Infrastructure

Open your terminal, move to the inf-code folder, initialize, plan and apply your Terraform Code:

# cd inf-code
# terraform init
# terraform plan
# terraform apply

Terraform will show what infrastructure will created, and we need to approve these chnages with yes

While creating the infrastructure we receive an E-Mail to validate our Domain-Ownership to create an SSL Certificate:

After executing the output will look like this:

Apply complete! Resources: 25 added, 0 changed, 0 destroyed.


git_remote_url = ssh://APKAIX5XFMNUAMMXXD4A@git-codecommit.eu-central-1.amazonaws.com/v1/repos/www.lindendanny.de
nameservers = [

Change git remote URL

The first output is shows the git remote url of our newly created and empty git repository. To submit our code into it we need to change the remote URL to the new one:

# git remote set-url origin ssh://APKAIX5XFMNUAMMXXD4A@git-codecommit.eu-central-1.amazonaws.com/v1/repos/www.lindendanny.de

Update Namesever

The second output variable is a list of four nameservers for our domain. We need to update these at our Domainprovider.

You get infos how to do this from your Domain providers Help-Center / FAQ / Support.


You need to change the Namesever (NS Entry) of your Domain, not the A Records! A Records are already handled by AWS Route 53.

Check if infrastructure works:

Now we can push our code to the AWS Git Repository:

# git push

Output look like this:

Counting objects: 13, done.
Delta compression using up to 4 threads.
Compressing objects: 100% (11/11), done.
Writing objects: 100% (13/13), 2.73 KiB | 2.73 MiB/s, done.
Total 13 (delta 1), reused 13 (delta 1)
To ssh://git-codecommit.eu-central-1.amazonaws.com/v1/repos/www.lindendanny.de
 * [new branch]      master -> master

If we open our Website https://www.example.com we should see something similiar:

The reson is that AWS Cloudfront tries to read the index.html or 404.html from the S3 Bucket but both didn’t exist.

Create our first Hugo site

Our Infrastructure is now up & running. Next we create our first Hugo website following the https://gohugo.io/getting-started/quick-start/ tutorial:

  • First we add a Theme, and put it into the config (config.toml)

Open the console and move to the git repository:

# hugo new site website-code
# git clone https://github.com/budparr/gohugo-theme-ananke.git website-code/themes/ananke
# cd website-code
# rm -rf themes/ananke/.git
# echo 'theme = "ananke"' >> config.toml
  • Lets create a new Page/Content
# hugo new posts/my-first-post.md
  • Edit the newly created content file if you want. Now, start the Hugo server with drafts enabled:
# hugo server -D

Now we can see our new website locally at http://localhost:1313/

To make our content also in Production available we need to change the draft parameter and add some content in content/posts/my-first-post.md:

title: "My First Post"
date: 2019-01-02T19:00:33+01:00
draft: false

Yeahhhhh, Hello World 👋

Also update the config.toml in a text editor:

baseURL = "https://example.org/"
languageCode = "en-us"
title = "My New Hugo Site"
theme = "ananke"

Now we can add, commit & push these changes to our remote git repository:

# git add .
# git commit -m 'My first Website commit'
# git push

The output look similar:

Counting objects: 6, done.
Delta compression using up to 4 threads.
Compressing objects: 100% (4/4), done.
Writing objects: 100% (6/6), 563 bytes | 563.00 KiB/s, done.
Total 6 (delta 1), reused 0 (delta 0)
To ssh://git-codecommit.eu-central-1.amazonaws.com/v1/repos/www.lindendanny.de
   f3e0345..4c0137a  master -> master

We can now move to our Pipeline on the AWS GUI and watch the Build process: https://eu-central-1.console.aws.amazon.com/codesuite/codepipeline/pipelines?region=eu-central-1

After some minutes all should be green:


Your website should now up and running on https://www.example.com



My research for this tutorial starts here: https://medium.com/runatlantis/hosting-our-static-site-over-ssl-with-s3-acm-cloudfront-and-terraform-513b799aec0f

comments powered by Disqus