Hi, I’m trying to move an old website from nginx to caddy. One of the things that needs translating are the dozens of rewrite rules that have accumulated.
The case I’m currently looking at is our URL shortener. This rewrites certain patterns such as https://small.uk/@Simon
to https://realwebsite.uk/profile.php?username=Simon
. In nginx, this is implemented as single rewrite rules, for example:
rewrite ^/@([\w-]+)$ https://realwebsite.uk/profile.php?username=$1 redirect;
In Caddy, I’ve tried to reproduce this using a combination of path_regexp
and rewrite
to rewrite the paths, then redir
to finish up and redirect to the main domain. However, I’ve not been able to use the rewritten uri inside the redir directive, and it’s confusing me why this is the case.
To test, I’ve produced the following config:
http://short.local {
@simple_matcher path_regexp /foo$
rewrite @simple_matcher /bar
respond http://www.local{uri}
}
Fetching this using curl gives the following response:
> GET /foo HTTP/1.1
> Host: short.local
> User-Agent: curl/8.9.1
> Accept: */*
>
< HTTP/1.1 200 OK
< Content-Type: text/plain; charset=utf-8
< Server: Caddy
< Date: Sun, 01 Jun 2025 17:59:24 GMT
< Content-Length: 20
<
http://www.local/bar
As expected, the rewrite directive has replaced foo with bar, and I can then redirect by combining the other domain and rewritten uri.
However, when I then try to redirect to this url, simply by using redir
:
http://short.local {
@simple_matcher path_regexp /foo$
rewrite @simple_matcher /bar
redir http://www.local{uri}
}
Instead of the Location header using the expected /bar path, it uses the original /foo path, as seen in curl:
> GET /foo HTTP/1.1
> Host: short.local
> User-Agent: curl/8.9.1
> Accept: */*
>
< HTTP/1.1 302 Found
< Location: http://www.local/foo
< Server: Caddy
< Date: Sun, 01 Jun 2025 18:02:21 GMT
< Content-Length: 0
<
Now, I don’t doubt there are other (albeit less concise) ways of achieving what I want, but before I try those, I’d like to understand why respond
does what I expect, but redir
doesn’t.
Version and environment info:
Caddy v2.10.0
Dockerfile:
FROM caddy:2-builder AS builder
RUN xcaddy build
FROM caddy:2
COPY --from=builder /usr/bin/caddy /usr/bin/caddy
compose.yml:
services:
caddy:
build: ./caddy/build
ports:
- "80:80"
- "443:443"
volumes:
- ./caddy/conf:/etc/caddy
- caddy_data:/data
- caddy_config:/config
volumes:
caddy_data:
caddy_config:
Running on Windows 10, Podman, WSL2