Hugo and Docker Development
I like to use Docker to manage my development environment for all of my projects. This allows me to pickup where I left off on a project without haing to spend the time getting my local machine back into the state it was when I was last working on the project. Docker also acts as documentation of the setup involved for my development environment.
I also start out with a monorepo with my Hugo project in a subfolder instead of the root.
My project folder starts off looking something like this:
root/
├─ hugo/
│ ├─ src/
│ │ ├─ .gitkeep
│ ├─ Dockerfile
├─ docker-compose.yml
├─ .env
The Dockerfile itself sets up a golang:bullseye
container with Hugo and Node installed.
# hugo/Dockerfile
FROM golang:bullseye as hugo
WORKDIR /src
ARG NODE_VERSION=18.x
ENV NODE_VERSION ${NODE_VERSION}
RUN curl -sL https://deb.nodesource.com/setup_${NODE_VERSION} | bash - &&\
apt-get update -y &&\
apt-get install -y nodejs
# Install Hugo after Node to avoid Node installation everytime the Hugo version changes.
ARG HUGO_ARCH=amd64
ARG HUGO_VERSION=0.107.0
ENV HUGO_VERSION ${HUGO_VERSION}
RUN curl -L https://github.com/gohugoio/hugo/releases/download/v${HUGO_VERSION}/hugo_${HUGO_VERSION}_Linux-${HUGO_ARCH}.deb -o hugo.deb &&\
apt-get update -y &&\
apt install ./hugo.deb
## NOTE: For new projects, you will need to comment the lines between the `start` and `end`. Otherwise you will get a build error.
## start: comment for new projects
# COPY ./src/package.json ./src/package-lock.json ./
# RUN npm install
# COPY ./src ./
# CMD npm start
## end: comment for new projects
Then my docker-compose.yml
file starts off with just the hugo
service.
# docker-compose.yml
version: '3.7'
services:
hugo:
build:
context: ./hugo
dockerfile: Dockerfile
target: hugo
args:
HUGO_ARCH: ${HUGO_ARCH:-amd64}
env_file:
- .env
- hugo/.env
environment:
NODE_ENV: ${NODE_ENV:-development}
HUGO_ENV: ${HUGO_ENV:-development}
HUGO_BASEURL: ${HUGO_BASEURL}
restart: unless-stopped
volumes:
- type: bind
source: ./hugo/src
target: /src
## NOTE: For new projects, you will need to comment the `/src/node_modules/` volumne
# - /src/node_modules/
tmpfs: /src/tmp
ports:
- 1313:1313
The last bit are the .env
files in the root
and hugo
folders that will allow us to fine tune the setup based on our device. For instance, I ofetn develop on an AMD iMac and an M1 Macbook Pro on the road. By default the configuration is for the iMac.
touch .env
touch hugo/.env
On my M1 Macbook I have a .env
file that changes the HUGO_ARCH
evironment variable:
# .env (on my M1 Macbook)
HUGO_ARCH=arm64
With this configuration, you can also customize the NODE_VERSION
, HUGO_VERSION
, NODE_ENV
, and HUGO_ENV
.
The other environment variable to mention is HUGO_BASEURL
so we dont have to set the baseURL
in the hugo config.(toml|yaml|json)
and the --baseURL
flag when running the hugo development server.
With that we can run docker-compose build
to build our container and docker-compose run --rm hugo bash
to ssh into the container to run our hugo new site .
to generate the hugo files in our hugo/src
folder.
I have a few helper bash files I create to reduce the amount of docker-compose ...
I have to write.
echo $'#!/usr/bin/env bash\ndocker-compose build "$@"' > build.sh
echo $'#!/usr/bin/env bash\ndocker-compose logs -f --tail=100 "$@"' > logs.sh
echo $'#!/usr/bin/env bash\ndocker-compose restart "$@"' > restart.sh
echo $'#!/usr/bin/env bash\ndocker-compose run --rm "$@"' > run.sh
echo $'#!/usr/bin/env bash\ndocker-compose stop "$@"' > stop.sh
echo $'#!/usr/bin/env bash\ndocker-compose up -d --build --force-recreate -V "$@"' > up.sh
chmod +x build.sh logs.sh restart.sh run.sh stop.sh up.sh
These scripts allow me to focus on the task and not have to memorize the docker commands. They all tak an optional service
parameter which should match the name of your service in the docker-compose.yml
file. If you do not pass the service name, it will run the command agains ALL services in your docker-compose.yml
.
# Build all services in the `docker-compose.yml`
./build.sh
# Build JUST the `hugo` service
./build.sh hugo
I also named the service the same as the folder to allow autocomplete in the shell by using tab. Just be sure to hit backspace to remove the trailing /
.