Can't translate the Caddy v1 directive proxy with the without option to its equivalent for v2

1. Caddy version (caddy version):

2.0.0

2. How I run Caddy:

Caddy binary for windows 64bit .\caddy.exe run

a. System environment:

Windows 10 64-bit

b. Command:

 .\caddy.exe run
2020/05/08 09:29:22.472 e[34mINFOe[0m   using adjacent Caddyfile
run: adapting config using caddyfile: Caddyfile:4: unrecognized directive: matcher
PS D:\Federico\Projects\caddy_2.0.0_windows_amd64>

d. My complete Caddyfile or JSON config:

Caddyfile v2

example.test {
	reverse_proxy / localhost:3000
	
	matcher a {
		path /api
	}
	
	rewrite match:a /
	
	reverse_proxy  match:a localhost:3001
	}

	tls off
}

Caddyfile v1 that I am trying to port to v2

example.test {
    proxy / localhost:3000 {
        transparent
    }
	
    proxy /api localhost:3001 {
	without /api
    }

    tls off
}

3. The problem I’m having:

  1. The matcher for some reason isn’t recognized, contrary to what I learnt here :zipper_mouth_face:

4. Error messages and/or full log output:

2020/05/08 09:29:22.472 e[34mINFOe[0m   using adjacent Caddyfile
run: adapting config using caddyfile: Caddyfile:4: unrecognized directive: matcher

5. What I already tried:

I tried to learn what has been discussed

But overall so far I have been unable to translate my v1 Caddyfile to the v2 format, overall I’m smashing my head like never before. I loved Caddy for its simplicity and learnt how to setup the v1 Caddyfile in minutes while now it’s been two days that I’m browsing the forum, the documentation and GitHub to achieve the same in v2. (Sorry for the rant, I’m burned out for not being able to accomplish such a simple setup in v2).

If possible I’d rather not use the JSON configuration as of now, but I’m trying to understand it, eventually I know I will need it.

example.test {
 reverse_proxy / localhost:3000
 reverse_proxy /api localhost:3001
}
1 Like

@Maxiride, the post you referred to is about 6 months old, from the early betas of Caddy 2. You can find the current docs for matchers in our documentation: Request matchers (Caddyfile) — Caddy Documentation

It’s a much nicer @-block syntax now, but you don’t need that when it’s only a path matcher: you can still define those inline. (See the link for details.)

Here’s an upgrade guide that will help you update your proxy directives to reverse_proxy: Upgrading to Caddy 2 — Caddy Documentation

No need for that! Just read the docs :slight_smile:

I think it’s because you didn’t read the docs or try the upgrade guide? You should go in with a clean slate into v2, since it’s different from v1. But you’ll find that it’s familiar once you try it.

Here’s an upgrade guide that will help you update your proxy directives to reverse_proxy : Upgrading to Caddy 2 — Caddy Documentation

I did read that part and the section on proxies says:

The without subdirective has been removed because rewrite hacks are no longer necessary in v2 thanks to improved matcher support.

I was aware it had been removed however I have no clue about what rewrite hacks the documentation refers to in relation to the v1 without option and that didn’t give me any insight. Following the rewrite hacks link it leads to Upgrading to Caddy 2 — Caddy Documentation which didn’t shed light on how to re-implement the without behaviour.

I think it’s because you didn’t read the docs or try the upgrade guide? You should go in with a clean slate into v2, since it’s different from v1. But you’ll find that it’s familiar once you try it.

Tried the upgrade guide and while I learnt the new blocks syntax and formatting I wanted to learn by trying to re-implement a known v1 behaviour in the v2 configuration.


Anyway I tried what @tweeniev2 suggested, but the trailing /api path is still present in the proxied request.

A backend is serving an API at localhost:3001 and replies to GET\POST etc requests, an example path is:

/clients

Using Postman to debug the path is reachable at localhost:3001/clients
Now I’d also want to nest it under the example.test domain, however when hitting example.test/api/clients the forwarded request is localhost:3001/api/info which doesn’t exist and yields a 404.

Either I change all the routes to prefix them with /api, or as I used to do with the Caddyfile v1, I simply used the without option.

Caddyfile v2 used in the examples above

example.test:80
root * /usr/share/caddy/
		
reverse_proxy /api localhost:3001

I’ve also tried to use the uri directive however, the backend api is unreachable for all the paths that shares an equal name with the site root:

The root site has a path clients which shows the clients in an HTML page, the API also has a clients path which I want to be reachable as example.test:80/api/clients

example.test:80
root * /usr/share/caddy/

uri strip_prefix /api 
reverse_proxy /api backend:3001

file_server

However with this approach if I try access example.test:80/api/clients I am server the website’s example.test:80/clients path.

I hope to have been clear in the scenario.

I’ve also tried to use rewrite /api/* / in place of the uri strip with the same result.


TL;DR

This approach to the directive keeps the /api path to the forwarded request.

example.test:80
reverse_proxy /api localhost:3001


Observed behaviour
example.test:80/api/clients -> localhost:3001/api/clients

Expected behaviour 
example.test:80/api/clients -> localhost:3001/clients

You are sincerely the friendliest dev I ever encountered on the web =), you are always very helpful here in the forums, and I also stumbled upon some Stack Overflow replies from you.

Hello,

I’m not sure if I got this right but it seems you have all the elements.

Full redirection from example.test:80/api* to localhost:3001 :

example.test:80
reverse_proxy /api* localhost:3001

Full redirection with uri change :

example.test:80 {
    handle /api* {
        uri strip_prefix /api
        reverse_proxy localhost:3001
    }
} 

In the last one, you can request on example.test:80/api/clients and reach localhost:3001/clients.

I guess the key point you need is the nested reverse_proxy when adding a uri manipulation. The first example with a uri change is not working for me (not sure why…?).

Alex

1 Like

I’d recommend a uri strip_prefix /api so that you don’t accidentally replace /api/ anywhere else in the URI.

2 Likes

I didn’t understand that directives could be nested. Might be something I never encountered in v1 but I thought that all the directives had to be on the first level under a site block like in the example here Caddyfile Concepts — Caddy Documentation

My bad I didn’t understand that and how to use the handle directive.

Thank you very much for pointing it out.

1 Like

Glad it can help!
No worry, I know what it is as I’m still exploring the awesomeness of caddy :heart_eyes:.
Documentation is really helpful to me (well done for that too!).

1 Like

Yeah! Caddy is the best web server and easiest to use IMHO.

Compared to Apache and Nginx which are over necessarily verbose and complicated. I’m just having an hard time for v2 but I’ll eventually get there in my workflow =)

2 Likes

Not all of them can!

route and handle are special cases for nesting and grouping, though!

route specifically allows you to manually define the order in which directives execute, too, while handle’s schtick is that it’s mutually exclusive with other handle blocks, i.e. only one ever executes at each level. So with two handle blocks you can ensure that for any given request only one set of handle grouped directives will execute.

Very useful, both. They exist because Caddy no longer actually uses (or even understands, per se) the Caddyfile. Caddy v2’s config structure is expressed entirely in JSON, and all the Caddyfile does is act as a shorthand way to expand out into more complex JSON. route/handle, therefore, are just methods to help shape how a Caddyfile is translated and the resulting request handling flow in JSON.

4 Likes

Thank you very much for the overview explanation!

May I suggest @Whitestrake and @matt changing a bit the wording in the documentation?
On the Directives and Subdirectives section here I believe it’s clear what are the directives (which are also listed here) but it seemed to me that subdirectives are only the ones that are specified in each directive’s syntax block, like the subdirective health_path for reverse_proxy for instance, this is also reinforced with the example made with lb_policy first.

Where subdirectives are explained I’d mention those two directives that are “special” in the sense that they can accept other directives.

After more thought this is indeed explicitly said in the directive list

  • handle: A mutually-exclusive group of directives
  • route: A group of directives treated literally as single unit

The information is indeed actually there in the directive lists and my fault I didn’t read them all, that’s why I missed them :sweat_smile:

Anyway just my 2cents from this experience =)

2 Likes

No worries, every bit of earnest feedback is very welcome!

You know, it might not go awry to have a section there right at the bottom of Caddyfile Concepts — Caddy Documentation that explicitly points out route and handle. They look like directives that accept other directives as subdirectives, but that’s not strictly what they are. Could be a good place to introduce them and explain that.

2 Likes

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