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.
- Infos about Hugo: https://gohugo.io
- Quickstart Tutorial: https://gohugo.io/getting-started/quick-start/
- Theme Gallery: https://themes.gohugo.io/
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.
- DNS (AWS Route 53)
- Content-Delivery-Network as HTTP Endpoint (AWS Cloudfront)
- SSL Certificates (AWS Certificate Manager)
- Storage for Website Content (AWS S3)
- Code-Repository (AWS Code-Commit)
- Integration-Pipeline (AWS CodePipeline & CodeBuild)
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
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:
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).
- Click add User
- Type in a User name, e.g.
Programmatic Access, click next
Attach existing policies directlyand check
AdministratorAccess, click next
- click next, click
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
/* 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
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
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. Outputs: git_remote_url = ssh://APKAIX5XFMNUAMMXXD4A@git-codecommit.eu-central-1.amazonaws.com/v1/repos/www.lindendanny.de nameservers = [ ns-1427.awsdns-50.org, ns-1639.awsdns-12.co.uk, ns-468.awsdns-58.com, ns-807.awsdns-36.net ]
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
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
and add some content in
--- 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
Boilerplate Repo: https://github.com/dannylinden/high-performance-seo-website
Terraform Module Code: https://github.com/dannylinden/terraform-aws-website-serverless
Terraform Registry: https://registry.terraform.io/modules/dannylinden/website-serverless/aws/1.0.1
My research for this tutorial starts here: https://medium.com/runatlantis/hosting-our-static-site-over-ssl-with-s3-acm-cloudfront-and-terraform-513b799aec0f