Nginx: proxy_pass cannot have URI part in location inside "if" statement - nginx

Suppose there's a nginx configuration:
server {
...
location /nakayoshi {
if ($georedirect) {
proxy_pass http://foo.bar/fa/fb/fc;
}
proxy_pass http://foo.bar/fa/fb/fd;
}
}
When I sudo nginx -t, it prints out:
nginx: [emerg] "proxy_pass" cannot have URI part in location given by regular express, or inside named location, or inside "if" statement, or inside "limit_except" block in /etc/nginx/conf.d/nakayoshi.conf
Also I've found rewrite help me here, but the redirected uri will change to urls like "http://foo.bar/fa/fb/fc".
Can I keep the redirected uris unchanged with proxy_pass?

Try something like this
http {
...
map $georedirect $proxyuri {
"" fa/fb/fd;
default fa/fb/fc;
}
server {
...
location /nakayoshi {
proxy_pass http://foo.bar/$proxyuri;
}
}
}

Related

Replace first part of nginx $uri before proxy_pass

I have following location ngix config:
location /bar {
proxy_pass http://bar-api/api;
}
I can test it with curl
$ curl foo.com/bar/test
{"test passed":true}
But IP address of internal server bar-api could change, so I can not specify it directly as above.
I understand, I need to use variables in the location block and specify resolver. Resolver is already specified in http block of nginx config resolver 192.168.0.11 valid=10s;
I'm not sure how to modify location block, so it will work the same way as before.
I tried this:
location /bar {
set $target http://bar-api/api;
proxy_pass $target;
}
But test fails:
$ curl foo.com/bar/test
<getting 404>
Also tried:
location /bar {
set $target bar-api;
proxy_pass http://$target/api;
}
Test still fails:
$ curl foo.com/bar/test
<getting 404>
Probably $uri should be modified with regex. This part /bar/test should be /api/test
So I could use it in location.
location /bar {
set $target bar-api;
<some magic here>
proxy_pass http://$target/$modified_uri;
}
But how to do it?
Use rewrite...break to make the URI change. For example:
location /bar {
set $target bar-api;
rewrite ^/bar(.*)$ /api$1 break;
proxy_pass http://$target;
}
See this document for details.

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 reverse proxy docker - filter by location

I am following this article http://jasonwilder.com/blog/2014/03/25/automated-nginx-reverse-proxy-for-docker/ and I am wondering how "filtering" of requests by location (inspecting URL) can be set up.
For instance when request comes to www.example.com/a it will go to container A, when request comes to www.example.com/b it be redirected to container B.
You can configure two upstreams and redirect from /a to first one and from /b to second one. Something like this:
upstream first {
server 172.17.0.4:5000;
server 172.17.0.3:5000;
}
upstream second {
server 172.17.0.5:5000;
}
server {
...
location /a {
proxy_pass http://first;
include /etc/nginx/proxy_params;
}
location /b {
proxy_pass http://second;
include /etc/nginx/proxy_params;
}
}

Nginx location part not being replaced in proxy_pass when using variable

I have a service listening on myservice.mycompany.local
We're proxifying request like this
server {
listen 80;
location /myservice/ {
proxy_pass http://myservice.mycompany.local/;
}
}
it all works fine requests on public.mycompany.com/myservice/api/1/ping are correctly transformed into request to http://myservice.mycompany.local/api/1/ping as there is the trailing /
but now if we try to use a variable
server {
listen 80;
set $MY_SERVICE "myservice.mycompany.local";
location /acm/ {
proxy_pass http://$MY_SERVICE/;
}
}
the local service will only receive a requests to / with the URI part being lost
I've been able to reproduce this "problem" with several version of nginx
1.8.1-1~wheezy
1.4.6-1ubuntu3.5
I'm able also to reproduce it locally by replacing the proxified service by a simple nc -l 127.0.0.2 8080 and using it as the value of my variable, so it really seems to be something happening inside nginx
And this behaviour is not covered in http://nginx.org/en/docs/http/ngx_http_proxy_module.html#proxy_pass
You may have discovered an undocumented feature, but you can always use a rewrite ... break instead of proxy_pass aliasing:
server {
listen 80;
set $MY_SERVICE "myservice.mycompany.local";
location /acm {
rewrite ^/acm(/.*)$ $1 break;
proxy_pass http://$MY_SERVICE;
}
}

How to use nginx as reverse proxy to direct localhost:9292 to a sub domain foo.localhost/?

I've learned how to pass localhost:9292 to localhost/foo with the following directive:
location /foo {
proxy_pass http://localhost:9292;
}
but I want do something like
foo.localhost -> localhost:9292
Is there a way I can do that?
If foo.localhost is your sub domain name and you want to proxy pass sub-domain to main-domain, you can use proxy_pass and you can learn a little more about server directive if needed. An example:
server {
listem 8080;
host sub.main.com;
...
location / {
proxy_pass http://main.com;
break;
}
}
server {
listen 8081;
host main.com;
...
location / {
//do something
}
}
This is proxy pass, means when access sub.main.com, actually it finally dealt by main.com, but the client side still shows sub.main.com. If you want client side shows main.com, here should use redirect but not proxy_pass.

Resources