From Push to Production: Hugo Static Website Deployment
Table of Contents
Finding the fastest way to publish static Hugo websites isn’t always straightforward.
After finishing your site, you’ll probably ask yourself: What’s next? and How do I deploy it easily to production?
In this article, I’ll share a simple approach to build, publish, and prepare your site for containerized environments like Docker or Kubernetes—just like the website you’re reading right now.
So, let’s say your site is ready and you already connected a GitHub Repository. From a DevOps perspective, there are many ways to bring it to production. Here, we’ll focus on a clean workflow using GitHub, GitHub Actions, and Docker.
Your Repository should look like this:

Dockerfile
As you can see, the website hasn’t been built yet, so there’s no public
folder.
However, we know that after the automatic build process, a public
folder will be generated. This means we can already prepare the Docker image. In this example, we’re using Nginx as the web server, but feel free to use any other tool that fits your needs.
Create a Dockerfile in the root of your repository:
touch Dockerfile
vim Dockerfile # or nano
Then, paste the following content:
FROM nginx:alpine
COPY public /usr/share/nginx/html
EXPOSE 80
Make sure to commit your changes:
git add Dockerfile
git commit -m "feat: added Dockerfile"
GitHub Workflow
Our CI pipeline will consist of just a few steps:
First, we’ll build the Hugo site. Then, we’ll use the Dockerfile to package it into an image and push it to a container registry.
In this example, we’re using Docker Hub, so anyone can try it out easily. Of course, you can replace it with any other registry you prefer.
First, create the .github/workflows
folder to store your pipeline files:
mkdir -p .github/workflows
Then create the workflow file:
cd .github/workflows
touch hugo.yml
vim hugo.yml
Paste the following content:
name: Build and Push Hugo Site to Docker Hub
env:
IMAGE_NAME: <your_image_name>
on:
push:
branches: ["master"]
workflow_dispatch:
jobs:
build:
runs-on: ubuntu-latest
steps:
- name: Checkout
uses: actions/checkout@v4
with:
submodules: recursive
- name: Install Hugo
run: |
HUGO_VERSION=0.128.0
wget -O hugo.deb https://github.com/gohugoio/hugo/releases/download/v${HUGO_VERSION}/hugo_extended_${HUGO_VERSION}_linux-amd64.deb
sudo dpkg -i hugo.deb
- name: Install Dart Sass
run: sudo snap install dart-sass
- name: Build Hugo site
run: hugo --minify --baseURL "/"
- name: Install cosign
uses: sigstore/cosign-installer@59acb6260d9c0ba8f4a2f9d9b48431a222b68e20 #v3.5.0
with:
cosign-release: 'v2.2.4'
- name: Set up Docker Buildx
uses: docker/setup-buildx-action@f95db51fddba0c2d1ec667646a06c2ce06100226 # v3.0.0
- name: Log in to Docker Hub
uses: docker/login-action@v3
with:
username: ${{ secrets.DOCKER_USERNAME }}
password: ${{ secrets.DOCKER_PASSWORD }}
- name: Extract Docker metadata
id: meta
uses: docker/metadata-action@96383f45573cb7f253c731d3b3ab81c87ef81934 # v5.0.0
with:
images: docker.io/${{ env.IMAGE_NAME }}
- name: Build and push Docker image
id: build-and-push
uses: docker/build-push-action@v6
with:
context: .
platforms: linux/amd64,linux/arm64
push: ${{ github.event_name != 'pull_request' }}
tags: |
docker.io/${{ env.IMAGE_NAME }}:latest
docker.io/${{ env.IMAGE_NAME }}:${{ github.sha }}
labels: ${{ steps.meta.outputs.labels }}
cache-from: type=gha
cache-to: type=gha,mode=max
Finally, replace the placeholder with your own image name, for example:
env:
IMAGE_NAME: user123/hugo-static-website
Before pushing, note that the workflow uses two secrets:DOCKER_USERNAME
and DOCKER_PASSWORD
.
You need to configure these secrets in your GitHub repository:
- Go to Settings → Secrets and variables → Actions.
- Under Repository secrets, add:
DOCKER_USERNAME
→ Your Docker Hub usernameDOCKER_PASSWORD
→ Your Docker Hub password or personal access token

After completing this setup, push your changes:
git add .
git commit -m "ci: added hugo pipeline"
git push
Docker Hub
Now, you should find your new image on Docker Hub:

Run the website on your localhost with:
docker run -d -p 80:80 <user/image:tag> # example: user123/hugo-static-website:latest
Now, you can visit your website on http://localhost
Make your repository private on Docker Hub
If you don’t host an image registry by yourself, you could also make your docker image repository private to make the website unavailable for other docker hub users.
To achive this, Docker Hub go to manage repositories and choose your repository. On Settings you will find the Visibility settings. Change the visbility to private
.
