Caddy v2: Help with rewrite rule using value contained in the query string

1. Caddy version (caddy version):

v2.0.0 h1:pQSaIJGFluFvu8KDGDODV8u4/QRED/OPyIR+MWYYse8=

2. How I run Caddy:

I’m running caddy via docker (from caddyserver/caddy-docker):

a. System environment:

caddyserver/caddy-docker Docker container on Mac OSX host (Catalina) with Docker Desktop

b. Command:

docker run -d -p 80:80 -p 443:443 -p 2019:2019 -v /Users/scott/caddy/index.html:/usr/share/caddy/index.html -v caddy_data:/data -v $PWD/Caddyfile:/etc/caddy/Caddyfile --name caddy caddy

c. Service/unit/compose file:

I’m running the default Docker configuration from caddyserver/caddy-docker using the instructions from here: Docker Hub

d. My complete Caddyfile or JSON config:

{
        admin 0.0.0.0:2019
}
local.dev-example.net {
        tls internal

        @siteredirect {
                path_regexp siteredirect_regexp ^/site-redirect?target=/?(.*)
        }
        rewrite @siteredirect /{http.regexp.siteredirect_regexp.1}

        reverse_proxy tcp/localhost:5678
}

3. The problem I’m having:

I’m attempting to translate an nginx configuration over to caddy. I have the following nginx rewrite rule:

    # Site Redirect
    location ~* /site-redirect(.*) {
      set $target $arg_target;

      # Add a leading slash if $target doesn't have one
      if ($target ~* ^(?!\/)(.*)) {
        set $target "/$1";
      }

      rewrite ^ $target? redirect;
    }

This rewrite rule will rewrite traffic from:
https://www.dev-example.net/site-redirect?target=billing to https://www.dev-example.net/billing,
and
https://www.dev-example.net/site-redirect?target=/billing to https://www.dev-example.net/billing,

I’m very much aware that the snippet above won’t work due to the fact that the path_regexp only looks at the path and does not include the query string, but I’m unable to piece together a way to get a specific value out of the query string and perform the rewrite using it.

Is there a way to do this with Caddy v2?

4. Error messages and/or full log output:

I’m not getting an error message. The URL isn’t getting rewritten.

5. What I already tried:

I have been reading through the Caddy v2 documentation. Path_regexp matchers don’t include query string parameters. The expression matchers, per the documentation, must resolve to a true/false value. I’ve looked through the example Caddyfiles on the github repo. My google-fu is failing me as well.

6. Links to relevant resources:

https://hub.docker.com/_/caddy

Maybe something like this?

@siteRedirect {
	path /site-redirect*
	query target=*
}
rewrite @siteRedirect {http.request.uri.query.target}

If the rewrite doesn’t include a leading slash, I think it should still work just fine.

I tried adding that site redirect (both with and without the query field) and the URL is still not getting rewritten.

I was able to solve this by changing it to this, which appears to be working as expected:

        @siteRedirect {
                path_regexp "^/site-redirect.*"
        }
        rewrite @siteRedirect {http.request.uri.query.target}

Thanks for your help!

Huh? path_regexp "^/site-redirect.*" and path /site-redirect* should do the exact same thing (except that the second is faster because it’s a fast prefix match rather than a regexp).

The only reason I could think of that it doesn’t work otherwise would be because there’s no target query.

Actually, ignore my previous post. You are correct. I think there was a problem with the URL that I was using to test.

(i.e. “site-redirec” != “site-redirect”)

This does work:

        @siteRedirect {
                path /site-redirect*
                query target=*
        }
        redir @siteRedirect {http.request.uri.query.target}
1 Like

I do have one follow up question so that I can maybe avoid asking really basic questions like this in the future. Where would I look in the Caddy v2 documentation to get specifics about the {http.request.uri.query} placeholder? I didn’t know that you could just appent the name of the query string parameter to the end of the placeholder like that.

This page doesn’t give me any indication that you can do that:

It’s a good question and we haven’t figured out the best way to document placeholders yet, since they’re defined by individual modules.

The Caddyfile has “shorthand” placeholders that are just a search-replace before Caddyfile parsing, and the actual placeholder values are defined in various places throughout the code base – and also from third party modules. So I guess it’s up to each module to document the placeholders they expose.

Most of the HTTP placeholders, including the one you’re asking about, are defined here: Modules - Caddy Documentation

Caddy has a few placeholders that aren’t dependent on context, so they can be used anywhere placeholders are accepted: Conventions — Caddy Documentation

1 Like

In Caddy v2.1, we’re adding a new shorthand {query.*} so it should make your config slightly easier to read :smile:

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