Skip to content

No trailing slash messes up MkDocs relative link

I had to share the blog homepage as ariesta.id/blog/.

There's an updated config below the post.

Now, I can share it as ariesta.id/blog (without trailing slash).

Static pages built by MkDocs allow users accessing the path /blog to be served with the content of /blog/, but the relative links inside the blog homepage is written like this: 2025/01/04/flask-google-login. (I set this blog on Coolify, so this maybe a specific behavior, not caused by MkDocs.)

However, when the browser interprets that link, it resolves to /2025/01/04/flask-google-login, which, if opened, breaks the blog.

There is no problem if users open the blog homepage at /blog/, since the child path will be interpreted as /blog/2025/01/04/flask-google-login (the correct slug built by MkDocs).

Luckily, Coolify uses NGINX and I chose to force trailing slash for each path.

rewrite ^([^.]*[^/])$ $1/ permanent;

Source: Bob Monteverde's answer on Stack Overflow.


Update

I'm not sure why, but suddenly the server started redirecting non-trailing slash URLs to something like ariesta.id:3000/blog/. My stack is Coolify (with Caddy and Traefik), Dockerfile, Nginx, Mkdocs and so on. So maybe that's complicating things. Serves me right for relying on so many technologies to serve a static blog, huh?

So, naturally, I asked DeepSeek-R1 (and subsequently V3, because R1 was overthinking). Here's the new setting:

if (!-d $request_filename) {
    rewrite ^([^.]*[^/])$ $scheme://$host$1/ permanent;
}

I don't fully understand it, but let’s try to break it down. First line means "if the requested path is not a directory" (according to V3).

For the second line: rewrites any URLs that don’t end with a / (that's what the regex means) into the following format.

$scheme://$host$1/

In this context: - $scheme is the protocol (e.g., https),
- $host is the domain, and
- $1 is the regex match that we want to rewrite, appended with a /.

Read here to setup MkDocs for blogging.