proxy_pass based on GET args in nginx

A bit of a non-trivial task, as it turns out the location directive will not match anything after the ? in the URL. Furthermore, attempting to work around this issue by putting the proxy_pass inside an if block will likely result in an error like this one:
nginx: [emerg] "proxy_pass" cannot have URI part in location given by regular expression, or inside named location, or inside "if" statement, or inside "limit_except" block in /etc/nginx/conf.d/domain.com.conf:23

There is a workaround, it’s not pretty, but it should do the trick (giving you time to hopefully refactor the URLs in your app to something more sensible). In the example below, I needed to match a couple of MD5 hashes and proxy those requests to host B while proxying the rest of the requests to host A.

location / {
error_page 418 = @myredir;
if ( $args ~ "c=[0-9a-f]{32}" ) { return 418; }
proxy_pass http://host_a:80;
proxy_set_header Host yourdomain.com;
proxy_set_header X-Real-IP $remote_addr;
proxy_connect_timeout 120;
proxy_send_timeout 120;
proxy_read_timeout 180;
}
location @myredir {
proxy_pass http://host_b:80;
proxy_set_header Host yourdomain.com;
proxy_set_header X-Real-IP $remote_addr;
proxy_connect_timeout 120;
proxy_send_timeout 120;
proxy_read_timeout 180;
}
location / { error_page 418 = @myredir; if ( $args ~ "c=[0-9a-f]{32}" ) { return 418; } proxy_pass http://host_a:80; proxy_set_header Host yourdomain.com; proxy_set_header X-Real-IP $remote_addr; proxy_connect_timeout 120; proxy_send_timeout 120; proxy_read_timeout 180; } location @myredir { proxy_pass http://host_b:80; proxy_set_header Host yourdomain.com; proxy_set_header X-Real-IP $remote_addr; proxy_connect_timeout 120; proxy_send_timeout 120; proxy_read_timeout 180; }
location / {
		error_page 418 = @myredir;
		if ( $args ~ "c=[0-9a-f]{32}" ) { return 418; }
		
		proxy_pass http://host_a:80;
		proxy_set_header Host yourdomain.com;
		proxy_set_header X-Real-IP $remote_addr;
		proxy_connect_timeout 120;
		proxy_send_timeout 120;
		proxy_read_timeout 180;
}

location @myredir {
		proxy_pass http://host_b:80;
		proxy_set_header Host yourdomain.com;
		proxy_set_header X-Real-IP $remote_addr;
		proxy_connect_timeout 120;
		proxy_send_timeout 120;
		proxy_read_timeout 180;
}

Note that the error code we are “throwing” is actually a part of a old April fool’s RFC. You can use any other code that is not a valid HTTP response code.

Leave a Reply

Your email address will not be published.