Nginx map doesn't use the arguments of my regular expression - nginx

I'm trying to use the map of nginx, but the results aren't what I expect.
This is what I have:
map $uri $new {
default "";
~*/cc/(?P<suffix>.*)$ test.php?suffix=$suffix;
}
location ~ [a-zA-Z0-9/_]+$ {
proxy_pass http://www.domain.com:81/$new;
proxy_set_header X-Real-IP $remote_addr;
proxy_set_header Host $host;
proxy_set_header X-Host $host;
proxy_set_header X-Forwarded-For $proxy_add_x_forwarded_for;
}
When I go to www.domain.com/cc/abc, I see this in the logs
2012/03/29 17:27:53 [warn] 3382#0: *33 an upstream response is buffered to a temporary file /var/cache/nginx/proxy_temp/5/00/0000000005 while reading upstream, client: 1.2.3.4, server: www.domain.com, request: "GET /cc/abc HTTP/1.1", upstream: "http://1270.0.0.1:81/test.php?suffix=$suffix", host: "www.domain.com"
The $suffix isn't replaced.
But when I do this:
map $uri $new {
default "";
~*/cc/(?P<suffix>.*)$ $suffix;
}
location ~ [a-zA-Z0-9/_]+$ {
proxy_pass http://www.domain.com:81/$new;
proxy_set_header X-Real-IP $remote_addr;
proxy_set_header Host $host;
proxy_set_header X-Host $host;
proxy_set_header X-Forwarded-For $proxy_add_x_forwarded_for;
}
And now, when I go to go to www.domain.com/cc/abc, the logs show me this:
2012/03/29 17:29:39 [warn] 5916#0: *26 an upstream response is buffered to a temporary file /var/cache/nginx/proxy_temp/2/00/0000000002 while reading upstream, client: 1.2.3.4, server: www.domain.com, request: "GET /cc/abc HTTP/1.1", upstream: "http://1270.0.01:81/abc", host: "www.domain.com"
So, when the rewrite contains a string including the variable, it isn't replaced. But if it only contains the variable, it will work.
What am I doing wrong?

As you've discovered, map replacements can only be a static string or a single variable. Since test.php?suffix=$suffix doesn't start with a $, nginx assumes it's just a static string. Instead of using a map, you'll need to use two rewrites to accomplish what you want:
location ~ [a-zA-Z0-9/_]+$ {
rewrite ^/cc/(.*) /test.php?suffix=$1 break;
rewrite ^ / break;
proxy_pass http://www.domain.com:81;
proxy_set_header X-Real-IP $remote_addr;
proxy_set_header Host $host;
proxy_set_header X-Host $host;
proxy_set_header X-Forwarded-For $proxy_add_x_forwarded_for;
}
The first rewrite will strip any initial /cc/ from the url and append the rest as the url arg like your map was trying to. The break flag tells nginx to stop processing rewrite directives. If the first rewrite doesn't match, then the second will always match, and will set the url to /.
EDIT: As of 1.11.0, map values can be complex values, so the original config would work

Related

nginx proxy_pass to external url fail

I'd like to config nginx to proxy_pass my domain *xyz.abc.com to external url such as google.com/...The idea is same as this post. But it constantly show error below:
[error] 12725#12725: *1530410 no resolver defined to resolve google.com, client: 27.64.99.7, server: ~^(?<name>\w+)\.xyz\.abc\.com$, request: "GET /favicon.ico HTTP/1.1", host: "ivy1.xyz.abc.com", referrer: "http://ivy1.xyz.abc.com/"
Here is my config
server {
server_name ~^(?<name>\w+)\.xyz\.abc\.com$;
location / {
proxy_pass https://google.com/$name$request_uri;
proxy_set_header Host $proxy_host;
proxy_set_header X-Real-IP $remote_addr;
proxy_set_header X-Forwarded-For $proxy_add_x_forwarded_for;
}
}
Is the something wrong in my configuration? I'm using nginx 1.11.6
As #Richard advice,I set resolver in location context which solved my issue.
resolver 8.8.8.8;
resolver_timeout 10s;

nginx proxy_pass to https / image-server not working

I'm trying to proxy an image server imagekit.io so that all requests have same domain name.
Have tried multiple configurations in HTTPS nginx server (with self-signed certificate) and even in HTTP server.
Let's say the URL is https://ik.imagekit.io/hj8sm3kk7/brochures/92/1579/suzuki-gsx-r150-615123.pdf
With the below configuration, I'm trying to hit http://localhost.com:8800/brochures/92/1579/suzuki-gsx-r150-615123.pdf
server {
listen 8800;
server_name localhost.com;
location /brochures {
proxy_ignore_headers Set-Cookie;
proxy_set_header Host ik.imagekit.io;
# proxy_set_header X-Real-IP $remote_addr;
# proxy_set_header X-Forwarded-For $proxy_add_x_forwarded_for;
proxy_set_header Pragma no-cache;
proxy_set_header Accept $http_accept;
proxy_set_header User-Agent $http_user_agent;
proxy_set_header Accept-Encoding $http_accept_encoding;
proxy_set_header Accept-Language $http_accept_language;
proxy_set_header sec-fetch-mode navigate;
proxy_set_header sec-fetch-site cross-site;
proxy_set_header sec-fetch-user ?1;
proxy_set_header :authority ik.imagekit.io;
proxy_set_header :method GET;
proxy_set_header :path $path;
proxy_set_header :scheme https;
proxy_set_header Upgrade-Insecure-Requests 1;
proxy_pass https://ik.imagekit.io/hj8sm3kk7/brochures;
}
}
This however works:
http://localhost.com:8800/financial-advisor/mfs-investment-management-review opens the same page as https://smartasset.com/financial-advisor/mfs-investment-management-review
location /financial-advisor {
proxy_ignore_headers Set-Cookie;
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_pass https://smartasset.com;
}
The real issue turned out to be an SSL problem with ik.imagekit.io, using http:// instead of https:// in the proxy_pass value helps.
Original (and wrong) answer I've given:
The first example requires a manipulation of the URL path. Consider a similar approach:
location ~ ^/(brochures/.*) {
# all the previous config you used should be added here
proxy_pass https://ik.imagekit.io/hj8sm3kk7/$1;
}
This will proxy the request to the proper URL path, which changes from the original request. $1 is the part of the request URL path that matches the first brackets (...).

RabbitMQ Management Over HTTPS and Nginx

I'm trying to access the RabbitMQ interface over HTTPS/SSL with nginx, and I can't figure out what I'm missing.
Here's my rabbitmq.conf file:
[
{ssl, [{versions, ['tlsv1.2', 'tlsv1.1']}]},
{rabbit, [
{reverse_dns_lookups, true},
{hipe_compile, true},
{tcp_listeners, [5672]},
{ssl_listeners, [5671]},
{ssl_options, [
{cacertfile, "/etc/ssl/certs/CA.pem"},
{certfile, "/etc/nginx/ssl/my_domain.crt"},
{keyfile, "/etc/nginx/ssl/my_domain.key"},
{versions, ['tlsv1.2', 'tlsv1.1']}
]}
]
},
{rabbitmq_management, [
{listener, [
{port, 15671},
{ssl, true},
{ssl_opts, [
{cacertfile, "/etc/ssl/certs/CA.pem"},
{certfile, "/etc/nginx/ssl/my_domain.crt"},
{keyfile, "/etc/nginx/ssl/my_domain.key"},
{versions, ['tlsv1.2', 'tlsv1.1']}
]}
]}
]}
].
All works ok when I restart rabbitmq-server
My nginx file looks like this:
location /rabbitmq/ {
if ($request_uri ~* "/rabbitmq/(.*)") {
proxy_pass https://example.com:15671/$1;
}
}
Now, I'm guessing there's something with the ngnix config not being able to resolve the HTTPS URL, as I'm getting 504 timeout errors when trying to browse:
https://example.com/rabbitmq/
Obviously, this is not the correct FQDN, but the SSL cert works fine without the /rabbitmq/
Has anyone been able to use the RabbitMQ Management web interface on an external connection over a FQDN and HTTPS?
Do I need to create a new "server" block in nginx config dedicated to the 15671 port?
Any help would be much appreciated!
I ended up reverting back to the default rabbitmq.config file, then modified my nginx config block to the below, based on another stackoverflow answer that I can't find right now.
location ~* /rabbitmq/api/(.*?)/(.*) {
proxy_pass http://127.0.0.1:15672/api/$1/%2F/$2?$query_string;
proxy_buffering off;
proxy_set_header Host $http_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;
}
location ~* /rabbitmq/(.*) {
rewrite ^/rabbitmq/(.*)$ /$1 break;
proxy_pass http://127.0.0.1:15672;
proxy_buffering off;
proxy_set_header Host $http_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;
}
Also, I had browser caching for JS files, which was causing issues and have disabled that.
I will try to re-enable SSL piece-by-piece but do have the example URL working for now:
https://example.com/rabbitmq/
I tried the following nginx.conf
location /rabbitmq/ {
proxy_pass http://rabbitmq/;
proxy_buffering off;
proxy_set_header Host $http_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;
}
However I couldn't get the details for a queue or exchange. I got 404 errors for api calls.
And there was a %2F in the url, it's url encoded /.
We need to keep the %2F in the API url and pass it to rabbitmq.
The following link describes how to keep the encoded url part and rewrite it.
Nginx pass_proxy subdirectory without url decoding
So my solution is:
location /rabbitmq/api/ {
rewrite ^ $request_uri;
rewrite ^/rabbitmq/api/(.*) /api/$1 break;
return 400;
proxy_pass http://rabbitmq$uri;
proxy_buffering off;
proxy_set_header Host $http_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;
}
location /rabbitmq/ {
proxy_pass http://rabbitmq/;
proxy_buffering off;
proxy_set_header Host $http_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;
}
This did the trick for me
location /rabbitmq {
proxy_pass http://localhost:15672/;
rewrite ^/rabbitmq/(.*)$ /$1 break;
}
I didn't have to use any other directives.
In case someone is looking for the solution for the Apache (2.4):
<VirtualHost *:443>
ServerName rabbitmq.your-domain.com
AllowEncodedSlashes NoDecode
... // rest of the settings
<Location "/">
Require all granted
ProxyPass http://localhost:15672/
ProxyPassReverse http://localhost:15672/
</Location>
<Location "/api">
Require all granted
ProxyPass http://localhost:15672/api nocanon
</Location>
</VirtualHost>
In fact, 2 elements are very important:
The 'AllowEncodedSlashes NoDecode' on VirtualHost level
The 'nocanon' parameter for ProxyPass on "/api" location
This worked for me and I did not need any other header settings. This is a variation on the answer by #user3142747:
location /rabbitmq/ {
# Strip off the "/rabbitmq" prefix
rewrite ^/rabbitmq/(.*) /$1 break;
# Do NOT suffix proxy_pass path with a trailing "/". This allows NGINX to pass the client request completely unchanged.
# - see http://mailman.nginx.org/pipermail/nginx/2009-November/016577.html
proxy_pass $scheme://localhost:15672;
}

Variable can't be used in proxy_pass in nginx

Here is my config below:
server {
server_name www.xxx.com;
location ~* ^/(unstable|staging|prod)-console/ {
set $serverip "";
rewrite_by_lua '
if string.find(ngx.var.uri, "unstable") ~= nil then
ngx.var.serverip = "10.17.21.123"
elseif string.find(ngx.var.uri, "staging") ~= nil then
ngx.var.serverip = "10.17.21.123"
elseif string.find(ngx.var.uri, "prod") ~= nil then
ngx.var.serverip = "10.17.21.123"
end
';
proxy_set_header X-Real-IP $remote_addr;
proxy_set_header X-Forwarded-For $remote_addr;
proxy_set_header Host $host;
proxy_pass http://$serverip:1234;
proxy_http_version 1.1;
proxy_set_header Upgrade $http_upgrade;
proxy_set_header Connection "upgrade";
}
}
When I visit the page matched this locaion it gives me 500 error. In the nginx error log it says 2017/03/17 15:11:19 [error] 2638#2638: *6 no host in upstream ":1234", client: 10.19.35.20, server: console.allinmoney.com, request: "GET /unstable-console/?arg=ifconfig HTTP/1.1", host: "console.allinmoney.com". It means that the variable hasn't been changed correctly in lua script. Could anyone help for this? Thanks

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