Serve and route requests
Strip a path prefix
Choose handle_path when an upstream or file tree should receive the request path without its matched prefix, and plain handle when it should not.
Sometimes you mount something under a path prefix. Docs under /docs/, an API under /api/. But the thing you’re serving doesn’t know about that prefix. A folder of HTML files has no docs/ subfolder inside it. An upstream app expects /users, not /api/users.
handle_path solves exactly this. It works like handle, with one addition: it strips the matched prefix from the path before running its handlers.
With a file server
Let’s mount a manual under /docs/:
:8080 {
handle_path /docs/* {
root * ./manual
file_server
}
}
Create a file and request it:
mkdir -p manual
echo '<h1>Getting started</h1>' > manual/start.html
curl http://127.0.0.1:8080/docs/start.html
You get the heading back. The request path was /docs/start.html. Inside the block, the path became /start.html, so file_server looked for manual/start.html.
Without the stripping, Caddy would look for manual/docs/start.html and return a 404, even though your file is right there.
With a proxy
The same logic applies to proxying:
:8080 {
handle_path /api/* {
reverse_proxy 127.0.0.1:3000
}
}
A request for /api/users reaches the upstream as /users. The prefix stays your routing concern. The app never learns it exists, so you can move it to /v2/ tomorrow without touching application code.
Pick the right one
Use handle when the downstream expects the full original path. Use handle_path when the prefix is only a mounting point.
Getting this wrong produces 404s that are confusing to debug. The path Caddy looks up is not the path in your browser, so everything looks right and nothing works. When in doubt, check what actually arrived. For a file server, read the runtime log. For a proxy, log the request path inside your application.
Don’t stack rewrites
Caddy also has a rewrite directive, and you could strip a prefix with it. Resist the temptation to pile up rewrite rules until a request happens to work. handle_path states your intent in one word. A stack of rewrites hides it, and the next person to read the file has to simulate them in their head.
Try this on your own: swap handle_path for handle in the docs example and request the same URL. Watch the 404, then look at which file Caddy tried to open.
Lesson completed