How to Host a Static Website with Hugo on Your Linux Server (Fast, Free, No Database)

WordPress (tutorial 30) is right when several people edit, plugins matter, or the site needs comments and forms. For a personal blog, a project site or documentation, a static site is simpler and safer: plain HTML files, nothing to hack, nothing to update, served by Nginx or Caddy at silly speed. Hugo turns Markdown files into that site in milliseconds, and a push to Gitea can rebuild and publish it automatically.
Quick reference
| Task | Command |
|---|---|
| Install Hugo (on the server) | sudo apt install hugo -y (or the newer .deb from GitHub) |
| New site | hugo new site mysite && cd mysite |
| Theme | git submodule add https://github.com/adityatelange/hugo-PaperMod themes/PaperMod |
| New post | hugo new posts/first-post.md |
| Preview | hugo server -D --bind 0.0.0.0 → http://server-ip:1313 |
| Build | hugo --minify → public/ |
| Serve | Nginx/Caddy root → /var/www/mysite |
1. Install Hugo
sudo apt install hugo -y
hugo version
Themes often want a recent version; if Ubuntu's is old, grab the hugo_extended_*_linux-amd64.deb from Hugo's GitHub releases and sudo apt install ./hugo_extended...deb (tutorial 63).
2. Make a site
mkdir -p ~/sites && cd ~/sites
hugo new site mysite
cd mysite
git init
git submodule add https://github.com/adityatelange/hugo-PaperMod themes/PaperMod
nano hugo.toml
baseURL = "https://blog.example.com/"
languageCode = "en-gb"
title = "My Blog"
theme = "PaperMod"
[params]
defaultTheme = "auto"
ShowReadingTime = true
PaperMod is a clean, fast default; themes.gohugo.io has hundreds more.
3. Write a post
hugo new posts/hello-world.md
nano content/posts/hello-world.md
---
title: "Hello World"
date: 2026-11-05
draft: false
tags: ["homeserver"]
---
First post. **Markdown** works, so do images: 
Images go in static/images/. That's the whole content workflow: a folder of Markdown files.
4. Preview
hugo server -D --bind 0.0.0.0 --baseURL http://192.168.1.50
Open http://192.168.1.50:1313. It rebuilds the instant you save a file. -D includes drafts. Ctrl+C to stop.
5. Build and serve
hugo --minify
sudo mkdir -p /var/www/mysite
sudo rsync -a --delete public/ /var/www/mysite/
Nginx (tutorial 26):
server {
listen 80;
server_name blog.example.com;
root /var/www/mysite;
index index.html;
location / { try_files $uri $uri/ =404; }
location ~* \.(css|js|jpg|png|webp|svg|woff2)$ { expires 30d; add_header Cache-Control "public"; }
}
Or Caddy (tutorial 57): blog.example.com { root * /var/www/mysite file_server encode gzip }. Add HTTPS, or publish it through a Cloudflare Tunnel (tutorial 109) with no port forward at all.
6. Publish with a git push
Push the site's source to Gitea (tutorial 45) and let the server rebuild on each push. Simplest: a post-receive hook in the bare repository on the server, or — if you write on a laptop — a tiny script on the server run by a Gitea webhook via n8n (tutorial 77):
#!/bin/bash
# /usr/local/bin/deploy-blog.sh
set -e
cd ~/sites/mysite
git pull --quiet
git submodule update --init --quiet
hugo --minify --quiet
rsync -a --delete public/ /var/www/mysite/
curl -fsS -o /dev/null https://hc.example.com/ping/UUID # healthchecks, tutorial 104
Write a post on the laptop, git push, and the live site updates in a second. Gitea Actions can do the same with a workflow if you prefer CI.
7. Comments, search, forms
Static sites don't do those alone; add them as separate tiny services: Isso or Remark42 for self-hosted comments, Pagefind for client-side search (runs at build time), and a form endpoint via n8n. Or keep it simple and link to email.
Troubleshooting
Site builds but CSS is missing on the live site. baseURL doesn't match the real address, or you served public/ from a subfolder. Set baseURL exactly.
Theme errors about Hugo version. Install the newer extended .deb.
New post doesn't show. draft: true and you built without -D, or the date is in the future.
Changes don't appear after deploy. Browser cache from the expires header; hard-refresh. Hugo fingerprints assets if the theme supports it.
Wrapping up
Markdown in a folder, one theme, hugo --minify, a web server pointing at the output. A site that can't be hacked, loads instantly, costs nothing to run and updates with git push — for most personal sites it's the better answer, and it's a good excuse to use half the things you've built in this series.
