Help needed with reverse proxy as replacement for apache

1. Caddy version (caddy version):


2. How I run Caddy:

at the moment, I have the Caddyfile in the same folder and run
sudo caddy run Caddyfile

a. System environment:

Ubuntu 18.04

b. Command:

sudo caddy run Caddyfile

c. Service/unit/compose file:

paste full file contents here

d. My complete Caddyfile or JSON config: {
reverse_proxy localhost:8080
} {
reverse_proxy / localhost:8088/exist/apps/tls-app/

3. The problem I’m having:

I am currently running the second site behind apache with the following vhost configuration:

RewriteEngine on
ProxyPass / http://localhost:8088/exist/apps/tls-app/
ProxyPassReverse / http://localhost:8088/exist/apps/tls-app/
ProxyPassReverseCookieDomain localhost
ProxyPassReverseCookiePath /exist /
RewriteRule    ^/(.*)$ /$1 [PT]

The effect is that when I visit the site at, the server running locally on port 8088 is called, with the path /exist/apps/tls-app added before the request path, so
a call to

results in a call to


4. Error messages and/or full log output:

There is no error message, but the path called seems to be only

5. What I already tried:

I have tried several ways to form the reverse_proxy path, but nothing solved the problem.
The configuration did work nicely, but now I want to switch to caddy because I want to add the conf for another vhost at

6. Links to relevant resources:

This is the relevant documentation for the server I am using:

First, remove the / matcher. That will only match on exactly / and nothing else. Caddy uses exact path matching. Omitting it is the same as *, meaning match everything.

Second, Caddy v2’s proxy handler doesn’t support rewrites on its own. Instead, you need to use a rewrite handler to change the path before proxying. Looks like this:

rewrite * /exist/apps/tls-app{uri}

Just put that before your proxy, and remove the path portion from the proxy. Should work just fine.

Dear Francis,
Thank you so much for your answer. This is very helpful, as I now understand why none of the reverse_proxy examples I found had a path component!
My system is almost working now, except for one small glitch:
If no document is specified, that is if the URI ends with a slash or has no document ending, I will need to request the “index.html” document.
I tried to add a try_files statement like this: {
rewrite * /exist/apps/tls-app/{uri}
try_files {uri} /index.html?{query}&p={path}
reverse_proxy  localhost:8088

But this does not have the effect I need.
Any help appreciated,

try_files doesn’t make sense for your site because you don’t have a root defined. That’s meant to read files from disk to see if they exist.

I think what you want is more like this?

@noIndex path */
rewrite @noIndex {path}index.html

rewrite * /exist/apps/tls-app{uri}

Note that the omission of / besides the placeholders is intentional, because in both cases, they include the / at their boundaries. {uri} always starts with a /, and since we matched path as ending with a /, we know it will already have it.

Also to note, this relies on the Caddyfile directive sorting logic. Directives will be ordered based on the length of their path matchers. Since the first one has a path matcher, it will be ordered first; the second rewrite doesn’t have a path matcher so it will be ordered last. If you were to add another rewrite for some other reason, be aware that if it uses a path longer than 2 characters, it will be ordered before your index.html. You can solve that by wrapping them in route { } which will guarantee the order they’re handled.

1 Like

Hmm, unfortunately this does not solve my problem, calling the domain without any path component still does an internal direct at some point, which is adding an unwanted /exist to the request (this is coming from the upstream server).
I also realized there is another problem, with the cookies used for maintaining login state:
In apache I have

    ProxyPassReverseCookieDomain localhost
    ProxyPassReverseCookiePath /exist /

but I have no idea how to achieve the same with caddy.
all the best, Chris

I don’t understand the problem. What do you see if you make the request with curl -v?

Looking at the exist-db docs, I think you should be looking at the nginx example instead of Apache. Caddy is more similar to nginx than to Apache.

Maybe sending along the nginx-request-uri header with the value from Caddy’s {http.request.orig_uri} placeholder will be enough to make it work.

rewrite * /exist/apps/tls-app{uri}
reverse_proxy localhost:8088 {
    header_up nginx-request-uri {http.request.orig_uri}

That’s the only thing from the nginx example in their docs that Caddy doesn’t do automatically. The exist app might be looking for that header to decide how to handle its requests.

Anyways I’m just making guesses at this point. If it still doesn’t work, please elaborate and be specific about the behaviour you’re seeing, with logs etc.

1 Like

Still working on this issue. I tried your solution, but that did not solve the problem, the nginx headers do not have any special meaning within exist-db. The crucial point I think is that the path in the cookie is wrong, for the login to work I need to have the root path “/” instead of the path from the backend, which is “/exist”. So while going back through caddy, I need to instruct it to remove this part.
I still have the production server running behind apache, so I made a comparison of the cookies as seen in the Firefox developer tools.

I hope this provides the information needed to solve this problem. Thank you for your attention.
All the best, Chris

It’s not really Caddy’s job to modify cookies on the way back downstream. Caddy can do it, but that’s not the right solution here.

You’ll need to figure out why exist-db thinks the base path is /exist whereas it doesn’t with apache or nginx.

You’re more likely to find a solution by asking the exist-db maintainers, they understand their app better than I could.

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