Getting Started with Hugo and Docker
Learn how to set up a Hugo static site using Docker containers - no local installation required! This step-by-step guide shows you how to create, develop, and build Hugo sites in an isolated, reproducible environment.

Docker Container
Pull the Docker container from the Docker Hub:
docker pull registry.gitlab.com/pages/hugo/hugo_extended:latest
Tag
For convenience, let’s create an alias (tag) so we don’t have to refer to the full url for every Docker command.
docker tag registry.gitlab.com/pages/hugo/hugo_extended:latest hugo_extended
For more information see docker tag.
Creating a New Site
We can begin using the Hugo container to create a new site:
docker run --rm -v ${PWD}:/src hugo_extended hugo new site quickstart
docker runHave Docker run (create a new container)--rmtells Docker we want to clean up the container once it finishes executing.-v ${PWD}:/srcmounts the current directory on the host machine to a folder within the Hugo container at/site.hugo_extendedis the Hugo container we pulled earlier.hugo new site <site_name>Execute thenew sitesubcommands for Hugo. The Hugo container has already defined the primary entry point of the container to be thehugocommand. The last argument is the name of the site we are creating.
After executing the command above you’ll see:
Congratulations! Your new Hugo site is created in /src/quickstart.
Just a few more steps and you're ready to go:
1. Download a theme into the same-named folder.
Choose a theme from https://themes.gohugo.io/ or
create your own with the "hugo new theme <THEMENAME>" command.
2. Perhaps you want to add some content. You can add single files
with "hugo new <SECTIONNAME>/<FILENAME>.<FORMAT>".
3. Start the built-in live server via "hugo server".
Visit https://gohugo.io/ for quickstart guide and full documentation.
We executed Hugo within the container; Hugo isn’t installed on the host.
The resulting files (or artifacts) from running the
hugo new sitewere persisted and available on the host even after the container was destroy because of the volume we mounted.
Adding a Theme
Before we go add a theme let’s treat this as a real project:
cd quickstart
git init
git add .
git commit -m "initial commit"
Now that we have a git repository we an add a theme via submodule:
git submodule add https://github.com/calintat/minimal.git themes/minimal
git submodule init
git submodule update
echo 'theme = "minimal"' >> config.toml
If this theme isn’t to your liking feel free to browse https://themes.gohugo.io/ for more them options.
At this point we can bring up the site with:
docker run --rm -v ${PWD}:/src -p 1313:1313 hugo_extended hugo server --bind 0.0.0.0
docker runHave Docker run (create a new container)--rmtells Docker we want to clean up the container once it finishes executing.-v ${PWD}:/srcmounts the current directory on the host machine to a folder within the Hugo container at/src.-p 1313:1313port forwards port 1313 on our host to 1313 on our containerhugo_extendedis the Hugo container we pulled earlier.hugo server --bind 0.0.0.0Execute thehugo serversubcommand. The additional bind option is required when running in a container otherwise you won’t be able to open the site locally in your browser.
You’ll get some output:
| EN
+------------------+----+
Pages | 7
Paginator pages | 0
Non-page files | 0
Static files | 3
Processed images | 0
Aliases | 0
Sitemaps | 1
Cleaned | 0
Total in 42 ms
Watching for changes in /src/{content,data,layouts,static,themes}
Watching for config changes in /src/config.toml
Serving pages from memory
Running in Fast Render Mode. For full rebuilds on change: hugo server --disableFastRender
Web Server is available at http://localhost:1313/ (bind address 0.0.0.0)
Press Ctrl+C to stop
Open a browser and navigate to http://localhost:1313.
Once your done looking press Ctrl+C in the Terminal to stop the running Hugo Docker container.
Commit your Changes
git add .
git commit -m "add theme submodule"
Streamlining with Docker Compose
Docker Compose provides us a mechanism to reduce our typing and get everything we need up and going. In this case there is just the one service, but imagine needing databases, logging services, key-value services, and API service. It is so much nicer to run one thing and have the system ready for me to jump right into it.
Another reason for this is our continuous integration and deployment. You’ll often here a lot of people talk about using Docker to maintain consistency between environments; what is running in dev is the same as integration, staging, prod only with configuration variances. While this is true the other powerful thing Docker Compose provides it a composable set of deployment commands. More on this later.
Create a docker-compose.yml in the project root with the following contents:
version: "3"
services:
hugo:
image: registry.gitlab.com/pages/hugo/hugo_extended:latest
working_dir: /src
ports:
- "1313:1313"
volumes:
- ".:/src"
command: server --bind 0.0.0.0
Starting Hugo
docker-compose up -d hugo
Open a browser and navigate to http://localhost:1313.
Commit your Changes
git add .
git commit -m "add docker-compose"