Introduction
In this guide I’ll cover steps for installing Hugo on a server running Ubuntu. This may work on other Debian distros as well, however this has not been tested by me. Before starting this guide, you’ll need:
- A server running a Ubuntu 22.04+
- A working web host (nginx or apache) running
- A FQDN (Fully Qualified Domain Name) to use for the site — either a local A record (for internal hosting) or a public A record (for internet access)
Step 1. Installing Hugo
There’s a couple of ways to go about this, and I’ll detail two common methods
Prepare working space
The purpose of this is to keep your hugo website(s) in a single place, to make it easier to work with in the future. You can create this anywhere, but we’ll just be using the home directory for now.
cd ~
mkdir hugo
cd hugo/
Install using apt
The most basic and simplest way is to use Ubuntu’s built in apt command. Run the following command to install Hugo using apt:
sudo apt update
sudo apt install hugo
And that’s it!
Install directly from github
This is a little more complicated. Depending on your version of Ubuntu, you may get an older version of hugo which can cause compatibility issues with some themes. To do ths, follow the steps below.
First, grab the latest version of hugo from their github. You’ll want to find the one that contains the relevant architecture for your system - arm64 or amd64. Make sure to select the Linux one and get the tar.gz. Right-click this and select copy link. Run the following commands (this will be using the link to the latest version at the time of writing)
wget https://github.com/gohugoio/hugo/releases/download/v0.148.2/hugo_0.148.2_linux-amd64.tar.gz
tar -xzf hugo_*
sudo mv hugo /usr/local/bin/hugo
hash -r
Confirm installation
To confirm hugo is installed and running, run the following command.
hugo version
This should print an output of the version.
Step 2. Create first site
Now that it’s all up and running, make sure you’re in your working directory and run the command below to create your site.
cd ~/hugo
hugo new site mysite
Replace mysite above with the desired name of your site, such as blog. We’ll be using mysite for this.
Step 3. Install theme
Browse for a theme here. Once you find one you like, run the following commands to install it.
cd ~/hugo/mysite
git init
git submodule add https://github.com/user/example-theme themes/example-theme
Replace the url and name above with the url and name of the theme selected. For example, the theme Blowfish by nunocoracao
git submodule add https://github.com/nunocoracao/blowfish themes/blowfish
This will copy the theme down into the themes/ directory - full path should be ~/hugo/mysite/theme/
Step 4. Edit config file
Once that’s installed, time to edit the config file. This can be either hugo.toml, hugo.yaml, config.toml or config.yaml. Use what’s there by default. I’ll provide an example config for both yaml and toml formats. Feel free to edit this as you want. Make sure to update the baseURL to whatever you’ll be using for your website. If this isn’t set property, links and static assets may break when deployed.
Config example - toml
baseURL = "http://blog.example.com/"
languageCode = "en-us"
title = "My Blog"
theme = "name-of-theme"
[params]
mainSections = ["posts"]
description = "A Hugo blog"
enableDarkMode = true
favicon = "favicon.ico"
[menu]
[[menu.main]]
identifier = "about"
name = "About"
url = "/about"Config example - yaml
baseURL: "http://blog.example.com/"
languageCode: "en-us"
title: "My Blog"
theme: "name-of-theme"
params:
mainSections:
- "posts"
description: "A Hugo blog"
enableDarkMode: true
favicon: "favicon.ico"
menu:
main:
- identifier: "about"
name: "About"
url: "/about"Step 5. First post!
Now it’s time to make your first post. We do this by running the following command:
hugo new posts/my-first-post.md
nano content/posts/my-first-post.md
Here’s an example of a first post:
+++
title = 'My first post'
date = 2025-07-27
draft = false
description = "The first post of many!"
tags = ["blog", "intro"]
categories = ["blog posts"]
+++
This is my first post. Hello, world!
Step 6. Build website
To build the site, simply issue the below commands
cd ~/hugo/mysite
hugo
It’s important that this is run in the base directory of your site - from this guide we’ve been using ~/hugo/mysite, but if you’ve changed that make sure you’re in the base directory of your site.
Step 7. Serve with web hosting software
Now that the site’s been built, all the files have been placed in the public directory - ~/hugo/mysite/public/*
We’ll have to move this to where your website can access them and servce the pages. Create a directory and copy the files as below.
sudo mkdir -p /var/www/mysite
sudo cp -r ~/hugo/mysite/public/* /var/www/mysite
Now depending on what you’re using to host the website, you will need to set up a config file. I’ll provide some basic examples for nginx and apache.
Nginx config
For Nginx, you’ll need to create the config file in /etc/nginx/sites-available. Run the commands below to do this:
sudo nano /etc/nginx/sites-available/blog.example.com
Then use the example config file below:
server {
listen 80;
server_name blog.example.com;
root /var/www/mysite;
index index.html;
location / {
try_files $uri $uri/ =404;
}
}
Create a symbolic link to enable to site.
sudo ln -s /etc/nginx/sites-available/blog.example.com /etc/nginx/sites-enabled/blog.example.com
Test to make sure the config is all good
sudo nginx -t
Then restart Nginx
sudo systemctl restart nginx
Apache config
First, let’s make sure the permissions are all good
sudo chown -R www-data:www-data /var/www/mysite
sudo chmod -R 755 /var/www/mysite
Now we need to create the config file for Apache.
sudo nano /etc/apache2/sites-available/mysite.conf
Use the example config below
<VirtualHost *:80>
ServerName blog.example.com
DocumentRoot /var/www/mysite
<Directory /var/www/mysite>
Options Indexes FollowSymLinks
AllowOverride All
Require all granted
</Directory>
ErrorLog ${APACHE_LOG_DIR}/mysite_error.log
CustomLog ${APACHE_LOG_DIR}/mysite_access.log combined
</VirtualHost>
Now run these commands to enable the site and restart apache
sudo a2ensite mysite.conf
sudo systemctl reload apache2
Step 8. Site now live
With the configuration files created and services restarted, your website should now be live! Visit its URL to view the main page and your first blog post.
All that’s left now is to create more posts and pages! Make sure to check out your theme’s demo or example sites if they have them to see everything that’s available.
Optional - Simple deploy script
The only issue I found with Hugo was it was a bit of an annoyance to build the site, copy the public directory, then restart the webhost. So, I put together a couple of quick scripts to do this. I created this script in the base directory of the site, ~/hugo/mysite/deploy.sh. Run the command below to create the script file.
nano ~/hugo/mysite/deploy.sh
nginx script
#!/bin/bash
# Exit immediately on error
set -e
# Define paths
HUGO_SITE_DIR="$HOME/hugo/mysite" # change as needed
WEB_ROOT="/var/www/mysite"
echo ">> Building Hugo site..."
cd "$HUGO_SITE_DIR"
hugo
echo ">> Copying files to $WEB_ROOT..."
sudo cp -r public/* "$WEB_ROOT"
echo ">> Restarting Nginx..."
sudo systemctl restart nginx
echo ">> Done. Site should be live."
Save this script and then make it executable.
sudo chmod +x ~/hugo/mysite/deploy.sh
apache script
#!/bin/bash
# Exit immediately on error
set -e
# Define paths
HUGO_SITE_DIR="$HOME/hugo/mysite" # change as needed
WEB_ROOT="/var/www/mysite"
echo ">> Building Hugo site..."
cd "$HUGO_SITE_DIR"
hugo
echo ">> Copying files to $WEB_ROOT..."
sudo cp -r public/* "$WEB_ROOT"
echo ">> Restarting Apache..."
sudo systemctl restart apache2
echo ">> Done. Site should be live."
Save this script and then make it executable.
sudo chmod +x ~/hugo/mysite/deploy.sh
Now whenever you finish creating a post or making a change you can just run ./deploy.sh from your website’s working space directory. This also helps prevent any possible issues from running hugo in the wrong directory.
Endnote
That’s it for this guide. I hope it was helpful to some! Before switching to Hugo, I was manually editing .html files for every post—this change has been a massive time-saver!