Reverse proxy a single url

1. Caddy version (caddy version):

v2.1.1

2. How I run Caddy:

a. System environment:

systemd, docker

b. Command:

/usr/bin/caddy run --config /etc/caddy/Caddyfile

d. My complete Caddyfile or JSON config:

sub.domain1.tld {
    handle /ahh {
        rewrite /ahh /raw/u7Z-Pov-GTEyIohymWO0J
        reverse_proxy https://sub.domain2.tld
    }

    reverse_proxy localhost:23563
}

sub.domain2.tld {
    reverse_proxy localhost:18019
    file_server
}

3. The problem I’m having:

I am trying to get https://sub.domain1.tld/ahh to return sub.domain2.tld/raw/u7Z-Pov-GTEyIohymWO0J, which is plain text

4. Error messages and/or full log output:

2020/07/22 19:19:22.491	ERROR	http.log.access	handled request	{"request": {"method": "GET", "uri": "/raw/u7Z-Pov-GTEyIohymWO0J", "proto": "HTTP/2.0", "remote_addr": "serveripaddress:36720", "host": "sub.domain1.tld", "headers": {"User-Agent": ["Mozilla/5.0 (X1
1; Ubuntu; Linux x86_64; rv:78.0) Gecko/20100101 Firefox/78.0"], "Dnt": ["1"], "X-Forwarded-Proto": ["https"], "Accept-Language": ["en-US,en;q=0.5"], "Cache-Control": ["max-age=0"], "Te": ["trailers"], "X-Forwarded-For": ["myipaddress"], "Cookie": ["__cfduid=d4f6b4f5ccb2b79037878f714206e58e01595265189"], "Accept": ["text/html,application/xhtml+xml,application/xml;q=0.9,image/webp,*/*;q=0.8"], "Accept-Encoding": ["gzip, deflate, br"], "Upgrade-Insecure-Requests": ["1"]}, "tls": {"resumed": false, "version": 772, "ciphersuite": 4865, "proto": "h2", "proto_mutual": true, "server_name": "sub.domain2.tld"}}, "common_log": "serveripaddress - - [22/Jul/2020:12:19:22 -0700] \"GET /raw/u7Z-Pov-GTEyIohymWO0J HTTP/2.0\" 404 278", "duration": 0.004199111, "size": 278, "status": 404, "resp_headers": {"Server": ["Caddy", "Apache/2.4.38 (Debian)"], "Content-Length": ["278"], "Content-Type": ["text/html; charset=iso-8859-1"], "Date": ["Wed, 22 Jul 2020 19:19:22 GMT"]}}
2020/07/22 19:19:22.492	ERROR	http.log.access	handled request	{"request": {"method": "GET", "uri": "/ahh", "proto": "HTTP/2.0", "remote_addr": "myipaddress:48652", "host": "sub.domain1.tld", "headers": {"Accept": ["text/html,application/xhtml+xml,application/xml;q=0.9,image/webp,*/*;q=0.8"], "Accept-Language": ["en-US,en;q=0.5"], "Accept-Encoding": ["gzip, deflate, br"], "Upgrade-Insecure-Requests": ["1"], "Cache-Control": ["max-age=0"], "Te": ["trailers"], "User-Agent": ["Mozilla/5.0 (X11; Ubuntu; Linux x86_64; rv:78.0) Gecko/20100101 Firefox/78.0"], "Dnt": ["1"], "Cookie": ["__cfduid=d4f6b4f5ccb2b79037878f714206e58e01595265189"]}, "tls": {"resumed": false, "version": 772, "ciphersuite": 4865, "proto": "h2", "proto_mutual": true, "server_name": "sub.domain1.tld"}}, "common_log": "myipaddress - - [22/Jul/2020:12:19:22 -0700] \"GET /ahh HTTP/2.0\" 404 278", "duration": 0.065468676, "size": 278, "status": 404, "resp_headers": {"Date": ["Wed, 22 Jul 2020 19:19:22 GMT"], "Content-Length": ["278"], "Server": ["Caddy", "Caddy", "Apache/2.4.38 (Debian)"], "Content-Type": ["text/html; charset=iso-8859-1"]}}
2020/07/22 19:19:22.637	INFO	http.log.access	handled request	{"request": {"method": "GET", "uri": "/favicon.ico", "proto": "HTTP/2.0", "remote_addr": "myipaddress:48652", "host": "sub.domain1.tld", "headers": {"Cache-Control": ["max-age=0"], "Te": ["trailers"], "User-Agent": ["Mozilla/5.0 (X11; Ubuntu; Linux x86_64; rv:78.0) Gecko/20100101 Firefox/78.0"], "Accept": ["image/webp,*/*"], "Accept-Language": ["en-US,en;q=0.5"], "Accept-Encoding": ["gzip, deflate, br"], "Dnt": ["1"], "Cookie": ["__cfduid=d4f6b4f5ccb2b79037878f714206e58e01595265189"]}, "tls": {"resumed": false, "version": 772, "ciphersuite": 4865, "proto": "h2", "proto_mutual": true, "server_name": "sub.domain1.tld"}}, "common_log": "myipaddress - - [22/Jul/2020:12:19:22 -0700] \"GET /favicon.ico HTTP/2.0\" 0 0", "duration": 0.000425421, "size": 0, "status": 0, "resp_headers": {"Server": ["Caddy"]}}

5. What I already tried:

To try and narrow down the issue, I changed the url directly to the container (as they’re on the same host in this case)

        reverse_proxy https://sub.domain2.tld
-->     reverse_proxy localhost:18019

and this makes it work fine.
curl https://sub.domain1.tld/ahh returns the content of https://sub.domain2.tld/raw/u7Z-Pov-GTEyIohymWO0J

6. Links to relevant resources:

I think what’s happening is that sub.domain2.tld will be resolved as the WAN IP address, but the service is running locally. This will cause Caddy to try to make a request to the service at your WAN IP but the routing will not make the request go to your other site block instead.

What I think you can do is add a second site label which listens on some port you won’t expose publicly as a way to make it accessible to your first site. Something like this maybe:

sub.domain1.tld {
    handle /ahh {
        rewrite /ahh /raw/u7Z-Pov-GTEyIohymWO0J
        reverse_proxy localhost:8080
    }

    reverse_proxy localhost:23563
}

sub.domain2.tld, http://localhost:8080 {
    reverse_proxy localhost:18019
    file_server
}

What i’d like to do is have it return from any url, such as https://pastebin.com/raw/aGYS6iJ9. So there’s no guarantee it would be available locally. Apologies for not being clear. So something like this:

sub.domain1.tld {
    handle /ahh {
        rewrite /ahh /raw/aGYS6iJ9
        reverse_proxy https://pastebin.com
    }

    reverse_proxy localhost:23563
}

Caddy v2’s reverse proxy directive is transparent by default (it passes the client’s Host header through, among a few other things).

That means when proxying to sub.domain2.tld, Caddy will still request the hostname sub.domain1.tld from the upstream server.

To follow that chain of logic, a request to sub.domain1.tld/ahh gets rewritten, proxied to the server at sub.domain2.tld, and then Caddy requests sub.domain1.tld/raw/u7Z-Pov-GTEyIohymWO0J.

If I’m correct, when proxying to itself, this means Caddy will just follow the non-/ahh route, reverse proxying to localhost:23563. When proxying to Pastebin, it will request sub.domain1.tld/raw/u7Z-Pov-GTEyIohymWO0J, which will get 403’d by Cloudflare (wrong Host).

To get it working in front of Pastebin, I had to set the Host back:

http://:8080 {
  handle /ahh {
    rewrite * /raw/aGYS6iJ9
    reverse_proxy https://pastebin.com {
      header_up Host {http.reverse_proxy.upstream.host}
    }
  }
}

With the header_up subdirective added it seemed to function as expected.

3 Likes

This works perfectly.

Thank you for the explanation, I’ve been trying to figure this out for 2 days and this cleared it up really well!

1 Like

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