Part 1 got us a blog that works on localhost. Useful for exactly one person. Now we make it public – S3 for hosting, GitHub Actions for deployment. Push to main, site updates. No manual steps.
Set up S3
Create a bucket
Pick a unique bucket name (e.g., my-blog-bucket) and a region. Nothing special here.
Make it publicly readable
Go to your bucket’s Permissions tab, find Bucket Policy, and add:
{
"Version": "2012-10-17",
"Statement": [
{
"Sid": "PublicRead",
"Effect": "Allow",
"Principal": "*",
"Action": "s3:GetObject",
"Resource": "arn:aws:s3:::your-bucket-name/*"
}
]
}
Replace your-bucket-name with your actual bucket name.
Enable static website hosting
In the Properties tab, scroll to Static Website Hosting and enable it. Set the index document to index.html.
You’ll get a bucket website endpoint – something like http://your-bucket-name.s3-website-us-west-1.amazonaws.com. That’s your blog’s URL. It’s not pretty, but it works. Add a custom domain later if vanity matters.
Set up GitHub Actions
Connect your repo
git remote add origin <your-repo-url>
Add secrets
Go to Settings > Secrets and variables > Actions in your repo. Add three secrets:
| Secret | Value |
|---|---|
AWS_S3_BUCKET |
Your bucket name |
AWS_ACCESS_KEY_ID |
Your AWS access key |
AWS_SECRET_ACCESS_KEY |
Your AWS secret key |
Create the workflow
Add .github/workflows/deploy.yml:
name: Upload Website
on:
push:
branches:
- master
jobs:
deploy:
runs-on: ubuntu-latest
steps:
- uses: actions/checkout@master
- uses: jakejarvis/s3-sync-action@master
with:
args: --acl public-read --follow-symlinks --delete
env:
AWS_S3_BUCKET: ${{ secrets.AWS_S3_BUCKET }}
AWS_ACCESS_KEY_ID: ${{ secrets.AWS_ACCESS_KEY_ID }}
AWS_SECRET_ACCESS_KEY: ${{ secrets.AWS_SECRET_ACCESS_KEY }}
AWS_REGION: 'us-west-1' # optional: defaults to us-east-1
SOURCE_DIR: 'public' # optional: defaults to entire repository
This syncs your Hugo public/ directory to S3 on every push to master. The --delete flag removes files from S3 that no longer exist locally, so your bucket stays clean.
The full loop
Write in Org-mode. Export with ox-hugo. Commit and push. GitHub Actions builds and syncs to S3. Your site is live.
The entire deploy is a git push. Which is exactly how it should be.