Create Hugo in Container

One way that I publish my hugo pages is in a docker container or in my Kubernetes cluster. Both of the places that I run those is on my Raspberry Pi CM3 system which doesn’t have (until recently) a recent version of hugo. To get past this I first have docker to build a development container, load Go and Hugo, and compile the pages. Then I create a second container that doesn’t have the overhead of an operating system or system libraries, copy in the web pages and a web server that has been staticly linked

Note

I have Hugo configured to put the result pages in tht doc directory instead of public. I could simplify the web server if I put in the name of the path that I want to server to use (hugo-demo) in this case. There are other configuration options (relative pages for example) where I could make this build and server even more generic. Someday maybe.

Dockerfile

The first container built is temporary. It starts with Alpine Linux 3.20 which is a small distribution based around Busybox. From the Alpine repository we load go and hugo.

As of 2024-07-15 we get

  • Alpine 3.20.1
  • Go 1.22.5
  • Hugo 0.125.4+extended

The rest sets the working directory, copies all of the local files (our source code) into the working directory. Compiles the pages and compiles the web sever.

The second container starts with an empty container and copies the finished web pages and compiled web server from the first container. The it sets up to start the web server by default with no parameters.

# Container 1
FROM alpine:3.20 AS builder
RUN apk add --no-cache hugo go
WORKDIR /hugo-demo
COPY . /hugo-demo/
RUN hugo
RUN go build -a -tags netgo webserver.go

# Container 2
FROM scratch
WORKDIR /hugo-demo
COPY --from=builder /hugo-demo/doc doc
COPY --from=builder /hugo-demo/webserver webserver
EXPOSE 1313
ENTRYPOINT [ "/hugo-demo/webserver" ]

Build using something like:

docker build -t hugo-demo:latest .

Run using something similar to: (or run as daemon for background operation with -d etc.)

docker run --rm -it -p 1313:1313 hugo-demo [optional-parameters-here]

Web Server

This web server serves up pages from the doc directory. It allows you to put a prefix on the URL to make it easier to configure in a reverse proxy. Allowable values really depends on how Hugo was configured. For example, when I wrote this the configuration was:

baseURL = 'http://www.example.com/hugo-demo/'
relativeURLs = false
publishDir = "doc"

Another valid way to configure Hugo is with:

baseURL = '/'
relativeURLs = true
publishDir = "doc"

Now all of the URLs will be relative. Of course that means that site-map and RSS.xml files will be useless since they don’t have a host to point to. A discussion on these and other ways to configure Hugo is at Theme relearn customizations

Note that the redirect on line 20 was for user convenience. If they go to the root of the website they will be redirected to the top of the documentation.

 1package main
 2
 3// This is a simple web server that serves any file in the current directory
 4// (and below).
 5import (
 6	"flag"
 7	"log"
 8	"net/http"
 9)
10
11var (
12	webAddr = flag.String("web_addr", ":1313", "HTTP service address")
13	prefix  = flag.String("prefix", "/hugo-demo/", "Webpage prefix")
14	dir     = flag.String("dir", "./doc", "Base of documentation directory.")
15)
16
17func main() {
18	flag.Parse()
19	http.Handle(*prefix, http.StripPrefix(*prefix, http.FileServer(http.Dir(*dir))))
20	http.Handle("/", http.RedirectHandler(*prefix, http.StatusFound))
21	log.Printf("Starting Connection on %s\n", *webAddr)
22	log.Fatal(http.ListenAndServe(*webAddr, nil))
23}