Nginx rewrite and proxy_pass explanation - nginx

I can see a following locations in nginx/okd configuration:
location /STFlow/ {
rewrite ^/STFlow(.*)$ $1 last;
#
# Are four lines below executed if rewrite has last option ???
# What's the point of them?
#
proxy_pass http://zuul-proxy:8080;
proxy_set_header Host $host;
proxy_set_header X-Real-IP $http_x_forwarded_for;
proxy_set_header X-Forwarded-For $http_x_forwarded_for;
}
location / {
add_header debug-header dbg5;
set $realip $remote_addr;
if ($http_x_forwarded_for ~ "^(\d+\.\d+\.\d+\.\d+)") {
set $realip $1;
}
proxy_pass http://zuul-proxy:8080;
proxy_set_header Host $host;
proxy_set_header X-Real-IP $http_x_forwarded_for;
proxy_set_header X-Forwarded-For $http_x_forwarded_for;
client_max_body_size 50M;
}
In location /STFlow/ are four lines below rewrite ^/STFlow(.*)$ $1 last; ever executed?
If so when?
What's the point of them?

If that rewrite rule had a break flag instead of last, it would remove the /STFlow prefix from /STFlow/some/path URI before passing it to the upstream, i. e. do the same as the second location block except of setting debug-header and $realip variable. But as far as I understand using the last flag makes that four lines never executed, further URI processing would be done inside the second location block.

Related

Dynamic proxy_pass based on location

I'm trying to create dynamic proxy_pass based on location (to be run in docker and redirect traffic to docker stacks hosting http, based on stack name)
Here's my current config. Ive got to the point of working redirect with static location (commented variants at the bottom with blue/green redirect properly and application is working fine). I got problem with dynamic location (~^/(?<ver>.*)/(?<rest>.*)?$) - there's issue with proper glueing of the target URL. When i go to https://myapp.com/blue/, nginx logs issue with dns resolution blue could not be resolved (3: Host not found), looks like it cuts everything after $<ver> in http://${ver}_${subdomain}/$rest. Im not an REGEX expert and i probably messed the location part, any suggestions?
server {
listen 80;
server_name ~^(?<subdomain>.+)\.(mydomain\.com|mydomain\.pl)$;
resolver 127.0.0.11 ipv6=off;
location ~^/(?<ver>.*)/(?<rest>.*)?$ {
set $target http://${ver}_${subdomain}/$rest;
proxy_pass $target;
proxy_set_header Host $host;
proxy_set_header X-Real-IP $remote_addr;
proxy_set_header X-Forwarded-For $proxy_add_x_forwarded_for;
}
# location ~ ^/blue/((?<rest>.*))?$ {
# set $exdomain http://blue_$subdomain/$rest;
# proxy_pass $exdomain;
# proxy_set_header Host $host;
# proxy_set_header X-Real-IP $remote_addr;
# proxy_set_header X-Forwarded-For $proxy_add_x_forwarded_for;
# }
# location ~ ^/green/((?<rest>.*))?$ {
# set $exdomain http://green_$subdomain/$rest;
# proxy_pass $exdomain;
# proxy_set_header Host $host;
# proxy_set_header X-Real-IP $remote_addr;
# proxy_set_header X-Forwarded-For $proxy_add_x_forwarded_for;
# }
proxy_connect_timeout 90;
proxy_send_timeout 90;
proxy_read_timeout 90;
send_timeout 90;
}
* in a regular expression is greedy, so $ver will capture everything until the last /, and not the next / as you intended.
One solution is to use the non-greedy variant *? (not to be confused with ?), for example:
location ~ ^/(?<ver>.*?)/(?<rest>.*)?$ { ... }
But a better solution is to use a character class that excludes /, for example:
location ~ ^/(?<ver>[^/]+)/(?<rest>.*)?$ { ... }
See this useful resource on regular expressions.

Nginx - Rewrite rule under proxy failed

I have some issues with a "basic" rewriting rule under a proxy_pass location type :
location ~* /test1/network/v1/operator/ke3/dataUp {
rewrite ^(?<begin>/test1/network/v1/operator/ke3/dataUp)(?<parametersPart>.*)(?<mustDie>/dataUp)$ $parametersPart break;
proxy_pass http://server_preproduction;
proxy_set_header X-Real-IP $remote_addr;
proxy_set_header X-Forwarded-For $proxy_add_x_forwarded_for;
proxy_set_header X-Forwarded-Proto https;
proxy_set_header X-Forwarded-Port 443;
proxy_set_header Host $host;
}
I expect any calls sent to : .../test1/network/v1/operator/ke3/dataUp?param1=GHJ&param2=865/dataUp
To be equal to : .../test1/network/v1/operator/ke3/dataUp?param1=GHJ&param2=865
So I just want to parse the parameters section in order to remove any extra /dataUp from the original request.
But when I try to use any kind of regex to do so, nginx seems to return to the location / and use the default request...
I'm sure that the proper location is use, becanse when I use a rewrite like : rewrite ^(?<begin>/test1/network/v1/operator/ke3/dataUp)(?<parametersPart>.*)$ TEST$parametersPart break;
The log on the proxy server received : TEST?param1=GHJ&param2=865/dataUp
I do not add a / at the end of the proxy_pass because I want replace all the url.(but it's not mandatory ! I tried lot of combinations...)
If someone can save my day :p
Thanks !!
I find a way to manipulate the argument with a simple if statement...
if ($query_string ~ "^(?<argsok>/dataUp.*)(?<argsko>/dataUp)$") {
proxy_pass http://server_preproduction/$argsok;
}

nginx proxyPass to prometheus using variable

I have the following nginx.conf
location /monitoring/prometheus/ {
resolver 172.20.0.10 valid=5s;
set $prometheusUrl http://prometheus.monitoring.svc.cluster.local:9090/;
proxy_set_header Accept-Encoding "";
proxy_pass $prometheusUrl;
proxy_set_header Host $host;
proxy_set_header X-Real-IP $remote_addr;
proxy_set_header X-Forwarded-For $proxy_add_x_forwarded_for;
proxy_set_header X-Forwarded-Proto $scheme;
sub_filter_types text/html;
sub_filter_once off;
sub_filter '="/' '="/monitoring/prometheus/';
sub_filter 'var PATH_PREFIX = "";' 'var PATH_PREFIX = "/monitoring/prometheus";';
rewrite ^/monitoring/prometheus/?$ /monitoring/prometheus/graph redirect;
rewrite ^/monitoring/prometheus/(.*)$ /$1 break;
}
When I naviagte to https://myHost/monitoring/prometheus/graph I get redirected to /graph (https://myHost/graph)
When I don't use the variable and place the url directly to proxy_pass everything works as expected. I can navigate to https://myHost/monitoring/prometheus/graph and see prometheus.
location /monitoring/prometheus/ {
resolver 172.20.0.10 valid=5s;
proxy_set_header Accept-Encoding "";
proxy_pass http://prometheus.monitoring.svc.cluster.local:9090/;
proxy_set_header Host $host;
proxy_set_header X-Real-IP $remote_addr;
proxy_set_header X-Forwarded-For $proxy_add_x_forwarded_for;
proxy_set_header X-Forwarded-Proto $scheme;
sub_filter_types text/html;
sub_filter_once off;
sub_filter '="/' '="/monitoring/prometheus/';
sub_filter 'var PATH_PREFIX = "";' 'var PATH_PREFIX = "/monitoring/prometheus";';
rewrite ^/monitoring/prometheus/?$ /monitoring/prometheus/graph redirect;
rewrite ^/monitoring/prometheus/(.*)$ /$1 break;
}
Can anyone explain to me why using the variable leads to a different behaviour in terms of routing? I need to use variables to force nginx to resolve the dns name on each request.
I just figured it out.
As stated in the docs
When variables are used in proxy_pass:
location /name/ {
proxy_pass http://127.0.0.1$request_uri;
}
In this case, if URI is specified in the directive, it is passed to the server as is, replacing the original request URI.
So the problem was that I specified a request uri in the variable (the trailing /).
After removing this / everything worked fine.
Here the working config:
location /monitoring/prometheus/ {
set $prometheusUrl http://prometheus.monitoring.svc.cluster.local:9090;
proxy_set_header Accept-Encoding "";
proxy_pass $prometheusUrl;
proxy_redirect off;
proxy_set_header Host $host;
proxy_set_header X-Real-IP $remote_addr;
proxy_set_header X-Forwarded-For $proxy_add_x_forwarded_for;
proxy_set_header X-Forwarded-Proto $scheme;
sub_filter_types text/html;
sub_filter_once off;
sub_filter '="/' '="/monitoring/prometheus/';
sub_filter 'var PATH_PREFIX = "";' 'var PATH_PREFIX = "/monitoring/prometheus";';
rewrite ^/monitoring/prometheus/?$ /monitoring/prometheus/graph redirect;
rewrite ^/monitoring/prometheus/(.*)$ /$1 break;
}
I believe it's best to use the prometheus --web.external-url command line option.
This sandbox example shows a full working stack, complete with nginx config.
https://github.com/prometheus-community/prometheus-playground/tree/master/nginx
Of note is the prometheus command section of the docker-compose.yml file.
command:
- --config.file=/etc/prometheus/prometheus.yml
- --web.route-prefix=/
- --web.external-url=http://example.com/prometheus

nginx proxy_pass with url rewrite - preserve URL

I am trying to rewrite url for another domain, main agenda is keep the user in same URL[dev.gworks.mobi].
http://dev.gworks.mobi/openam/* -> http://frock.gworks.mobi:8080/openam/*
location /openam {
proxy_pass http://frock.gworks.mobi:8080/;
proxy_redirect off;
proxy_set_header Host $host;
}
it partially works
http://dev.gworks.mobi/openam/ -> http://frock.gworks.mobi:8080/ [it works]
http://dev.gworks.mobi/openam/XUI/#login/ -> http://frock.gworks.mobi:8080/openam/XUI/#login/[it does not work]
The reason is http://dev.gworks.mobi/openam/XUI/#login/ proxy to http://frock.gworks.mobi:8080//XUI/#login/ instead of http://frock.gworks.mobi:8080/openam/XUI/#login/. I'm trying rewrite URL but I'm not successful.
rewrite ^/openam/(.*)$ /$1 last;
can anyone help me to achieve my use case?
Below one is works
location /openam {
proxy_pass http://frock.gworks.mobi:8080/openam;
proxy_set_header X-Real-IP $remote_addr;
proxy_set_header X-Forwarded-For $proxy_add_x_forwarded_for;
proxy_buffering off;
}

Rewrite a subdomain to a backend proxy whith nginx

if have a subdomain on my nginx webserver configuration: sub.mydomain.com
and i have a backend server which listen on port 5000: http://127.0.0.1:5000
is it possible to pass all subdomain calls to the backend?
Like: https://sub.mydomain.com/list to http://127.0.0.1:5000/sub/list
This should work with all methods: POST, PUT, GET, DELETE
UPDATE:
when i call my server: https://mysubdomain.mydomain.com
with the following configuration:
upstream http_backend {
server 127.0.0.1:5000;
}
server_name ~^(?<subdomain>[^.]+)\.mydomain\.com;
This does not work (error: 404):
location / {
proxy_pass http://http_backend/$subdomain/;
proxy_redirect off;
proxy_set_header Host $host;
proxy_set_header X-Real-IP $remote_addr;
proxy_set_header X-Forwarded-For $proxy_add_x_forwarded_for;
proxy_set_header X-Forwarded-Proto https;
}
This works fine:
location / {
proxy_pass http://http_backend/mysubdomain/;
proxy_redirect off;
proxy_set_header Host $host;
proxy_set_header X-Real-IP $remote_addr;
proxy_set_header X-Forwarded-For $proxy_add_x_forwarded_for;
proxy_set_header X-Forwarded-Proto https;
}
When i log the $subdomain variable in the access_log, it seems to be correct.
nginx version: nginx/1.9.15
To pass all subdomains you need to set it in server name by putting dot before domain.
server_name .mydomain.com;
Yes, you can use variables in proxy_pass. And you can extract part of domain using regexp server name.
server {
server_name ~^(?<sub>[^.]+)\.example\.com;
# now subdomain of example.com placed to $sub
# please, note, this rule do not work for http://example.com
location / {
proxy_pass http://127.0.0.1:5000/$sub/;
# Path part of proxy_par URI will replace path
# part of location directive (so / -> /$sub/, /xxxx/ -> /$sub/xxxx/)
}
}
Thats all :)
It seems nginx does not add the $uri to the proxy_pass if i use the $subdomain variable.
The following solution works:
location / {
proxy_pass http://http_backend/$subdomain/$uri;
proxy_redirect off;
proxy_set_header Host $host;
proxy_set_header X-Real-IP $remote_addr;
proxy_set_header X-Forwarded-For $proxy_add_x_forwarded_for;
proxy_set_header X-Forwarded-Proto https;
}

Resources