Introduction
Looking at Hugo’s quick start tutorial, you’ll find many ways to host and deploy your website using different methods. Most of them involve some kind of cloud service where you upload the generated Hugo artifacts. What’s missing in my opinion — at least at the time of writing — is a guide on how to containerize your Hugo site.
A Dockerfile not only comes in handy in order to serve the site but also to build it in first place.
Prerequisites
This article uses Docker 28.5.1.
HTTP Server
There are plenty of reliable, robust, and mature HTTP servers out there.
Since it’s already 2025, let’s use a modern one built in Rust: simple-http-server.
It’s lightning fast, has a small memory footprint, and — being written in Rust — benefits from its memory safety guarantees.
Dockerfile
The basic assumption in this setup is that all files regarding hugo are stored inside src folder.
.
├── Dockerfile
└── src
├── archetypes
├── assets
├── content
├── data
├── hugo.toml
├── i18n
├── layouts
├── public
├── resources
├── static
└── themes
Stage 1
# ---- Stage 1: Build Rust simple-http-server ----
FROM rust:alpine AS build
RUN apk add --no-cache build-base pkgconf musl-dev openssl-dev openssl-libs-static zlib-dev zlib-static
RUN cargo install simple-http-server
Here we want to build the http server using rust default alpine docker image. Per default a few packages are missing that are required for compilation. Last but not least we build the server using cargo.
Stage 2
# ---- Stage 2: Create website artifacts using Hugo ----
FROM chainguard/hugo AS hugo
WORKDIR /tmp/src
# copy all hugo files
COPY src .
# --destination: write to a folder where Hugo has write permissions
# --noBuildLock: avoid permission errors
# --minify: optimize output size
RUN ["hugo", "--destination", "/tmp/srv", "--noBuildLock", "--minify"]
This stage generates the Hugo site artifacts. The Chainguard image includes the Hugo binary, but the container environment is quite restricted. That’s why all the work is done in a path under /tmp, where Hugo can write freely.
Stage 3
# ---- Stage 3: Copy binaries and website artifacts to final image ----
FROM alpine:latest
COPY --from=build /usr/local/cargo/bin/simple-http-server /usr/local/bin/
COPY --from=hugo /tmp/srv /srv
CMD ["/usr/local/bin/simple-http-server", "--port", "8080", "--ip", "0.0.0.0", "-i", "--try-file", "/srv/404.html", "/srv"]
This final stage combines the results of the previous stages into a minimal, optimized image. Therefore we only copy the server binary and the Hugo artifacts over. Finally, we set the CMD to start and configure the server.
Run
The rest is standard Docker workflow:
docker buildx build -f Dockerfile -t http-server --load .
docker run -it --rm --init -p 8080:8080 http-server
Conclusion
With just a few lines in your Dockerfile, you can fully containerize your Hugo site. Handling both the build and the serving process in one place. Whether you host it locally or deploy it to your own infrastructure, this approach keeps things simple, reproducible, and portable.