GitHub Actions & Hugo
My blog is statically generated by Hugo and I use GitHub Actions to automate publishing the updates. In this short article, I will walk you through how I’ve setup GitHub Actions to build and deploy this site to an S3 bucket.
AWS Setup
This workflow assumes you have already created an S3 bucket to host your statically generated website and Cloudflare is serving as the proxy. If you are curious how to do this, you can check out my previous post.
I am going to create an IAM user that GitHub will use to publish my statically generated website content. This user will need permission to read and write to my website’s S3 bucket.
Create an IAM Policy
First, I need an IAM Policy that allows an authorized user to read and write to my website’s S3 bucket. In my case, I created an IAM Policy named s3-detnstudios.com-rw
with the following JSON policy:
{
"Version": "2012-10-17",
"Statement": [
{
"Sid": "VisualEditor0",
"Effect": "Allow",
"Action": [
"s3:DeleteObjectTagging",
"s3:ListBucketMultipartUploads",
"s3:GetBucketTagging",
"s3:DeleteObjectVersion",
"s3:ReplicateTags",
"s3:PutObjectVersionTagging",
"s3:ListBucket",
"s3:DeleteObjectVersionTagging",
"s3:GetBucketVersioning",
"s3:GetBucketPolicy",
"s3:ListMultipartUploadParts",
"s3:ReplicateObject",
"s3:PutObject",
"s3:GetObjectAcl",
"s3:GetObject",
"s3:AbortMultipartUpload",
"s3:PutBucketTagging",
"s3:GetObjectVersionAcl",
"s3:GetObjectTagging",
"s3:PutBucketPolicy",
"s3:PutObjectTagging",
"s3:DeleteObject",
"s3:GetObjectVersion"
],
"Resource": [
"arn:aws:s3:::detnstudios.com/*",
"arn:aws:s3:::detnstudios.com"
]
}
]
}
Note: This was my initial IAM policy and I may be able to remove additional permissions without affecting GitHub’s ability to publish my changes.
IAM Group
Next, I created an IAM Group named GitHub
and attached my s3-detnstudios.com-rw
IAM Policy to it.
IAM User
Finally, I created an IAM User named svcGitHub
and I set the user’s access type to Programmatic access only. I added the user to the GitHub
group to ensure the user receives all the permissions assigned to the group.
The last step in the AWS Console was to go to the Security Credentials tab for svcGitHub
and generate an Access Key/Secret Access Key. GitHub uses this token to connect to the S3 bucket to upload website changes.
GitHub Setup
Now that all the grunt work in AWS is complete, it is time to configure the GitHub repository and publish my content updates.
Hugo Configuration
I need to tell Hugo where to deploy my website to. This was done by creating the following deployment section in my Hugo config.toml
file:
[deployment]
[[deployment.targets]]
name = "s3"
URL = "s3://detnstudios.com?region=us-east-1"
[[deployment.matchers]]
pattern = "^.+\\.(js|css|svg|ttf)$"
cacheControl = "max-age=31536000, no-transform, public"
gzip = true
[[deployment.matchers]]
pattern = "^.+\\.(png|jpg|gif)$"
cacheControl = "max-age=31536000, no-transform, public"
gzip = false
[[deployment.matchers]]
pattern = "^.+\\.(html|xml|json)$"
gzip = true
Adding AWS Keys to GitHub
GitHub needs to be able to authenticate to S3. To make this happen, I needed to add my svcGitHub
account’s AWS Access Key & Access Secret Key to GitHub as “secrets”. Secrets are environment variables that are encrypted and only exposed to selected actions. According to GitHub, anyone with collaborator access to this repository can use these secrets in a workflow.
To add the secrets, I browsed to my blog’s GitHub repository Settings page and selected Secrets. I added secrets for AWS_ACCESS_KEY_ID
and AWS_SECRET_ACCESS_KEY
.
The GitHub Action
The secret sauce was adding a .github/workflows/build.yml
YAML file to my Hugo content repository. This tells GitHub Actions exactly what to do.
In my build.yml (below), GitHub Actions installs Hugo v0.73.0, builds my site using the minification option, and then deploys it to S3 using the Access Key and Secret Access Key that I previously setup as GitHub secrets:
name: Build and Deploy
on: push
jobs:
build:
name: Build and Deploy
runs-on: ubuntu-latest
steps:
- uses: actions/checkout@v1
- name: Install Hugo
run: |
HUGO_DOWNLOAD=hugo_extended_${HUGO_VERSION}_Linux-64bit.tar.gz
wget https://github.com/gohugoio/hugo/releases/download/v${HUGO_VERSION}/${HUGO_DOWNLOAD}
tar xvzf ${HUGO_DOWNLOAD} hugo
mv hugo $HOME/hugo
env:
HUGO_VERSION: 0.73.0
- name: Hugo Build
run: $HOME/hugo --minify
- name: Deploy to S3
if: github.ref == 'refs/heads/master'
run: $HOME/hugo -v deploy --target s3
env:
AWS_ACCESS_KEY_ID: ${{ secrets.AWS_ACCESS_KEY_ID }}
AWS_SECRET_ACCESS_KEY: ${{ secrets.AWS_SECRET_ACCESS_KEY }}
git commit
Now that both AWS and GitHub are configured properly, GitHub automatically publishes my posts whenever I commit a new, non-draft page. If the build or upload process fails, I get an email from GitHub.
Future Plans
I routinely create blog posts ahead of time that I want published on different dates. (Full disclosure, I currently have 8 in draft and a list of 29 ideas for future posts.) I’m planning to setup a scheduled GitHub Action that kicks off 2 times a day (6am and 6pm) to execute the Hugo build & deploy steps. But I’ll leave that for another post…