Nginx dynamic proxy_pass with variable between redirections

nginxredirectreverse-proxy

Nginx proxy_pass with variables are hard to understand. Can some one explain how would i acheive the below scenario.

#first call /?proxytohost=http://blahblah.com
#second redirection to /
#third call /home 

location / {
    if ($arg_proxytohost) {
        set $proxytohost $arg_proxytohost;
        rewrite ^.*$ / break;
    }

    proxy_pass https://$proxytohost;   #first call it may recognize, third call definitely it cant

    proxy_intercept_errors on;
    error_page 301 302 307 = @handle_redirects;
}

location @handle_redirects {
    set $saved_redirect_location '$upstream_http_location';
    proxy_set_header  Host $proxy_host;
    proxy_pass $proxytohost$saved_redirect_location;   #this has proxytohost, i dont think it can recognize the variable here
}

EDIT:

Wanted to reverse proxy few instances which are dynamic (a.blahblah.com, b.blahblah.com, etc.). Each of those service instances has multiple redirects where i need to store cookies and redirect them (thats why i have @handle_redirects section).

If I set the variable $proxytohost above the location declaration as a.blahblah.com, then its working as expected.

But if i want to send that $proxytohost as a dynamic argument to first request and then set it to a variable and then proxy_pass it, it doesnt work.

For example, if assume my nginx is running in localhost:8080, this is what my expectation is

If i curl below

http://localhost:8080/?proxytohost=a.blahblah.com?authToken=aksdfkj

it should take me to a home page after using that token for authentication and redirecting to the home page,

http://localhost:8080/home

in this case /home is a content thats served from https://a.blahblah.com/home.

Best Answer

That will not work.

If I understand correctly you want to proxy to the same host on successive request. Nginx handles request independent of each other. So on the 2nd and 3rd request if $arg_proxytohost is absent and the default you provided is used.

I suggest using Cookies for this. A little example below.

This needs to be in the http{} could be in conf.d in a separate file

map $cookie_p_host $p_host {
    default $cookie_p_host;
    ""      $host;
}

next we have the locations that go in to the server{}

location ~ /proxy/sethost/(?<p_host>.*) { 
    add_header Set-Cookie 'p_host=$p_host;path=/proxy'; 
    add_header Content-type text/html; 
    return 200 'cookie was "$cookie_p_host"<br>now set to "$p_host"'; 
}

location   ~ /proxy(?<p_uri>.*) { 
    resolver         8.8.8.8 ; 
    resolver_timeout 5s; 
    proxy_set_header Host $p_host; 
    proxy_pass       http://$p_host$p_uri; 
}

usage / explanation:

mapping

The mapping is used to avoid nasty if statements. If the cookie is set it is used as the hostname ( correct or not we don't check or care ). If it is not set (null/empty) we use the $host variable. Can change that to anything you want there.

first location

(http://localhost:8080/proxy/sethost/example.com) will set a cookie with the host set to example.com. Anything after /proxy/sethost/ will count as the host name!

second location

(http://localhost:8080/proxy) will now proxy to example.com. Added a resolver for dynamic lookups if not already somewhere else in the config. We need to set the Host header of the proxy request to the one requested and off we go.

Hope this helps. The redirect voodoo is another topic

Related Topic