Setting up reverse proxy to URL from query parameter

1. Output of caddy version:

v2.5.1 h1:bAWwslD1jNeCzDa+jDCNwb8M3UJ2tPa8UZFFzPVmGKs=

2. How I run Caddy:

a. System environment:

Mac OS X

b. Command:

caddy run --watch

c. Service/unit/compose file:

N/A

d. My complete Caddy config:

localhost:2015 {
	handle /proxy/i {
	    reverse_proxy {query.url}
	}
}

3. The problem I’m having:

I’m trying to get a URL from a query parameter ( /proxy/i?url=www.example.com/someimage.png )
The issue is that on reverse_proxy, the extra path would cause an invalid dial address : missing port in address since there is a path (someimage.png).

e.g.

https://localhost:2015/proxy/i?url=https%3A%2F%2Fstatic.ktbyte.cn%2Fimages%2Fscifi.jpg

would do reverse_proxy directly to the image

https://static.ktbyte.cn/images/scifi.jpg

However I believe it has to be reverse_proxy https://static.ktbyte.cn and I’d have to then pass /images/scifi.jpg through a rewrite or uri. I’m not sure, what the right approach is.

4. Error messages and/or full log output:

2022/08/11 22:39:12.226	ERROR	http.log.error	making dial info: upstream {query.url.hostname}: invalid dial address : missing port in address	{"request": {"remote_ip": "::1", "remote_port": "51668", "proto": "HTTP/2.0", "method": "GET", "host": "localhost:2015", "uri": "/proxy/i?url=https%3A%2F%2Fstatic.ktbyte.cn%2Fimages%2Fscifi.jpg", "headers": {"Accept-Language": ["en-CA,en;q=0.9,ru-KZ;q=0.8,ru;q=0.7,en-GB;q=0.6,en-US;q=0.5,fr;q=0.4"], "Cookie": [], "Sec-Fetch-Dest": ["document"], "Cache-Control": ["no-cache"], "Accept": ["text/html,application/xhtml+xml,application/xml;q=0.9,image/avif,image/webp,image/apng,*/*;q=0.8,application/signed-exchange;v=b3;q=0.9"], "Sec-Fetch-Mode": ["navigate"], "Sec-Fetch-User": ["?1"], "Sec-Ch-Ua-Platform": ["\"macOS\""], "Sec-Fetch-Site": ["none"], "Sec-Ch-Ua-Mobile": ["?0"], "Upgrade-Insecure-Requests": ["1"], "User-Agent": ["Mozilla/5.0 (Macintosh; Intel Mac OS X 10_15_7) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/104.0.0.0 Safari/537.36"], "Accept-Encoding": ["gzip, deflate, br"], "Pragma": ["no-cache"], "Sec-Ch-Ua": ["\"Chromium\";v=\"104\", \" Not A;Brand\";v=\"99\", \"Google Chrome\";v=\"104\""]}, "tls": {"resumed": false, "version": 772, "cipher_suite": 4865, "proto": "h2", "server_name": "localhost"}}, "duration": 0.00008913, "status": 502, "err_id": "rs74xf208", "err_trace": "reverseproxy.statusError (reverseproxy.go:1196)"}

5. What I already tried:

I tried the above and considered a double reverse_proxy to extract the relevant information.

6. Links to relevant resources:

Isn’t this kind of the opposite of what a reverse proxy does?

You put a reverse proxy in front of a known resource like a server and it accepts varied clients on behalf of that resource.

It kinda seems like you want Caddy to reach out to arbitrary resources on behalf of your clients, which, conceptually speaking, is what a forward proxy does.

1 Like

The reason you’re getting that error is that the reverse proxy specifically expects an upstream to just be a hostname and port combination only. No scheme, no URL. So this cannot work as-is.

Basically, wrong tool for the job.

It’s unclear why you want to do this, so it’s hard to suggest a solution.

1 Like

Hi guys,
Thanks for the quick replies!
Ah yes I see a forward proxy sounds like what I need then.
Is there a way Caddy could do that?

There’s a forwardproxy plugin, but it’s not really maintained, and the v2 update was never merged:

But @matt suggests “it should work” so you might be able to try to play with that. But no guarantees.

Like I said though, why do you need this? What problem are you trying to solve?

Hi Francis,

Ahh okay unfortunate that it’s not maintained, I’ll take a look and try it.
The problem is a bit hard to describe without showing the website.

Essentially this is our product:
https://ktbyte.com/coder

This is an MVP code you could run in our coder to get an idea.

// Welcome to the KTBYTE coder!
// Feel free to run some code, create a new project, or work on a PSET problem!

// Press the run button or "CTRL + ENTER" to run the code below!
PImage img;

// Press the run button or "CTRL + ENTER" to run the code below!
void setup() {
    size(800, 600);
    img = loadImage("https://static.ktbyte.cn/images/scifi.jpg");
}

void draw() {
    image(img, 0, 0);
}

The kids could choose any image they want to load and our web server currently downloads the image, caches them and serves it to them. This also allows processing.js to do some manipulation on the image.

The problem happens when we have students from China. Essentially we have two Caddy setups one in China and one in US. Communication with China needs to go through a Bridge (for China firewall purpose) which cost money per bytes that have to be transferred.

We only have one web server in the US, so when they ping ktbyte.cn, they hit Caddy cn, which routes through the bridge and to our US Caddy and the web server.

The issue is that every time a student from China loads an image, especially if it’s huge, we have to go through Bridge in order to allow our web server to serve them the image.
This has two issues:

  1. Costs us extra money every time they request an image
  2. It would take a long time if they send a URL for a big picture in China, we have to get the request, download a picture in CN to our US server, and then serve it through the bridge back to them in China.

You’re probably looking for something like v2ray then. That seems to be the preferred “network bypass proxy” these days :man_shrugging: I don’t need any of these solutions myself so I haven’t dug into it at all.

Ahh okay we don’t necessarily need a network bypass.
We ended up loading a web server in China and have the Caddy reverse proxy to it.
Thanks for your time!

1 Like

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