Hugo And AWS

Let’s generate a website with Hugo and deploy it using Amazon Web Services (AWS).

As an exercise we’ll walk through the following steps to deploy a simple static website:

Tools and Methods

Hugo is a static website framework built in Go, it provides a convenient templating system that is then rendered to HTML and packaged along with CSS and other web resources to create a static website. I’m admittedly not an expert in using Hugo and will not go into much detail on it in this post.

AWS is an extensive suite of services provided by Amazon. We will only be scratching a very tiny portion of the services they provide but I would suggest S3 to be a service that everyone be comfortable with. Along with the CLI S3 provides an easy way to backup data - everything from production databases to personal documents.

Methods

Hugo - Create A Website

Checkout the official quick-start and walk through the initial steps to create a project. After spending several hours testing different themes that you’re not quite 100% happy with come back here.

To track our steps let’s create a Makefile in the project with the following dev and dist targets:

.PHONY: dist

dev:
	hugo server --buildDrafts

dist:
	hugo

make dev - Runs a development server locally which will auto-reload when changes are made for easier development.

make dist - Packages the website into the directory specified by the publishDir variable in Hugo’s config.yaml or config.toml file:

> grep publishDir ./config.yaml 
publishDir: "dist"

S3 - Create And Configure A Bucket

For this step it’s assumed that the AWS CLI is installed and configured locally:

> aws configure
AWS Access Key ID [********************]: 
AWS Secret Access Key [********************]: 
Default region name [us-west-2]: 
Default output format [json]: 

If not you will need to follow instructions online to create keys in IAM. For the purposed of this post you will also need the following permission policies:

To simplify the process of creating and configuring the S3 bucket I’ve created the following script s3-manage-website.sh.

Which we can integrate into our project by adding the core-devops repository as a subtree:

git subtree add --prefix .core-devops git@gitlab.com:mega-mac-slice/core-devops.git master --squash

And then modifying our Makefile by adding the following setup target:

.PHONY: dist setup
BUCKET := example.org
REGION := us-west-2

dev:
	hugo server --buildDrafts

dist:
	hugo

setup:
	.core-devops/scripts/aws/s3-manage-website.sh create $(BUCKET) $(REGION) \
	&& .core-devops/scripts/aws/s3-manage-website.sh update $(BUCKET)

Note that we defined a variable REGION at the top, this value can be determined by running aws configure get region.

And run make setup once before deploying to create and configure the S3 bucket.

Deploying

Modify your Makefile by adding the following deploy, publish and open targets:

.PHONY: dist setup
BUCKET := example.org
REGION := us-west-2

dev:
	hugo server --buildDrafts

dist:
	hugo
	
setup:
	.core-devops/scripts/aws/s3-manage-website.sh create $(BUCKET) $(REGION) \
	&& .core-devops/scripts/aws/s3-manage-website.sh update $(BUCKET)

deploy:
	aws s3 sync dist/ s3://$(BUCKET)

publish: dist deploy

open:
	open $(shell .core-devops/scripts/aws/s3-manage-website.sh url $(BUCKET))

Now run make publish && make open and your browser should be opened to something like http://example.org.s3-website-us-west-2.amazonaws.com with your beautiful website visible to the world.

Now that we have our site hosted in S3 let’s link it to a prettier domain. I’m going to omit the codifying of acquiring the domain as I don’t believe I have the control to not purchase a domain for every terrible idea I have, so we’ll assume the domain has been acquired through the AWS Console already.

To simplify the process of configuring the domain I’ve again created another script route53-manage-domain.sh.

Since we’ve already added the core-devops repo to our project we only need to update our Makefile with the link target:

.PHONY: dist test clean
BUCKET := example.org
REGION := us-west-2

dev:
	hugo server --buildDrafts

dist:
	hugo

setup:
	.core-devops/scripts/aws/s3-manage-website.sh create $(BUCKET) $(REGION) \
	&& .core-devops/scripts/aws/s3-manage-website.sh update $(BUCKET)

deploy:
	aws s3 sync dist/ s3://$(BUCKET)

publish: dist deploy

open:
	open http://$(shell .core-devops/scripts/aws/s3-manage-website.sh url $(BUCKET) $(REGION))

link:
	.core-devops/scripts/aws/route53-manage-domain.sh link $(BUCKET) $(REGION)

Afterwards we can run make link, and provided there’s no error we can go for a walk and come back to a working domain. (The effects may not be immediate. A 5 to 20 minute walk should be sufficient.)

Results

mega-mac.com was created with Hugo and deployed with AWS, and this post is the resulting notes.

Discussion

Hugo isn’t the only static site generator, GatsbyJS seems pretty common in addition to just a few other ones in a variety of languages. The use of static generators is a component of the JAMstack.

A yeoman generator based off the findings from this post can be found at generator-hugo.

Future Considerations

AWS

Gitlab

Website

References