Using Caddy as a reverse proxy with multiple subdirectories and rewrites

1. Caddy version (caddy version):

v2.4.6

2. How I run Caddy:

systemctl start caddy

a. System environment:

Debian 11, not docker

d. My complete Caddyfile or JSON config:

psono.beeswax.eu {
    reverse_proxy localhost:10101
    reverse_proxy /server localhost:10100
    reverse_proxy /portal/* localhost:10102
}

3. The problem I’m having:

I’m using a self-hosted password management service called Psono. It worked perfectly under nginx using the example config file provided in their documentation.
Now I’m migrating from nginx to caddy, but I simply can’t wrap my head around the configuration with these many added headers and rewrites.

Psono has two subdirectories. /server would lead to the password-management service itself (not a webpage), and /portal should have to lead to the admin page (and it is actually /portal/login, but nginx took care of redirecting.
The latter works sort of… now I have to explicitly write psono.beeswax.eu/portal/login to access the login screen of the admin panel.
The former doesn’t work at all, if I try to login from the main page it states Server offline - it’s online, if I switch back to nginx, it is working.

My other sites - which were only need a simple reverse_proxy - works perfectly.

4. Error messages and/or full log output:

5. What I already tried:

I tried to format the caddyfile as it is in nginx’s configfile, but ultimately failed…

6. Links to relevant resources:

The working nginx example at Psono’s site

Hi :wave:

path matchers are exact since Caddy v2.
So

reverse_proxy /server localhost:10100

will only match /server but not /server/ or /server/something.else.

reverse_proxy /portal/* localhost:10102

on the other hand matches /portal/ and /portal/something.else but not /portal.
If you want to match /portal (without a trailing slash) too, you could write it as

reverse_proxy /portal* localhost:10102

or

## https://caddyserver.com/docs/caddyfile/matchers#named-matchers
@portal path /portal/* /portal
reverse_proxy @portal localhost:10102

The reference nginx config you shared reads:

location /server {
    rewrite ^/server/(.*) /$1 break;
    proxy_pass          http://localhost:10100;

Which strips /server/ from its uri before passing it to the upstream.

Caddy has a dedicated uri (Caddyfile directive) — Caddy Documentation, and it’s handle_ shorthand handle_path (Caddyfile directive) — Caddy Documentation for that:

handle_path /server* {
  reverse_proxy localhost:10100
}

So everything put together would look something like that:

psono.beeswax.eu {
  reverse_proxy localhost:10101
  handle_path /server* {
    reverse_proxy localhost:10100
  }
  reverse_proxy /portal* localhost:10102
}
Caddyfile with diff
  psono.beeswax.eu {
    reverse_proxy localhost:10101
-   reverse_proxy /server localhost:10100
+   handle_path /server* {
+     reverse_proxy localhost:10100
+   }
-   reverse_proxy /portal/* localhost:10102
+   reverse_proxy /portal* localhost:10102
  }
2 Likes

FWIW, I’d write it like this (for mutual exclusivity)

psono.beeswax.eu {
	handle_path /server* {
		reverse_proxy localhost:10100
	}

	handle /portal* {
		reverse_proxy localhost:10102
	}

	handle {
		reverse_proxy localhost:10101
	}
}

I think it’s easier to read – you can clearly see top-down how a request will be handled. The handle without a matcher will catch any request that wasn’t otherwise matched by the previous 2 handles.

2 Likes

It works!

Thank you very much for both of you!

2 Likes

This topic was automatically closed after 30 days. New replies are no longer allowed.