问题
I'm using nginx to create a reverse proxy to a web app that may be behind a firewall. For my initial proof of concept I used the following location block to ensure it worked.
location / {
proxy_pass https://localhost:2222;
proxy_set_header Host $host;
proxy_set_header X-Forwarded-For $remote_addr;
}
I open up my reverse tunnel on my web app with ssh -f -N -T -R2222:localhost:443 user@nginx-ip
.
This works exactly as I like. I type in my nginx-ip
into my browser and I get the https traffic from my web app but obfuscated by the nginx-ip
, etc.
I want to allow potentially a few thousand reverse tunnels though across a few thousand ports (instead of just 2222 in the above case). Reading up on nginx, I thought to use regular expressions to dynamically use a URI containing the port number to proxy_pass to that specific port.
That is, I'd like https://nginx-ip/2222/
to proxy_pass https://localhost:2222;
and I'd like https://nginx-ip/1111/
to proxy_pass https://localhost:1111;
.
I've tried quite a few variations, but as far as I've been able to reason, I've landed on thinking this should work:
location ~* ^/(\d+) {
proxy_pass https://localhost:$1;
proxy_set_header Host $host;
proxy_set_header X-Forwarded-For $remote_addr;
}
It doesn't. I get a 502 Bad Gateway in my browser and the error log gives me:
2016/05/31 21:02:36 [error] 6188#0: *3584 no resolver defined to resolve localhost, client: {my-client-ip}, server: localhost, request: "GET /2222/ HTTP/1.1", host: "{nginx-ip}"
When I use 127.0.0.1
instead of localhost
I get a 404. The webpage says
Not Found The requested URL /2222/ was not found on this server.
Is what I'm attempting possible with nginx configuration?
To reiterate, I would like to be able to initiate many (thousands) unique reverse tunnels through an nginx web server. My initial thought was to vary the outgoing ports of the nginx server based on what other web app I want to proxy through, and to assign the request to my nginx server to a different port by a port in the URI (extracting it via regex).
回答1:
To solve my problem, and with the help of @Cirdec I ended up going a different direction.
Instead of using path in the URI to reference port, I was successful using the port as a subdomain. That is, 1111.my-host-name
will send things through the reverse proxy on 127.0.0.1
(localhost
) on port 1111
. This requires enlisting some DNS wildcarding to help with some of the heavy listing (of note: wildcard DNS matching in /etc/hosts
will not work, but you can hard code a few entries to test that it works.
Excerpt from my /etc/hosts
file:
nginx-box-ip-address 2222.my-host-name
nginx-box-ip-address 1111.my-host-name
This paired with nginx config:
server {
listen 443;
server_name ~^(?<port_subdomain>[0-9]*).my-host-name$;
# NOTE: omitted extra ssl configuration lines
location / {
proxy_pass https://127.0.0.1:$port_subdomain;
proxy_set_header Host $host;
proxy_set_header X-Forwarded-For $remote_addr;
}
}
Now I can have my web app open up reverse proxy tunnels to arbitrary ports on my nginx box (my-host-name) and reach them through a subdomain.
An step by step example:
- On one of my web app boxes, I open up a reverse tunnel to port
2222
on my nginx box (my-host-name) withssh -f -N -T -R2222:localhost:443 user@my-host-name
- On a different web app box I can open up a different tunnel to the same nginx box (my-host-name), say port
1111
by runningssh -f -N -T -R1111:localhost:443 user@my-host-name
on the different web app box
- On a different web app box I can open up a different tunnel to the same nginx box (my-host-name), say port
- On my nginx box, I have loaded the config above. I open up chrome and hit
2222.my-host-name
and it is as if I'm directly hitting the URL/IP address of my web app box (only it can be behind a firewall thanks to the reverse proxy). Hitting1111.my-host-name
takes me to the other web app box, that is completely separate and through a completely separate tunnel.
回答2:
You should be able to do this with a combination of a url-rewriting rule to remove the digits specifying the port and a named capture to extract the requested_port
as a usable variable for the proxy_pass
directive.
location ~* ^/(?<requested_port>\d+) {
rewrite /(\d+)(.*) /$1 break;
proxy_pass https://localhost:$requested_port;
proxy_set_header Host $host;
proxy_set_header X-Forwarded-For $remote_addr;
}
来源:https://stackoverflow.com/questions/37555674/using-nginx-regex-location-matching-to-dynamically-map-uris-to-different-ports