skip to content
blog.metters.dev

Configuring Client-Side Routing for React SPA with Caddy

/ 2 min read


DISCLAIMER

The blog post was written by me. However, to solve this issue, I consulted a LLM, which was quite helpful in writing this.


I was building a static site with React and React Router. Unfortunately, there were two issues:

  1. It crashed, when the site was reloaded
  2. It was not possible to access sub-pages directly, e.g. blog.metters.dev worked, but blog.metters.dev/posts did not.

This is because the request is handled on server-side instead of client-side. The server-side routing does not know about the subpage and returns 404. To solve this, Caddy must be configured to serve the main index.html file for all incoming requests, except for static assets. Kind of like a catch-all route.

There are two directives that need to be added and configured, in order to fix this issue: file_server and try_files.

Caddy directive file_server

Caddyfile
blog.metters.dev {
root * /var/www/html/blog.metters.dev
file_server
try_files {path} {path}/ /index.html
}

When the root of the website or a directory is requested, Caddy will attempt to serve an index file. The defaults are index.html or index.txt. This directive should be set anyway, if Caddy is serving a static site.

Caddy directive try_files

Caddyfile
blog.metters.dev {
root * /var/www/html/blog.metters.dev
file_server
try_files {path} {path}/ /index.html
}
  • {path} On reload try to serve the file at the exact path.
  • {path}/ If that fails, append a trailing slash to the requested path. If a default HTML file is available the request succeeds.
  • /index.html Otherwise, return index.html as fallback.

With these two directives, Caddy ensures that page reloads are routed correctly.


Resources