Deploy Hugo site to AWS S3
Hugo is a static site generator
When the site is generated with hugo it’s time to deploy it to some hosting platform. Here is a howto push it to AWS S3 and serve with AWS CloudFront CDN.
Prepare site
Will not be descibing here how to create Hugo site project or add articles or blog posts there. Assuming you have already done this.
If not, here is a Hugo quickstart
Deployment Options
There are several options available to deploy and host a Hugo generated site (https://gohugo.io/hosting-and-deployment/). I personally like
- How hugo site can be hosted on github
- AWS Amplify building and deploying.
- and deploying to s3 with hugo deploy command and serving it with AWS CloudDront CDN and AWS Route53 and AWS Lambda.
Below I am describing exactly this - last - method.
1. Create s3 bitbucket with relaxed permissions
goto: https://console.aws.amazon.com/s3
-
create bucket with the name like site name, for example: “microsoft.com”
-
click on the bucket => properties, down below => static website hosting
-
click edit, then - enable, and “host a static website”
- also put there in index: index.html and in error: 404.html
- click save, remember “bucket website endpoint”, it would look like: http://microsoft.com.s3-website-ap-southeast-2.amazonaws.com
- goto bucket permissions, see the images below. public access must not be blocked.
- bucket policy (replace microsoft.com with your domain name):
{
"Version": "2012-10-17",
"Statement": [
{
"Sid": "PublicReadGetObject",
"Effect": "Allow",
"Principal": "*",
"Action": "s3:GetObject",
"Resource": "arn:aws:s3:::microsoft.com/*"
}
]
}
2. Create Certificate
goto AWS certificate manager https://console.aws.amazon.com/acm pick correct region.
- click request
- public certificate
- domain names: take two like: “microsoft.com” and “www.microsoft.com”
- you can ask for more subdomains like “blog.microsoft.com”, “xmpp.microsoft.com” etc
- do the dns validation. It’s much easier to do/push this via Route53 console if your registrar is AWS.
3. Deploy Lamnda function to Lambda@Edge
The Lambda@Edge function takes will rewrite the Hugo QuickStart project urls for directories to a default object, index.html. That’s how Cloudfront serves the URI ‘/posts/my-post/’ with content ‘/posts/my-post/index.html’ returning 200 instead of 404.
Flavor Cafe (Scotch) Lambda@Edge Code
// Hugo on Cloudfront, Lambda@Edge function
// Flavor Cafe (Scotch)
// @starpebble on github
//
// Two rewrite rules for hugo sub directory uri's.
// Example:
// 1. rewrite uri /posts/ to /posts/index.html
// 2. rewrite uri /posts to /posts/index.html
//
// Add as many file extensions as you like for rule 2.
// uri's that end in a known file extensions are not rewritten by rule 2.
'use strict';
// @starpebble on github
// hugo flavor cafe (scotch)
const DEFAULT_OBJECT = 'index.html';
exports.handler = (event, context, callback) => {
const cfrequest = event.Records[0].cf.request;
if (cfrequest.uri.length > 0 && cfrequest.uri.charAt(cfrequest.uri.length - 1) === '/') {
// e.g. /posts/ to /posts/index.html
cfrequest.uri += DEFAULT_OBJECT;
}
else if (!cfrequest.uri.match(/.(css|md|gif|ico|jpg|jpeg|js|png|txt|svg|woff|ttf|map|json|html)$/)) {
// e.g. /posts to /posts/index.html
cfrequest.uri += `/${DEFAULT_OBJECT}`;
}
callback(null, cfrequest);
return true;
};
4. Create AWS CloudFront CDN
goto https://console.aws.amazon.com/cloudfront
- Create Distribution
- create origin pointing to your s3 bucket
- Certificate for your site
- when it offers to convert to static website - agree
- create behaviour pointing to your origin, and Redirect Http to Https
- below in behaviour/functions associations - in Origin Request - select your Lambda Function
- Save
- Goto your distribution’s General tab and copy your Distribution domain name. Should be looling like: asdfasdfasdf.cloudfront.net
5. Point AWS Route53 DNS to your CloudFrount
goto https://console.aws.amazon.com/route53/v2/hostedzones
- create or click on your site’s hosted zone. Should be called like your site: for example: “microsoft.com”
- create “A” empty record pointing to your CloudFront distribution (Distribution domain name)
- create “A” “www” record pointing as alias to your first “A” record
6. Install aws cli
- Install aws client commandline tools https://docs.aws.amazon.com/cli/latest/userguide/getting-started-install.html
- configure aws cli connection
- check file ~/.aws/credentials, it should have something like
[default]
aws_access_key_id = .......
aws_secret_access_key = .......
- test the connection, type something like below to see your s3 bucket
aws s3 ls
7. Update your config.toml
- open your hugo.toml or config.toml in your hugo project
- add to the end (replace again microsoft.com with yours):
[[deployment.targets]]
# An arbitrary name for this target.
name = "lfs3"
# S3; see https://gocloud.dev/howto/blob/#s3
# For S3-compatible endpoints, see https://gocloud.dev/howto/blob/#s3-compatible
URL = "s3://microsoft.com?region=ap-southeast-2"
# If you are using a CloudFront CDN, deploy will invalidate the cache as needed.
cloudFrontDistributionID = ""
If you keep your configs in config.yml, it should look like
deployment:
targets:
name: "lfs3"
URL: "s3://microsoft.com?region=ap-southeast-2"
cloudFrontDistributionID: "E123123123"
- save this file
- compile your site
hugo
- deploy it with hugo deploy command
hugo deploy
- open your site url in browser to see if this all worked
Useful links
- Submit Google Form in Hugo Website
- Adding Structured data markup to the Hugo website
- Hugo Cheat Sheet
- Using Gitea Actions deploy Hugo website to AWS S3
- Hugo quickstart: https://gohugo.io/getting-started/quick-start/
- Large list of Hugo theme examples: https://themes.gohugo.io/
- Hugo hosting and deployment: https://gohugo.io/hosting-and-deployment/
- Images handling in Mainroad Hugo Theme: Mainroad theme image handling
- Install AWS Command Line Interface (AWS CLI): https://docs.aws.amazon.com/cli/latest/userguide/getting-started-install.html
- Most popular themes for Hugo
- How to store thumbnail images in page bundle folder for Hugo sites with Mainroad theme
I hope this little howto doc would help you. Have a great day!