Publishing With Hugo

This site has been generated using Hugo and the Academic Theme.

Hugo is a static website generator. Which means that you can publish your site anywhere, without the need of a content management system like WordPress installed on the server. There are no need for setting up - and backing up a database on the server.

Also, as a developer I prefer to work with plain text files, and use Git for backup and version control.

Content are created primarily in plain text files using the MarkDown syntax.

The Academic Theme even has build in support for Mermaid for the creation of many different types of graphs. Here is a simple example:

graph LR;
  S1[Install Hugo];
  S2[Get Theme];
  S3[Run Localy];

(However, I have found that the mermaid graphs are a bit unstable, and will sometimes render as the source code text of the graph, instead of the graph it self. Hopefully a future update of Mermaid and Academic will fix this).

Step 1: Install Hugo

If you are on a Mac and are using hombrew it’s as easy as :

brew install hugo

Otherwise check out the various installation options on the Install Hugo page

Step 2: Get a Theme

Now you need to setup a basic site, and choose a theme.

hugo new site your_new_site
cd your_new_site
git init
git submodule add themes/some_theme
echo 'theme = "some_theme"' >> config.toml

If you would like to use the Academic Theme (like I do here), they even have a kickstart template, with a bit of sample content:

git clone My_Website
cd My_Website
git submodule update --init --recursive

Step 3: Run site locally

You are now ready to run your site locally

hugo server -D

Your new site should now be ready at http://localhost:1313/, and it will automatically refresh when you add and edit content, so you always have a live view of how your site will look.

Step 4: Configure and edit content

Most hugo themes comes with a guide on how to configure it. The Academic theme is exceptionally well documented, and a detailed Getting started guide, will lead you through the process.

The Hugo site also have lots of documentation if you need something advanced. But if you can use any of the many provided themes as is, you usually just need to start generating content in the form of MarkDown files.

Step 5: Publish your site

Until now the site have been generated ‘live’ in memory, but before we can upload it to a remote server we need generate the static content files. So stop your ‘hugo server’ command and simply run hugo with no options


This generates the site in the ´/public/’ subdirectory ready for uploading.

There are many options on how, and where to publish your site. See the Academic Themes Deployment Guide or the Hugo Deployment Guide for examples.

I already had a webhotel that supports FTP upload. So I created a simple script to upload the site for me. It relies on the ‘lftp’ command, so first install lftp :

brew install lftp

Then I created script called websync, and saved it somewhere in my PATH (I use $HOME/bin)

# websync -- sync to webhost via ftp
# Expects login info in ~/.netrc and websync.cfg in $PWD
# Adapted from 
# See Also : 

# Check if websync.cfg can be found and no parameters are missing
if [ ! websync.cfg ]; then echo "websync.cfg could not be found."; exit; fi
source websync.cfg
if [ -z "$ftp_host" ]; then echo "FTP-Host is missing in websync.cfg."; exit; fi
if [ -z "$dir_local" ]; then echo "Local directory is missing in websync.cfg."; exit; fi
if [ -z "$dir_remote" ]; then echo "Remote directory is missing in websync.cfg."; exit; fi
echo -e "Start mirroring\n"
echo "Host: $ftp_host"
echo "Local directory: $dir_local"
echo "Remote directory: $dir_remote"

trap "rm -f websync.lock" SIGINT SIGTERM

if [ -e websync.lock ]
  echo "websync is already running."
  exit 1
  touch websync.lock
  lftp $ftp_host << EOF
  ## Some ftp servers hide dot-files by default (e.g. .htaccess), and show them only when LIST command is used with -a option.
  set ftp:list-options -a
  ## if  true, try to negotiate SSL connection with ftp server for non-anonymous access. Default is true. This and other ssl settings are only available if lftp was compiled with an ssl/tls library.
  set ftp:ssl-allow yes
  ## specifies -n option for pget command used to transfer every single file under mirror. Default is 1 which disables pget.
  set mirror:use-pget-n 5
  ## --only-missing # download only missing files
  ## --continue # continue a mirror job if possible
  ## -P5 # download N files in parallel
  ## --log=websync.log # write lftp commands being executed to FILE
  ## delete websync.lock
  rm -f websync.lock
  exit 0

Then I created a websync.cfg file in the root of each of my websites:


and now all it takes to generate and deploy my site is :


It doesn’t get much easier than that….

Bo Frese
Bo Frese
Software Craftsman, Lean Developer & Agile Coach

Uncovering better ways of developing software by doing it and helping others do it.