Nginx - pass proxy_cache value with proxy_cache_bypass - nginx

I have multiple proxy_cache_path directives and in the http block and I want to pass the value of the proxy_cache variable to a lua modul. However, I do not want to define the route (/tmp/cache/BackendA or /tmp/cache/BackendB, etc) more than once. I would rather store it in a variable.
My config snippet:
http {
proxy_cache_path /tmp/cache/BackendA keys_zone=BACKEND_A_PROXYCACHE:50m max_size=1g use_temp_path=off inactive=20m;
proxy_cache_path /tmp/cache/BackendB keys_zone=BACKEND_B_PROXYCACHE:100m max_size=2g use_temp_path=off inactive=30m;
# ...
server {
# ...
location =/BackendA/ServiceA {
# ...
proxy_cache BACKEND_A_PROXYCACHE;
# set $cache_folder_path "/tmp/cache/BackendA";
set $cache_folder_path $proxy_cache;
proxy_cache_bypass $cache_folder_path;
}
location =/BackendB/ServiceB {
# ...
proxy_cache BACKEND_B_PROXYCACHE;
# set $cache_folder_path "/tmp/cache/BackendA";
set $cache_folder_path $proxy_cache;
proxy_cache_bypass $cache_folder_path;
}
}
}
If i try to use set $cache_folder_path $proxy_cache; command then i can't start the nginx server.
Error message:
nginx: [emerg] unknown "proxy_cache" variable
I'm looking for a more elegant solution than the commented part:
set $cache_folder_path "/tmp/cache/BackendA";
The question is what should I do now? Will be grateful for any help.

if you using Linux and if is support apt-get, for cache module
apt-get install nginx-extras

Related

nginx get value of proxy_http_header

I add an traceId in my nginx config via $proxy_http_header. Here is the config:
location ~ /(xxx.*) {
proxy_set_header trace_id $connection-$connection_requests-$msec;
}
Now I need to print it in my Nginx log. How can I get it? It does not work if I get it via $http_trace_id. like
log_format normal '$remote_addr'
'"$http_trace_id"';

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.

conditional routing with nginx based on referer

I need to route traffic based on the http request origin. I have two environments and we need to redirect every http request for "/us-en" to Environment1 and others to Environment2 using "$http_referer".
Redirection based on location works.
location ~ /us-en {
proxy_pass Environment1;
proxy_set_header Host Environment1;
}
With '$http_referer' the below option does not work. Request your suggestion on the same.
if ($http_referer ~ ^https?://dev.xyz.com/us-en){
rewrite ^/us-en(/*)$ HOME_PAGE$1 break;
proxy_pass Environment1;
}
Error: nginx: [emerg] "proxy_pass" directive is not allowed here in /opt/nginx/conf/nginx.conf.
Note: By default all the traffic goes to Environment2 as an upstream configuration is present.
# needed if your proxy destination specified with domain name instead of IP address
resolver 8.8.8.8;
location /home/ {
proxy_set_header Host HOST1;
# setup other proxied headers if needed
if ($http_referer ~ ^https?://dev.xyz.com/home) {
rewrite ^/home(/.*)$ HOME_PAGE$1 break;
proxy_pass https://HOST1:8080; # this can be specified by IP address
}
}
With such configuration requests to your_domain.com/home/path/file from dev.xyz.com/home/... (but not from dev.xyz.com/any/other/path!) will be proxied to https://HOST1:8080/HOME_PAGE/path/file. If you specify your proxy destination with domain name instead of IP address, you'll need to specify the additional parameter resolver in your server config. You can use your local name server if you have one, or use something external like Google public DNS (8.8.8.8) or DNS provided for you by your ISP. Anyway such configuration leads to additional DNS lookups, so if you can, specify your proxy destination with IP address.
Update
There is another way to do it with the valid_referers directive:
# needed if your proxy destination specified with domain name instead of IP address
resolver 8.8.8.8;
location /home/ {
proxy_set_header Host HOST1;
# setup other proxied headers if needed
valid_referers example.com/home;
if ($invalid_referer = "") {
rewrite ^/home(/.*)$ HOME_PAGE$1 break;
proxy_pass https://HOST1:8080; # this can be specified by IP address
}
}
Update # 2020.11.11
Besides this answer somehow achieved a score of 5, the given solution has an extremely bad design (it isn't a good approach to have different content handlers in the location and the nested if block; moreover, having an if block with any directive other than from the nginx rewrite module should be avoided if possible) and won't work at all on early nginx versions (I wanna cry when I look at some of my early answers). An original OP question was
The logic should be like below but has some syntax mistakes.
if ($http_origin ~ '^http?://(dev.xyz.com/home)') {
set $flag 'true';
}
if ($flag = 'true') {
location /home/ {
proxy_pass "https://HOST1:8080/HOME PAGE/";
}
}else{
Do Not proxy pass
}
It is unclear what do not proxy pass means. If it means returning some HTTP error (for example, HTTP 403 Forbidden), it can be done with the following configuration:
location /home/ {
if ($http_referer !~ ^https?://dev.xyz.com/home) {
return 403;
}
rewrite ^/home(/.*)$ HOME_PAGE$1 break;
proxy_set_header Host HOST1;
# setup other proxied headers if needed
proxy_pass https://HOST1:8080; # this can be specified by IP address
}
If do not proxy pass means to serve the request locally, the solution is more complex:
map $http_referer $loc {
~^https?://dev.xyz.com/home loc_proxy;
default loc_local;
}
server {
...
location /home/ {
try_files /dev/null #$loc;
}
location #loc_proxy {
rewrite ^/home(/.*)$ HOME_PAGE$1 break;
proxy_set_header Host HOST1;
# setup other proxied headers if needed
proxy_pass https://HOST1:8080;
}
location #loc_local {
rewrite ^/home(/.*)$ HOME_PAGE$1 break;
root /path/to/required/page;
...
}
The try_files /dev/null #the_named_location; trick is taken from this excellent answer.
However now the edited OP's question states for a different requirements, which also could be achieved with the map directive help:
map $http_referer $environment {
~^https?://dev.xyz.com/home Environment1;
default Environment2;
}
server {
...
location /home/ {
rewrite ^/home(/.*)$ HOME_PAGE$1 break;
proxy_set_header Host $environment;
# setup other proxied headers if needed
proxy_pass https://$environment;
}

NGINX health check requires an upstream

I have a location like:
location / {
set $api_name "Web";
proxy_intercept_errors on;
set $upstream upstream_a;
if ( $kms_in_cookie != "not_set" ) {
set $upstream $kms_in_cookie;
}
if ( $upstream_in_cookie != "not_set" ) {
set $upstream $upstream_in_cookie;
}
if ($cookie_zak != "") {
set $upstream upstream_b;
}
proxy_pass http://$upstream;
health_check uri=/healthcheck interval=30 fails=3 passes=3;}
Once I restart my NGINX, it failed:
nginx: [emerg] health check requires an upstream in
Any one has a idea about this? What does this error mean?
I had the same issue. From experimenting with it the issue appears to be the variable name in the proxy_pass directive. If you use the name of a valid upstream the issue is resolved.
Clearly you are trying to direct traffic based on some request meta-data, and the above advice wont help with this. Your scenario is not an uncommon one so I would expect this to work. Looks like a bug in nginx, or at the very least a gap in the documentation.

Hot change "Location" in the reply header 302 code from proxy-host.

I have the kubernetes-cluster and a few pods/containers with web-app. Pods connecting to each other by pod's name with listen port 9999 (like security-rest-api:9999, common-rest-api:9999, etc).
To outside listen nginx-pod with outside address http://e.net:30200/.
((app-pods:9999)-(nginx-pod:80)-(nginx-service:30200))-Network
Nginx use follow configuration for interactive with app-pods.
server {
listen 80;
server_name e.net;
location / {
proxy_pass http://web-console:9999/;
proxy_redirect http://web-console:9999/ http://e.net:30200/;
}
location /common {
proxy_pass http://common-rest-api:9999/common;
proxy_redirect http://common-rest-api:9999/ http://e.net:30200/;
}
location /security {
proxy_pass http://security-rest-api:9999/security;
proxy_redirect http://security-rest-api:9999/ http://e.net:30200/;
} }
It's working very well, but I have the one problem with 302-reply from app-pods:
If I try to login in my app, I get follow the 302 reply header:
HTTP/1.1 302 Found
Connection: keep-alive
Content-Length: 0
Date: Wed, 25 Apr 2018 10:37:50 GMT
Location: http://e.net:30200/security/rest/auth/login.html?callbackUrl=http://security-rest-api:9999/security/rest/namespace
Server: nginx/1.13.9
App-pods generated URL parameter "callbackUrl" from the Host request header Inside containers network and this URL parameter to get to the endpoint browser. Of course, next request get 404 code.
I can't to edit app-code (in app-pods don't use nginx), but I want to change 'security-rest-api:9999' to 'e.net:30200' parameter in the Location 302 reply header. How I can do it?
redirect isn't suitable since this generate new 302-reply and not solve my problem.
sub_filter change only reply body, but not reply head (where is Location parameter).
request_uri not working too, since this parameter work with request header only.
No, It's not working.
I tested this situation and finded work's config:
if ($args ~* (.*)(callbackUrl=http://security-rest-api:9999/)(.*)) {
set $args $1callbackUrl=http://e.net:30200/$3;
rewrite ^(.*)$ $1;
}
if ($args ~* (.*)(callbackURL=http%3A%2F%2Fsecurity-rest-api%3A9999%2F)(.*)) {
set $args $1callbackURL=http%3A%2F%2Fe.net%3A30200%2F$3;
rewrite ^(.*)$ $1;
}
location /security {
proxy_pass http://security-rest-api:9999/security;
proxy_set_header Host $http_host;
proxy_redirect http://security-rest-api:9999/ http://e.net:30200/;
}
Later, I will try to use this config on the pre-production stand and if this work (or work after corrects) - I will write it here.
Thanks for help information:
https://blog.imaginea.com/modifying-query-parameters-nginx-in-reverse-proxy-mode/
And thanks for you all, too!
Edit
I tested this config and have 2 edits:
If you to use un-standart port - you need write "proxy_set_header Host $http_host;" in location section;
URL in attributes can be like "http://security-rest-api:9999/" and like "http%3A%2F%2Fsecurity-rest-api%3A9999%2F". You need to use both conditions for each type of attribute.
I corrected code with this edits

Resources