404 Not Found in Hugo

Pipeline

This is the one of posts about tips and tricks I used when setting up Hugo blog.

I wanted to create a 404 page. Of course, I googled something like "404 page hugo" and of course I ended with official docs.

Hugo's official documentation about this topic is pretty poor in terms of details.

I have a static site that is hosted by Nginx which is started inside Docker container.

So there are 3 steps to implement this idea.

First of all, we need to create the page itself using html templating engine of Hugo. Then we need to configure a server (Nginx) to use this page in case of a 404 error. As bonus, although required for me, I need to put a configured server inside Docker image which is uploaded to the registry.

Hugo

Let's see what docs say. Create 404.html template inside layout/404.html

{{ define "main"}}
    <main id="main">
      <div>
       <h1 id="title"><a href="{{ "/" | relURL }}">Go Home</a></h1>
      </div>
    </main>
{{ end }}

You can use any markup you want here. It fully supports the templating engine you use for any Hugo template.

Moreover, you can delegate creating layouts/404.html to your custom theme as did I. This way your specific blog will be clean of any layouts like this.

Nginx

There's an Automatic Loading part of the docs page. Here you can see a general approach for some well-known servers.

Nginx. You might specify error_page 404 /404.html; in your nginx.conf file.

Where is this config and how to update it?

By default, Nginx uses config which is located here: /etc/nginx/conf.d/default.conf. I just used its default version and changed a bit like this:

server {
    listen       80;
    listen  [::]:80;
    server_name  localhost;

    location / {
        root   /usr/share/nginx/html;
        index  index.html index.htm;
    }

    error_page 404 /404.html; # Here and below is 404 error handling docs tried to describe
    location = /404.html {
        root   /usr/share/nginx/html;
    }

    error_page   500 502 503 504  /50x.html;
    location = /50x.html {
        root   /usr/share/nginx/html;
    }

}

Docker

Now we know that we need to change Nginx config. Nginx is started in Docker container for our Docker image. I have Dockerfile on my Hugo project root, it's a config that is used to create Docker image. Copy and paste Nginx config from a previous step in the same directory as Dockerfile. I named it nginx.conf. Then update Dockerfile like this:

FROM nginx:alpine
COPY ./public /usr/share/nginx/html
 
# Literally copy nginx.conf file from the Dockerfile directory into /etc/nginx/conf.d/default.conf of the container
COPY ./nginx.conf /etc/nginx/conf.d/default.conf

EXPOSE 80

Result

You can see the "demo" on this site. Just enter any invalid URL into the address bar, and you'll see my 404 page content.

For more specific details you may want to check out my previous post about complete blog deployment pipeline I set up.