The proper way to build a Hugo docker container
I’m writing this article since a cursory internet search when creating this blog revealed numerous terrible ways to build hugo.
A hugo deployment needs nothing other than an unprivileged webserver and the static html files.
Without further ado this is the most efficient hugo
Dockerfile you will find:
FROM --platform=$BUILDPLATFORM alpine:3.13 as build RUN apk add --no-cache hugo WORKDIR /src COPY . . RUN --mount=type=cache,target=/tmp/hugo_cache \ hugo FROM nginxinc/nginx-unprivileged COPY --from=build /src/public /usr/share/nginx/html EXPOSE 8080
This is a Dockerfile defines multi-stage build which results in a final image that does not include hugo itself, but only the blog. It runs nginx in unprivileged on port 8080 and as the non-root user for that extra bit of hardening.
It’s also the most efficient multi-arch build you will ever see. Why? The secert lies in the
--platform=$BUILDPLATFORM from argument.
The docker buildx (buildkit) container builder usually runs each stage with each and every architecture. This, although very quick anyway,
is wasteful as the generated web resources are not architecture dependent. Specifying –platform=$BUILDPLATFORM tells buildkit to not
bother emulating a different archictecture for that stage.
The final improvement is using
--mount=type=cache,target=/tmp/hugo_cache in order to reuse hugo cache between builds. As if builds weren’t quick enough!
Many thanks to Tõnis Tiigi, the buildkit developer who made this possible.