NGINX Reverse proxy based on presence of set of request headers? - nginx

If a user request do not have a set of headers, then the reverse proxy response should be routed to a different back end server , else if the reqeust have those headers, than request must go to a different server.
Is it possible in NGINX and how do we do that ?

Let's say that you're using x-backend-pool for your request header,
you can use the following NGINX module to get what you want: http://nginx.org/en/docs/http/ngx_http_map_module.html#map
The map directive allows you to set variables based on values in other variables, I've provided an example for you below:
upstream hostdefault {
server 127.0.0.1:8080;
}
upstream hosta {
server 127.0.0.1:8081;
}
upstream hostb {
server 127.0.0.1:8082;
}
map $http_x_backend_pool $backend_pool {
default "hostdefault";
a "hosta";
b "hostb";
}
server {
listen 80;
server_name example.com;
location / {
proxy_pass http://$backend_pool;
}
}

Related

how to split traffic from same url path to 2 different upstreams?

i have these upstreams declared:
upstream upstream_1 {
server some_container_1:8000;
}
upstream upstream_2 {
server some_container_2:8001;
}
and this server:
server {
listen 7000;
server_name localhost;
location /path {
uwsgi_pass upstream_1;
}
}
where both some_container_1 and some_container_2 are based on same image (thus offer the same apis on the same paths) but differ on env vars and other non related stuff. i want to fork 1% of all traffic from localhost:7000/path to be delivered 'as is' to upstream_2 and 99% to remain on upstream_1. both cases should keep the request as received, altering neither path nor headers
with split_clients i can fork which path will be set before forwarding the request to a single upstream, which is not my case.
here the fork is done inside an upstream between servers, not inside a location splitting between upstreams, as i need.
can i define an upstream of upstreams like
upstream compound_upstream_1 {
upstream upstream_1 weight=99;
upstream upstream_2;
}
to use it on
server {
listen 7000;
server_name localhost;
location /path {
uwsgi_pass compound_upstream_1;
}
is it possible to do this with nginx? considering so, which way should be the standard to accomplish this?
I don't understand, what stops you from using server names in the upstream block directly?
upstream compound_upstream_1 {
server some_container_1:8000 weight=99;
server some_container_2:8001;
}
server {
listen 7000;
server_name localhost;
location /path {
uwsgi_pass compound_upstream_1;
}
}
Or maybe I misunderstand your question?
It might be possible to accomplish this using a load balancer: https://docs.nginx.com/nginx/admin-guide/load-balancer/http-load-balancer/
I'm not sure what the weights would be for your '1%' scenario but you can toy with it and adjust it to your liking.

How to drop path in rewrite and proxy pass the args in nginx

Example request - http://localhost/iframe?ip=192.168.0.237
I want to proxy pass the request to the value of IP and remove the path and args after localhost/ .
Ideally the proxy_pass should point to 192.168.0.237 and the URL should be http://localhost/.
localhost /iframe {
rewrite ^/(iframe/.*)$ http://localhost/ permanent;
proxy_pass $arg_ip;
}
I'm not sure whether rewrite is the proper way to address this problem.
I would use the argument ip and a rewrite to remove the iframe location
server {
listen 8085;
location /iframe {
rewrite ^/iframe(.*)$ /$1 break;
proxy_pass http://$arg_ip;
}
}
server {
listen 8080;
location / { return 200 "$host$uri"; }
}
Security Notice
I just have a feeling you should whilelist the upstream servers accepted as arguments. If not this will be a wildcard proxy to every single http-server reachable in the network. This is a easy to use SSRF attack vector. So please add some extra layer of security.
SSRF Explained:
Let's say we use this configuration without any further security. Given the folowing NGINX config:
server {
listen 8085;
location /iframe {
rewrite ^/iframe(.*)$ /$1 break;
proxy_pass http://$arg_ip;
}
}
# Server for iframe service
server {
listen 8080;
root /usr/share/nginx/;
location / { return 200 "$host$uri\n"; }
}
# Private Server Section here!
server {
listen 8086;
allow 127.0.0.1;
deny all;
.....
location / {
index welcome.html;
}
}
Trying to reach the secret server directly
curl -v EXTERNALIP:8086
will fail with HTTP 403.
The NGINX will just allow connections form localhost/127.0.0.1 as defined in the allow/deny directives.
But lets try the iframe with the ip argument.
$# curl localhost:8085/iframe?ip=127.0.0.1:8086
Welcome to our very secure server! Internals only!
It prints the content of the secret server. Whitlisting a proxy-pass like this is never a good idea regardless its working or not.

NGINX: Same Hash for multiple upstreams

I've multiple upstreams with same 2 servers in different ports for different apps, but I would need it to keep a consistent connection to the server.
Example:
upstream APP {
ip_hash;
server 10.10.10.1:1111;
server 10.10.10.2:1111;
}
upstream APP_HTTP {
ip_hash;
server 10.10.10.1:2222;
server 10.10.10.2:2222;
}
upstream APP_WS {
ip_hash;
server 10.10.10.1:3333;
server 10.10.10.2:3333;
}
....
location /APP {
proxy_pass http://APP;
}
location /APP_HTTP {
proxy_pass http://APP_HTTP;
}
location /APP_WS {
proxy_pass http://APP_WS;
}
So if a user is redirected at APP starting point to server 10.10.10.1, I need to guarantee that for APP_HTTP and APP_WS goes as well to 10.10.10.1.
Is it possible? How?
IP_Hash seems to not be working as I would expect.
Thanks
Best regards

How to use one Nginx Cookie(route) in two upstreams with Nginx-sticky-module

I am using Nginx-sticky-module to add an upstream server persistance using cookies.But I have two upstreams like this:
upstream upstreamA{
sticky;
server server1:8080;
server server2:8080;
}
upstream upstreamB{
sticky;
server server1:9080;
server server2:9080;
}
location /requestA {
proxy_pass http://upstreamA;
}
location /requestB {
proxy_pass http://upstreamB
}
When user request nginx:port/requestA,Nginx can hold the request and distribute it to the same server.But if the user request nginx:port/requestB after requestA,Nginx will give it a new Set-Cookie value (route=xxx) by Nginx-sticky-module according upstreamB, can Nginx just use one Cookie in two upsteams?

How to look for a certain header in nginx

I'm using nginx as a proxy server to basically serve image files and hand off everything else to another server at port 9000.
What I want to do is have nginx return an HTTP 500 error code if the incoming request does not contain a specific header (X-AUTH-TOKEN), but only if the requests are not for the resources "/register" or "/events". In that case, they need to go straight to port 9000.
Here's the configuration I currently have:
http {
sendfile on;
upstream my-backend {
server 127.0.0.1:9000;
}
# main ngingx server
server {
server_name localhost;
location / {
proxy_pass http://my-backend;
}
location /images/ {
root /home/images;
}
}
}
Any idea how to implement this kind of logic? Thanks.
There is native HttpCoreModule feature exists:
You can check any header exists/match by something like this:
location /blah {
if ( $http_x_auth_token ) {
// do something, allow
}
}
http://wiki.nginx.org/HttpCoreModule#.24http_HEADER
Hope it will help :)

Resources