Deploying a Production Ready Hugo Site With 2 Lines of Code to AWS

What do you mean by production ready?

A site hosted on AWS S3, using a custom domain, with a CDN and a SSL certificate.

TL;DR

I use the CDK, a custom construct, and Python to easily deploy this site to AWS.

Requirements

  • Install the AWS CDK
  • Python 3.6+
  • Your hugo website
  • An AWS account and have previously setup the AWS CLI and run aws configure
  • A Route53 hosted zone and an available domain/subdoman A record (a domain or sub domain not currently in use)

Setup

Create a new directory and start a new CDK app:

mkdir cdk-app
cd cdk-app
cdk init --language python

This will generate a number of files, but the two that you care about are:

app.py
cdk_app/cdk_app_stack.py

2 Lines of Code

open the cdk_app_stack.py and add the following code at the bottom of the __init__:

zone = HostedZone.from_lookup(
    self, "HostedZone", 
    domain_name="MYDOMAINNAME.COM", 
    private_zone=False
)

StaticWebsite(
    self, "serverlesslink-website",
    hosted_zone=zone,
    site_domain="BLOG.DOMAINNAME.COM",
    sources="../public",
    website_error="404.html"
)

In the first line, you will be creating a hosted zone object from a lookup, this is an existing hosted zone in Route53 and you must have access to use it.

The second line is the static website construct and it takes:

  • The hosted zone you created above
  • The site domain/subdomain you want to use for your hugo site
  • The location of your code relative to the CDK app directory
  • Optional, the error page if is not called error.html

Deploy the site

All that is left now is to deploy the site:

cdk deploy

Update and sync files

Now that your infrastructure is in place, all you need to do moving forward is to sync the public directory with your website bucket.

Use a script like this to sync all your data and invalidate CloudFront

#!/bin/bash
# sync.sh
hugo -D
aws s3 sync public s3://BLOG.DOMAINNAME.COM
aws cloudfront create-invalidation --distribution-id YOURDISTRIBUTIONID --paths "/*"

It will take a few minutes to see all your updates.

Troubleshooting

While working with the CDK I learned some important lessons:

CDK asking for account and region

For local development and deployment, it is best to pass a custom env to the application stack. Open the app.py and pass a custom env dict to the stack:

import os
from aws_cdk import core

env = core.Environment(account=os.getenv('CDK_DEFAULT_ACCOUNT'), region=os.getenv('CDK_DEFAULT_REGION'))
CdkAppStack(app, "cdk-app", env=env)

All this is saying is that if the app can’t find some custom environment variables AWS_ACCOUNT_ID and AWS_DEFAULT_REGION, to use the CDK values which come from the aws cli profile. You would use the custom env vars when deploying this in a CICD.

Sub-directories are showing errors

Simply follow the instructions in this post. I’ll try to fix this in the construct, but as of right now, you may need to do it manually.