Reverse proxy to a localhost isn't behaving as I expect

1. The problem I’m having:

I am trying to reverse proxy a specific path to a Node.js server running locally. The Node server is listening on 127.0.0.1:51501, and I can access in the browser it if I use that address directly.

However, when I use Caddy to reverse_proxy to it, it seems to be ignored while my less specific “respond” directive takes over. If I remove the “respond” directive, then all I get is a blank white screen in my browser.

2. Error messages and/or full log output:

There are no errors.

3. Caddy version:

v2.8.4 h1:q3pe0wpBj1OcHFZ3n/1nl4V4bxBrYoSoab7rL9BMYNk=

4. How I installed and ran Caddy:

brew update
brew install caddy

a. System environment:

Mac OS 14.4.1

b. Command:

caddy run

c. Service/unit/compose file:

N/A not using Docker

d. My complete Caddy config:

local.mycomputer.net {
	tls internal

	reverse_proxy /dev/hello-world* 127.0.0.1:51501

	respond "what??"
}

Note that I am using a cosmetic localhost by modifying my /etc/hosts file. My /etc/hosts file looks like this:

127.0.0.1	localhost
255.255.255.255	broadcasthost
::1             localhost
127.0.0.1	local.mycomputer.net

5. Links to relevant resources:

N/A

Directives are not executed per the order they appear in in the Caddyfile, rather per a pre-defined order. See the default order here:

The order can be overriden using the route directive, which obeys the order directives appear in. Another trick is to use the handle directive to create mutually-exclusive handler blocks.

The crux of the matter is the question of whether you want route-first approach or behavior-first. Matt discusses the differences, pros, and cons in this Wiki post.

1 Like

My expectation is that the directive with the most specific matcher will be the one that is executed while all other directives get ignored – regardless of order. Is this wrong?

I expect my reverse_proxy directive that has a path matcher to be more specific than my generic respond directive that matches all paths. Therefore I expect the respond directive in my Caddyfile to be ignored.

Unfortunately, yes, your expectation wasn’t accurate. It is true that greater specificity matters in certain circumstances, but not universally so.

As a rule of thumb, path specificity matters between duplicates of the same object. Site blocks, for example, sort by length of the site address - so you can expect foo.example.com to match before *.example.com. Multiple reverse_proxy instances are another example - you can expect reverse_proxy /api http://api to match before reverse_proxy http://upstream does as the path matcher is sorted by specificity.

Any duplicated directives that don’t have a path matcher (implicit or otherwise) would be sorted in order of appearance in the Caddyfile.

But respond will always operate before reverse_proxy if it can, as per the directive order, meaning the reverse_proxy is the ignored directive in your example.

The link Mohammed supplied outlines how it works:

For ease of use, the Caddyfile adapter sorts directives according to the following rules:

  • Differently named directives are sorted by their position in the default order.
    […]
  • Same-named directives are sorted according to their matchers.
    […]
4 Likes

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