Generate website with Hugo without installation

Posted on September 9, 2023 • 7 min read • 1,354 words

How do I generate a static Hugo website without installing Hugo on my computer?

Generate website with Hugo without installation
Photo by pressfoto  on Freepik 

For this blog, I have opted for a static web project, i.e. the pages are created once and then delivered directly from the web server. To avoid having to create the web pages manually, there are so-called static website generators such as Jekyll , Gatsby or the fantastic Hugo , which I have chosen.

Static website generators generally have a number of pleasant features:

  • Content and presentation are separated
  • The complete static output is generated from Markdown/HTML files and images
  • There is a wide range of free and commercial designs/layouts available
  • Only a web server (Nginx/Apache) is required for productive use
  • Very good maintainability due to low complexity

The great thing about writing a blog is that you can research a topic at any time and prepare it for a short article whenever you come across something interesting.

The most common way is to install Hugo locally on a computer and use the installation to generate the page. So far so good.

I would like to show you an alternative way here that does not require an installation, but is based on a Docker container, which in turn contains Hugo. To make things easier, the main commands are implemented as scripts that then call the container.

Technologies used

All tools are completely free and open source.

I assume you already have Docker installed. If not, there are good introductions out there on the subject of containerisation and how to get started with it (e.g. Docker Docs ).

A Hugo project as starting point

As an example project, let’s take the Hugo Clarity Theme by Chip Zoller , which I think is very well-designed. If you already have a project, you can of course skip these steps.

On an Ubuntu Linux system, first create a suitable folder and clone the theme into it. The included sample pages are then copied into the template to create a website that can be generated.

mkdir -p ~/project/hugo-clarity/themes
cd ~/project/hugo-clarity
git clone https://github.com/chipzoller/hugo-clarity.git themes/hugo-clarity
cp -r themes/hugo-clarity/exampleSite/* .

Hugo in a Docker container

The Github project Github Projekt docker-hugo used here is described by its author Erlend Klakegg Bergheim himself as “Truly minimal Docker images for Hugo with batteries included”, i.e. a minimal Hugo Docker image with all the trimmings.

However, we do not need to concern ourselves with creating the image, as you can download the current version klakegg/hugo:0.111.3-ext-ubuntu (at the time of writing) from DockerHub as usual.

Local development of the Hugo project

For a local installation, the usual procedure would be to start the Hugo server with the parameters -D -E -F -w –disableFastRender in the Hugo project folder.

To do this, Hugo would have to be installed locally. Here we now use the klakegg/hugo image, which does nothing other than make Hugo available in a container, but does it well.

Firstly, some scripts are created. I maintain these little helpers in a ./tools folder within the Hugo project (parallel to ./config and ./content). This folder contains, for example, the tool for starting the Hugo server locally.

#!/bin/bash

DIR="$( cd "$( dirname "${BASH_SOURCE[0]}" )" && pwd )"
USER_ID=$(id -u ${USER})
GROUP_ID=$(id -g ${USER})
IMAGE="klakegg/hugo:0.111.3-ext-ubuntu"

SERVER_PARAMETERS=""
PORT="1313"

POSITIONAL_ARGS=()
while [[ $# -gt 0 ]]; do
  case $1 in
    --dev|--development)
      SERVER_PARAMETERS+="-D -E -F -w --disableFastRender "
      shift # past argument
      #shift # past value
      ;;
    --prod|--production)
      SERVER_PARAMETERS=" "
      shift # past argument
      #shift # past value
      echo "Production Server"
      ;;
    -p|--port)
      PORT="$2"
      shift # past argument
      shift # past value
      ;;
    -*|--*)
      echo "Unknown option $1"
      exit 1
      ;;
    *)
      POSITIONAL_ARGS+=("$1") # save positional arg
      shift # past argument
      ;;
  esac
done

echo "Start Hugo server using: $SERVER_PARAMETERS on port $PORT"

docker run --rm -it\
    -u ${USER_ID}:${GROUP_ID} \
    -p ${PORT}:${PORT} \
    -v ${DIR}/../:/src \
    ${IMAGE} server -p ${PORT} ${SERVER_PARAMETERS}

The script must be made executable once before it is used for the first time

chmod +x ./tools/hugo-server.sh

The script is executed in a separate terminal window and starts the Hugo server as usual, which then monitors the Hugo project folder, regenerates the project when changes are made and makes it available via a local web server.

Usage:

./tools/hugo-server.sh --dev          # (development) starts the server using -D -E -F -w --disableFastRender
./tools/hugo-server.sh --prod         # (production) starts the server, not showing pages marked as draft
./tools/hugo-server.sh --dev -p 1500  # (development), set local server port to 1500

When started, the output should be similar to this

./tools/hugo-server.sh --dev
Starte Hugo Server mit: -D -E -F -w --disableFastRender  auf Port 1313
Start building sites …
hugo v0.111.3-5d4eb5154e1fed125ca8e9b5a0315c4180dab192+extended linux/amd64 BuildDate=2023-03-12T11:40:50Z VendorInfo=hugoguru

                   | EN | PT
-------------------+----+-----
  Pages            | 53 | 30
  Paginator pages  |  1 |  0
  Non-page files   |  2 |  0
  Static files     | 63 | 63
  Processed images |  0 |  0
  Aliases          | 30 | 15
  Sitemaps         |  2 |  1
  Cleaned          |  0 |  0

Built in 627 ms
Watching for changes in /src/{archetypes,content,layouts,static,themes}
Watching for config changes in /src/config/_default, /src/config/_default/menus
Environment: "DEV"
Serving pages from memory
Web Server is available at http://localhost:1313/ (bind address 0.0.0.0)
Press Ctrl+C to stop

Now just start a local browser with the url http://localhost:1313/ (or the specified port p) and the website is already in the browser.

The container and thus the server can be closed in the terminal window with CTRL+C.

The charming thing about the Hugo server is that in development mode (--dev) it replaces the baseURL in config.toml, which normally points to the domain under which the page should run, with localhost:<port (default 1313)>. This means that the project can only be viewed on the local computer.

Creating static files of the Hugo project

At some point, the article will be finished, the right images will be included in the best place and the spelling will have been checked to the best of the author’s knowledge and belief. Now it’s time for the next step towards publication.

The following script generates the Hugo project and thus its web pages (or publishes them in Hugo-speak).

#!/bin/bash
set -e
set -o pipefail

DIR="$( cd "$( dirname "${BASH_SOURCE[0]}" )" && pwd )"
USER_ID=$(id -u ${USER})
GROUP_ID=$(id -g ${USER})

# generate the project with Hugo
IMAGE="klakegg/hugo:0.111.3-ext-ubuntu"
# Empty the output folder
rm -rf ${DIR}/../public/*

docker run --rm -it \
    -u ${USER_ID}:${GROUP_ID} \
    -v ${DIR}/../:/src \
    -e HUGO_ENVIRONMENT='production' \
    ${IMAGE} 

Executing the script generates everything necessary for the website in ./public.

chmod +x ./tools/hugo-generate.sh  # run once to make script executable

./tools/hugo-generate.sh

If the content of ./public is now placed in the root directory of a web server, this will make the static website that has just been created available.

Résumé

Encapsulating the Hugo static website generator in a Docker container enables it to be used without having to install Hugo and its dependencies on the local computer. This saves the computer from having to install anything. However, it also makes it possible to create identical, generated pages on different computers, as the generating software (Hugo) is encapsulated and versioned in the Docker image.

Next Steps

In order to be able to put the generated static web pages online, a web server is still missing and preferably an integration into an easy-to-publish Docker image.