Nginx keep-alive w/o upstream - nginx

I'm using a variable to define my proxy_pass target, similar to this answer except in my case the value is extracted from a query param on the incoming request, so e.g. /?url=http://example.com will be proxied to example.com. Since the proxy_pass argument is a variable, I have no upstream directive in my config. The proxying works fine. However, the connection is closed after each request and I want to them alive to amortize the TCP handshake. According to these directions, that requires a keepalive directive in the upstream directive. How can I do this without an upstream directive?
Here's my full config:
server {
if ($arg_url ~ \/\/([^\/]*)) {
set $proxy_host $1;
}
if ($proxy_host = "") {
return 404;
}
resolver 8.8.8.8;
location / {
proxy_http_version 1.1;
proxy_set_header Connection "";
proxy_set_header Host $proxy_host;
proxy_pass $arg_url;
}
}

Related

Nginx Proxy Pass not passing port

I'm working locally for the moment.
I have an NGINX configuration for nuxtwoo.example.com.
Whenver I visit nuxtwoo.example.com, I need it to proxy localhost:3000, which is working fine, however I also need it to pass the port :300.
location / {
proxy_pass http://localhost:3000;
}
What I need,
http://nuxtwoo.example.com -> proxy_pass : localhost: 3000 -> URL in browser, nuxtwoo.example.com:3000.
This will also need to for other params, such as nuxtwoo.example.com/blog, should go proxy_pass localhost:3000/blog, and the browser url should be nuxtwoo.example.com:3000/blog.
Can't seem to figure this one out.
You need to use an upstream
upstream http_backend {
server 127.0.0.1:8080;
keepalive 16;
}
server {
...
location /http/ {
proxy_pass http://http_backend;
proxy_http_version 1.1;
proxy_set_header Connection "";
...
}
}

Nginx upstream retry based on response

Not all API operations are retriable, so backend send a header retriable = true if the operations can be retried.
How can I say Nginx: retry if the upstream response contains the retriable header?
upstream mash {
ip_hash;
server 127.0.0.1:8081;
server 192.168.0.11:8081;
}
server {
location / {
if ($request_method = POST ) {
proxy_next_upstream error;
}
if ($request_method = PUT ) {
proxy_next_upstream error;
}
proxy_pass http://mash/;
proxy_set_header Host $host;
proxy_set_header X-Real-IP $remote_addr;
proxy_set_header X-Forwarded-For $proxy_add_x_forwarded_for;
}
}
The logic I want to implement is the following:
if(response.hasHeader('Retriable') {
do_retry
} else{
return_backend_response;
}
The Retrier Service
Create a second upstream retrier with a very simple web server running that forwards all requests back to nginx on a special port. Then nginx will forward the requests to the mash upstream. When the response comes back to nginx, the response will get sent to retrier and the logic for retrying can be executed there.

Nginx proxy_pass returns [No Host] while reverse proxying

I'm trying to reverse proxy an api with Nginx. I have the following configuration:
worker_processes 4;
events { worker_connections 1024; }
http {
upstream some_upstream {
server 1.something.com;
server 2.something.com;
}
server {
listen 80;
location ~/proxyNow/(?<zvar>(\w+))/(?<xvar>(\w+))/(?<yvar>(\w+))/ {
proxy_pass http://some_upstream/hello/something/$zvar/$xvar/$yvar/somethingelese;
proxy_set_header Host $http_host;
proxy_set_header Host $host;
proxy_set_header X-Forwarded-For $remote_addr;
proxy_cache maps_cache;
proxy_cache_valid 200 302 365d;
proxy_cache_valid 404 1m;
proxy_redirect off;
}
}
}
When I try to call the following url http://localhost:82/proxyNow/1/2/3/?app_id=someAppId&app_code=someCode
I get the following error message:
Invalid URL
The requested URL
"http://%5bNo%20Host%5d/hello/something/1/2/3/somethingelese", is
invalid. Reference #9.be35dd58.1489086561.5c9bd3c
It seems that the host cannot be retrieved by nginx. But if I execute the call directly:
http://1.something.com/hello/something/$zvar/$xvar/$yvar/somethingelese?app_id=someAppId&app_code=someCode
http://2.something.com/hello/something/$zvar/$xvar/$yvar/somethingelese?app_id=someAppId&app_code=someCode
It seems that Nginx for some reason is not able to resolve the host
You should take a look into the doc.
http://nginx.org/en/docs/http/ngx_http_proxy_module.html#proxy_pass
When location is specified using a regular expression.
In this case, the directive should be specified without a URI.
I suggest the following solution without expensive regex location.
http://nginx.org/en/docs/http/ngx_http_core_module.html#location
location /proxyNow/ {
rewrite /proxyNow/(?<zvar>(\w+))/(?<xvar>(\w+))/(?<yvar>(\w+))/.* /hello/something/$zvar/$xvar/$yvar/somethingelese$is_args?$args break;
proxy_pass http://some_upstream;
... other nginx diretives;
}

how to expose server port in upstream block of Nginx configuration?

We have a handful of homogenous application loosely under SOA pattern. Because of homogeneity, we have been able to define some neat pattern in Nginx to proxy all of our SOA apps through one configuration. Following Nginx configuration is absolutely working absolute wonders in conjunction with DNSmasq to resolve anything.yourdomain.devel eg. a.stackoverflow.devel, b.stackoverflow.devel domains and route that to appropriate app servers under your project folder via designated ports via maps.
worker_processes 2;
events {
worker_connections 1024;
}
http {
map $host $static_content_root {
hostnames;
default /path/to/project/folder;
# For typical standalone apps living in your project directory
# *.myapp.local.devel -> /path/to/project/myapp/public
~^([^\.]+\.)*(?<app>[^\.]+)\.devel$ /path/to/project/folder/$app/public; #rails pattern
}
map $app $devel_proxy_port1 {
default 3000;
domain1 3000;
domain2 4000;
}
map $app $devel_proxy_port2 {
default 3001;
domain1 3001;
domain2 4001;
}
server {
listen 127.0.0.1;
server_name ~^([^\.]+\.)*(?<app>[^\.]+)\.[^\.]+.devel$;
location / {
root $static_content_root; # Using the map we defined earlier
try_files $uri $uri/index.html #dynamic;
}
location #dynamic {
proxy_http_version 1.1;
proxy_set_header Upgrade $http_upgrade;
proxy_set_header Connection "upgrade";
proxy_set_header Host $http_host;
proxy_set_header X-Real-IP $remote_addr;
proxy_set_header X-Forward-For $proxy_add_x_forwarded_for;
proxy_set_header X-Forward-Proto http;
proxy_set_header X-Nginx-Proxy true;
proxy_redirect off;
proxy_pass http://127.0.0.1:$devel_proxy_port1;
}
}
}
Now, in order to simulate multiple servers behind Nginx load balancer. I thought of doing following proxy configuration which points to upstream rather than directly pointing to one server:port pair.
proxy_pass http://backend;
upstream backend {
server http://127.0.0.1:$devel_proxy_port1;
server http://127.0.0.1:$devel_proxy_port2;
}
I thought above would work but it always emits following error hinting the variables of map blocks are not available inside upstream context.
[emerg] 69478#0: invalid host in upstream "http://127.0.0.1:$devel_proxy_port1" in /usr/local/etc/nginx/nginx.conf:57
Is this an expected behavior?
Yes, variable can not be used inside upstream. You can create few upstream blocks with different names (upstream backend, upstream backend_domain, etc), resolve upstream name through map and put this variable to proxy_pass:
upstream backend {
server http://127.0.0.1:3000;
server http://127.0.0.1:3001;
}
upstream backend_domain1 {
server http://127.0.0.1:3002;
server http://127.0.0.1:3003;
}
upstream backend_domain2 {
server http://127.0.0.1:3004;
server http://127.0.0.1:3005;
}
...
upstream backend_domain30 {
server http://127.0.0.1:3060;
server http://127.0.0.1:3061;
}
map $app $devel_proxy {
default backend;
domain1 backend_domain1;
domain2 backend_domain2;
...
domain30 backend_domain30;
}
...
proxy_pass $devel_proxy;
...
In some cases you can skip map block using $app inside proxy_pass: proxy_pass backend_$app;, but need additional checks for $app values. Also, map allow to to map different "domains" to same applications.

Nginx rewrite based on header value

I have a nginx.conf which basically looks like (unnecessary parts omitted):
upstream app {
server unix:/tmp/unicorn.myapp.sock fail_timeout=0;
}
server {
listen 80;
location #app {
proxy_set_header X-Forwarded-For $proxy_add_x_forwarded_for;
proxy_set_header Host $http_host;
proxy_redirect off;
proxy_pass http://app;
}
}
I want to configure nginx so that the value of a specific header is used to rewrite the url being passed to the upstream.
For example, let's assume that I have a request to /test with the header Accept: application/vnd.demo.v1+json. I'd like it to be redirected to the upstream URL /v1/test, i.e. basically the upstream app will receive the request /v1/test without the header.
Similarly, the request to /test and the header Accept: application/vnd.demo.v2+json should be redirected to the upstream URL /v2/test.
Is this feasible? I've looked into the IfIsEvil nginx module, but the many warnings in there made me hesitant to use it.
Thanks,
r.
edit
In case there's no match, I'd like to return a 412 Precondition Failed immediately from nginx.
If Accept header does not contain required header return error.
map $http_accept $version {
default "";
"~application/vnd\.demo\.v2\+json" "v2";
"~application/vnd\.demo\.v1\+json" "v1";
}
server {
location #app {
if ($version = "") {
return 412;
}
...;
proxy_pass http://app/$version$uri$is_args$args;
}
}

Resources