This page looks best with JavaScript enabled

Serving Hugo from a non-root location with Nginx

 ·  ☕ 4 min read

About a year and a half ago, I wrote a post titled “Serving Flask from a non-root location with Nginx.” Doing the same thing for a Hugo blog is significantly less complicated, but it still took me some time to figure out, and as far as I could tell is not particularly documented, so I’m going to write up what I did.

In the example I’ll use throughout this post, my root domain is and I’m adding /fantasy to the path.


In nginx.conf (located at /etc/nginx/) we need to locate where our output directory is going to be. Because I have two Hugo sites on this server, I have the following (much of the file is omitted for brevity):

http {
	server {
		location /fantasy {
			root /var/www/;

		location / {
			root /var/www/;

It’s important that there’s no trailing slash after /fantasy; if that were included then would resolve, but would 404.

The paths /var/www/ and /var/www/ are my two output directories. The latter is for this blog and already existed; the former is the new one that I created for my new site, the one we’re setting up in this example. These folder names aren’t special, but you should choose names that are clear in their meaning.

After making changes to your nginx.conf, you will have to restart nginx:

sudo systemctl reload nginx


  • You can find nginx logs in /var/log/nginx. Here’s more information about nginx logs.
  • If you want to be absolutely certain that your nginx changes went through, you can restart your server (though if this works, and reloading systemctl didn’t, you should figure out why!).


Setting the output directory

The first thing I did was to create the output directory, the path we set up in nginx above. But, to make the path work, the output directory isn’t actually just /var/www/ but rather /var/www/ (note the extra sub-folder at the end).

After creating a new Hugo project I then aliased (I use the Fish shell, not bash):

alias fantasy 'cd ~/fantasy/; hugo version; hugo -d /var/www/'

This brings me to the correct project, prints the current Hugo version, and then builds the project to the right output directory. So when I want to build my site, I just type fantasy from any directory, and it takes me to the right location and builds my output to the right location.

Setting up config.toml

You will need to set the following two parameters:

baseurl = "/fantasy/"
canonifyurls = true

They should go at the top of your file, not underneath any heading.

The canonifyurls variable makes CSS, Javascript, and images point to the right place. Without this variable set, Hugo will attempt to look for assets in the base namespace instead of your subdomain.


  • If images are missing, use the element inspector to check where they’re attempting to load from.
  • You can also use the nginx logs to check for any errors.
  • The Network tab in dev tools in your browser can help you: check for anything loading with a 404 status and see what the document is. (You have to load or refresh a page after opening the network tab for it to work.) Check what file paths Hugo is expecting compared to what you want it to be expecting. This is comparable to what the nginx error logs would tell you, but it might be easier to use.
  • Your Hugo output folder has a file called sitemap.xml; check if this is what you expect it to be.


To set up Hugo at a non-root location, you need to:

  • Set up your nginx.conf
  • Set up the output directory properly when you build your site (there are a number of ways to do this; I did it in an alias when I build my site)
  • Set two parameters in your config.toml

To troubleshoot, take advantage of dev tools in your browser and/or nginx logs.

Share on

River is a developer most at home in MediaWiki and known for building Leaguepedia. She likes cats.

What's on this Page