I am trying to configure nginx to proxy pass the request to another server, only if the $request_body variable matches on a specific regular expression.But it is not working for me.
server{
listen 80 default;
server_name www.applozic.com;
location / {
proxy_set_header X-Real-IP $remote_addr;
proxy_set_header X-Forwarded-For $remote_addr;
proxy_set_header Host $http_host;
if ($request_body ~* (.*)appId(.*)) {
proxy_pass http://apps.applozic.com;
}
}
}
request body is::
{
"applicationId": "appId",
"authenticationTypeId": 1,
"enableEncryption": false,
"notificationMode": 0,
"deviceType": 4,
}
I found the solution.
I did following changes in nginx(open resty) config file
upstream algoapp {
server 127.0.0.0.1:543;
}
upstream main {
server 127.0.0.1:443;
}
location /rest/ws/login {
proxy_set_header X-Forwarded-Host $host;
proxy_set_header X-Forwarded-Server $host;
proxy_set_header X-Real-IP $remote_addr;
proxy_set_header X-Forwarded-For $proxy_add_x_forwarded_for;
proxy_set_header X-Url-Scheme $scheme;
proxy_set_header X-Forwarded-Proto $scheme;
proxy_set_header Host $http_host;
proxy_redirect off;
if ($request_method = OPTIONS ) {
proxy_pass https://127.0.0.1:543;
}
if ($request_method = POST ) {
set $upstream '';
access_by_lua '
ngx.req.read_body()
local data = ngx.req.get_body_data()
local match = ngx.re.match(ngx.var.request_body, "appId")
if match then
ngx.var.upstream = "algoapp"
else
ngx.var.upstream = "main"
end
';
proxy_pass https://$upstream;
}
}
As best I can tell the issue is that the variable $request_body may not have been read into memory at the time your if statement is executing.
Suggested alternatives would be to use the lua support or compile nginx with the echo modules and run echo_request_body.
That is not so easy when come to using integration , like some circumstances your nginx does not really allow you to do extra proxy stuff to change the whole design, then you can try nginx-if-request-body to achieve the result
http {
....
map "$uri" $forward_status {
default 100; # 100 means nothing return, continue to proxy phase
"~*.+?\.(css|js|bmp|gif|ico|jpeg|jpg|pict|png|svg|swf|tif)$" 418;
}
map "$request_body" $forward_status_by_body {
default 100;
"abc123xxx" 418;
"~*.+?\.(css|js|bmp|gif|ico|jpeg|jpg|pict|png|svg|swf|tif)$" 418;
}
server {
...
error_page 418 =200 #welcome_if_request_body;
location #welcome_if_request_body {
add_header Content-Type text/plain;
return 200 "welcome_if_request_body, you hit it";
}
location = / {
if_request_body on;
return_status_if_body_eq "ASD" 418 on;
return_status_if_body_eq "foo" 418;
return_status_if_body_eq "john" 418;
return_status_if_body_startswith "report" 418;
return_status_if_body_contains "report" 418;
return_status_if_body_regex "^[\d]+?abc" 418;
return_status_if_variable_map_to $forward_status;
return_status_if_variable_map_to $forward_status_by_body;
proxy_pass http://localhost:7777;
}
...
}
}
Related
What I am trying to achive; is when the request coming from http://<ip>/vault/ui/ (referer in the request header) and it includes the http://<ip>/v1/* endpoint, to be rewriten or redirected to http://<ip>/vault/v1/
can someone please help me to solve this issue?
/etc/nginx/sites-enabled/reverse-proxy.conf
upstream command_center_vault {
server command-center-0.blinchik.io:28200;
}
server {
listen 80;
listen [::]:80;
location /vault/ {
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 Accept-Encoding "";
proxy_pass "http://command_center_vault/vault/";
proxy_redirect /ui/ /vault/ui/;
}
location /vault/v1/ {
proxy_pass "http://command_center_vault/v1/";
}
}
Headers
Update
A little bit more context, the overarching architecture looks as in the picture below.
the configuration of nginx server in the private subnet looks like this:
private subnet nginx
upstream consul_server {
server brain-consul-server-0.blinchik.io:8500;
server brain-consul-server-1.blinchik.io:8500;
server brain-consul-server-2.blinchik.io:8500;
}
upstream vault_server {
server brain-vault-server-0.blinchik.io:8200;
server brain-vault-server-1.blinchik.io:8200;
}
server {
listen 28500;
listen [::]:28500;
location /consul/ {
proxy_pass "http://consul_server";
sub_filter_once off;
sub_filter_types application/javascript text/html;
sub_filter "/v1/" "/consul_v1/";
}
location /consul_v1/ {
proxy_pass "http://consul_server/v1/";
}
}
server {
listen 28200;
listen [::]:28200;
location /vault/ {
proxy_pass "http://vault_server/";
port_in_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 Accept-Encoding "";
proxy_redirect /ui/ /vault/ui/;
sub_filter_once off;
sub_filter '<head>' '<head><base href="/vault/">';
sub_filter '"/ui/' '"ui/';
#inspired by this repo https://github.com/Folcky/hashicorp-vault-and-nginx
}
location /v1/ {
proxy_pass "http://vault_server/v1/";
}
}
public subnet nginx
upstream command_center_vault {
server command-center-0.blinchik.io:28200;
}
server {
listen 80;
listen [::]:80;
location /vault/ {
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 Accept-Encoding "";
proxy_pass "http://command_center_vault/vault/";
proxy_redirect /ui/ /vault/ui/;
}
location /vault/v1/ {
proxy_pass "http://command_center_vault/v1/";
}
}
the consul part works fine. if I change in the public subnet configuration the location of /vault/v1/ to /v1/ then it works as well. But the problem that other products that I intend to add it to the reverse proxy (like Nomad) also uses the /v1/ path and in this case there will be a conflict.
I think this one should work (must be placed at the server context outside any locations:
if ($http_referer ~ /vault/ui) {
rewrite ^/v1(/.*) /vault/v1$1 last;
}
You can make regex pattern more strict including //<ip> or https?://<ip> parts.
I need to set up redirecting some requests to api depending on the value of variables. When using if statements, everything works fine. But when I try to use map instead of if, I get a "the rewritten URI has a zero length" error.
My working config file using if:
proxy_set_header X-Forwarded-Proto $scheme;
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-Server $host;
proxy_redirect off;
upstream backend {
server 192.168.2.2:5987;
}
server {
listen 80;
server_name exemple.com;
client_max_body_size 32m;
charset utf-8;
location /static/ {
alias /opt/project/public/;
}
location /media/ {
alias /opt/project/media/;
}
location /api/v2/ {
set $go "";
# abc query parameter exists
if ($arg_abc) {
set $abc $arg_abc;
set $go "abc";
}
# id query parameter exists
if ($arg_id) {
set $mid $arg_id;
set $go "${go}id";
}
# For v2 REST API remove id query parameter from URL
if ($args ~ (.*)id=[^&]*(.*)) {
set $args $1$2;
}
# For v2 REST API remove abc query parameter from URL
if ($args ~ (.*)abc=[^&]*(.*)) {
set $args $1$2;
}
# only id query parameter exists
if ($go = "id") {
rewrite ^/api/v2/(.*)$ /api/v1/$1$mid/ last;
}
# only id and abc query parameters exists
if ($go = "abcid") {
rewrite ^/api/v2/(.*)$ /api/v1/$1$mid/$abc/ last;
}
}
location / {
proxy_pass http://backend;
}
}
And my not working config using map:
proxy_set_header X-Forwarded-Proto $scheme;
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-Server $host;
proxy_redirect off;
map $arg_abc $abc {
default $arg_abc;
}
map $arg_abc $go {
default abc;
}
map $arg_id $mid {
default $arg_id;
}
map $arg_id $go {
default ${go}id;
}
map $args $args {
~(.*)id=[^&]*(.*) $1$2;
~(.*)abc=[^&]*(.*) $1$2;
}
map $go $api_v1 {
id /api/v1/$1$mid/;
abcid /api/v1/$1$mid/$abc/;
}
upstream backend {
server 192.168.2.2:5987;
}
server {
listen 80;
server_name exemple.com;
client_max_body_size 32m;
charset utf-8;
location /static/ {
alias /opt/project/public/;
}
location /media/ {
alias /opt/project/media/;
}
location /api/v2/ {
set $go "";
rewrite ^/api/v2/(.*)$ $api_v1 last;
}
location / {
proxy_pass http://backend;
}
}
As I found out, I get the error "the rewritten URI has a zero length" because the $api_v1 variable remains empty, since the $go value remains empty, but why is map not processing the url? I tried installing / before $api_v1 in location, but then only parameters without the /api/v1/ part come to my backend.
For example, after processing the request http://exemple.com/api/v2/exemple/test/?id=9090&abc=xyz&stop=pots&rest=api
I expect to get http://exemple.com/api/v1/exemple/test/9090/xyz/?stop=pots&rest=api
But I get http://exemple.com/?id=9090&abc=xyz&stop=pots&rest=api
What's wrong with my map settings?
I make two version of website, one for pc while the other for mobile.
The pc version runs through django which points to a reverse_proxy through http://127.0.0.1:8000/.
While the mobile version only serves the static path in /path/for/mobile.
I tried many ways, for example, but cannot get it work.
location / {
if ($http_user_agent ~ Mobile) {
root /path/for/mobile;
}
else {
proxy_set_header Host $http_host;
proxy_set_header X-Real-IP $remote_addr;
proxy_set_header X-Scheme $scheme;
proxy_pass http://127.0.0.1:8000;
}
}
After some attempt, it turns out using extra server with fixed port number works good.
The if statement only affects a number variable, which affects the port proxy to different version of any content.
server {
# static server
listen 11112;
root /path/to/static/html;
}
server {
# dynamic server
listen 11111;
client_max_body_size 300m;
location / {
proxy_set_header Host $http_host;
proxy_set_header X-Real-IP $remote_addr;
proxy_set_header X-Scheme $scheme;
proxy_pass http://django_devaluation:8000/;
}
}
server {
listen 80;
server_name www.example.com;
index index.html;
// here do the condition separation
set $proxy_port 11111;
if ($http_user_agent ~* mobile) {
set $proxy_port 11112;
}
location / {
proxy_set_header Host $http_host;
proxy_set_header X-Real-IP $remote_addr;
proxy_set_header X-Scheme $scheme;
proxy_pass http://127.0.0.1:$proxy_port;
}
}
Try this - If is mobile, use the default root, otherwise proxy_pass.
location / {
set $mobile 0;
root /path/for/mobile;
if ($http_user_agent ~ Mobile) {
set $mobile 1;
}
if ($mobile = 0) {
proxy_set_header Host $http_host;
proxy_set_header X-Real-IP $remote_addr;
proxy_set_header X-Scheme $scheme;
proxy_pass http://127.0.0.1:8000;
break;
}
}
The only safe operations on nginx if blocks are rewrite and return.
Try something like:
if ($mobile = 0) {
add_header Content-Type text/plain;
return 200 "Desktop Version";
break;
}
to verify that your $mobile variable is set correctly, then:
if ($mobile = 0) {
rewrite ^ /desktopProxy/$request_uri;
}
location ~* ^/desktopProxy/(.*)$ {
...
proxy_pass http://127.0.0.1:8000/$1$is_args$args;
break;
}
I didn't test the "$1$is_args$args" condition, verify that before using on prod.
I try to return 503 status code when the user agent header has a specific value. I tried outside and inside the location block. But when I reload the this config nginx failes to reload:
upstream api{
server 127.0.0.1:1336;
}
# the nginx server instance
server {
listen 0.0.0.0:80;
server_name api.project.com;
# if($http_user_agent = "android") {
# return 503;
# }
# pass the request to the node.js server with the correct headers
location / {
# if($http_user_agent = "android") {
# return 503;
# }
proxy_set_header X-Real-IP $remote_addr;
proxy_set_header X-Forwarded-For $proxy_add_x_forwarded_for;
proxy_set_header Host $http_host;
proxy_set_header X-NginX-Proxy true;
proxy_pass http://api/;
proxy_redirect off;
}
}
Any ideas whats wrong? I am using nginx/1.4.7
From syslog:
nginx: [emerg] unknown directive "if($http_user_agent"
Add a space between if and (. that should do the trick!
I have a server running at http://localhost:8080 i want a specific url of this server to be proxied by nginx.
For example, i only want http://localhost:8080/test/(.*) to be reverse proxied to http://localhost/test/(.*).
I'm proxing another server to http://localhost/.
What about just a simple location block?
server {
# ... other stuff
location /test/ {
try_files $uri #testproxy;
}
location #testproxy {
proxy_pass http://127.0.0.1:8080;
proxy_set_header X-Forwarded-Host $server_name;
proxy_set_header X-Real-IP $remote_addr;
# all your params
}
}
I made it somehow this way and it worked. Thanks for your comment anyway. :)
server {
listen 80;
# ... other stuff
upstream backend1 {
server 127.0.0.1:8080;
}
location /test/ {
proxy_pass_header Server;
proxy_set_header Host $http_host;
proxy_redirect off;
proxy_set_header X-Real-IP $remote_addr;
proxy_set_header X-Scheme $scheme;
proxy_pass http://backend1/test/;
}
}