nginx reverse proxy "catch-all" location - nginx-location

EDIT: To be more clear, this is nginx version 1.13.8.
Take the following as an example nginx.conf file:
http {
upstream portal_backend {
server pc-loc43-01:15080;
}
upstream auth_backend {
server pc-loc43-01:16080;
}
server {
listen 9080 default_server;
server_name my-reverse-proxy;
location / {
auth_basic off;
proxy_http_version 1.1;
proxy_set_header Host $http_host;
proxy_pass http://portal_backend/;
}
location /auth {
auth_basic off;
proxy_http_version 1.1;
proxy_set_header Host $http_host;
proxy_pass http://auth_backend/auth;
}
}
}
I want to configure nginx to default to location / if it is unable to match the request to any of the locations, but I cannot find how to do this.

I don't see anything wrong with your code.
location / { is already the default location block for "unhandled" locations.
This would match all locations:
location / {
# ...
}
This would match the root only:
location = / {
# ...
}
This will match /auth and sub directories:
location /auth {
# ...
}

It must be related to how nginx does request matching -- somehow auth and authorize are too similar and it causes nginx problems (not a great explanation and maybe someone more experienced with nginx internals can chime in). The "solution" was to duplicate location / into location /authorize, so now the config file looks like:
...
location / {
auth_basic off;
proxy_http_version 1.1;
proxy_set_header Host $http_host;
proxy_pass http://portal_backend/;
}
location /authorize {
auth_basic off;
proxy_http_version 1.1;
proxy_set_header Host $http_host;
proxy_pass http://portal_backend/;
}
...
All the other routes work as I would have expected, e.g. /users, /customers, /whatever are all handled by location /

Related

nginx: Match multiple locations / disable access log without returning

I would like to disable access logging for some specific paths but still proxy it to another container. In other words "match multiple locations without returning/exiting" which is not possible as far as I know.
The following config will make nginx cancel the request without entering the proxy pass location.
server {
# ...
# do not log requests for /_nuxt/* and /_ipx/*
location ~ ^/(_ipx|_nuxt) {
access_log off;
}
# still proxy these paths
location ~* ^(\/|\/(foo|bar|_nuxt|_ipx)$ {
proxy_pass http://frontend:3000;
proxy_http_version 1.1;
proxy_set_header X-Forwarded-For $remote_addr;
proxy_set_header Host $server_name:$server_port;
}
}
Is there a more clean way of achieving the desired behavior other than duplicating the proxy configuration and adding the access log config line to that second location?
server {
# ...
# proxy pass without _nuxt and _ipx
location ~* ^(\/|\/(foo|bar)$ {
proxy_pass http://frontend:3000;
proxy_http_version 1.1;
proxy_set_header X-Forwarded-For $remote_addr;
proxy_set_header Host $server_name:$server_port;
}
# access log + proxy pass
location ~ ^/(_ipx|_nuxt) {
access_log off;
proxy_pass http://frontend:3000;
proxy_http_version 1.1;
proxy_set_header X-Forwarded-For $remote_addr;
proxy_set_header Host $server_name:$server_port;
}
}
You're right, location working like switch case taking the first hit and break.
Maybe you can try something like that:
if ($request_uri ~ ^/(_ipx|_nuxt)) {
access_log off;
}
instead of your first location statement.
The access_log directive has the following syntax:
access_log path [format [buffer=size] [gzip[=level]] [flush=time] [if=condition]]; ...
...
The if parameter (1.7.0) enables conditional logging. A request will not be logged if the condition evaluates to “0” or an empty string. In the following example, the requests with response codes 2xx and 3xx will not be logged:
map $status $loggable {
~^[23] 0;
default 1;
}
access_log /path/to/access.log combined if=$loggable;
Applied to the asked question, that means the following config should achieve the desired goal:
map $uri $loggable {
~^/_(ips|nuxt) 0;
default 1;
}
server {
...
access_log /path/to/access.log <format> if=$loggable;
}

nginx redirect different roots to different ports

After hours of checking documents and stackoverflow, I still cannot figure out how to do this.
this is my nginx.conf:
http {
upstream backend {
least_conn;
server 192.168.77.81:8078 weight=4;
server 192.168.77.231:8078 weight=7 max_fails=1 fail_timeout=1s;
}
upstream static_backend {
server 192.168.77.81:8079;
}
server {
listen 8068;
access_log off;
error_log off;
location / {
proxy_pass http://backend;
proxy_set_header Host $host;
proxy_set_header X-Real-IP $remote_addr;
proxy_set_header X-Forwarded-For $proxy_add_x_forwarded_for;
}
location /static/ {
proxy_pass http://192.168.77.81:8079;
}
}
}
events {}
I want to redirect all the http://192.168.77.81:8068/static to http://192.168.77.81:8079/static
but it all results in either 301 Moved Permanently or http://192.168.77.81:8078/static
which drive me crazy
I also have tried alias and root, and they don't work as well
any advice would be very appreciated!
simply just do proxy_pass ~ /static
this "~" took me hours...

NGINX Rewrite ignored / not working with proxy_pass

Bug in the upstream vendor app. Wrote a route in our node app to proxy the request and avoid the bug but can't get the NGINX rewrite to work correctly. I've tried many variations of rewrite and now at my wit's end. Spent more time on the rewrite than the actual code... =(
IN: /Txtranscription/transcription/TranscriptionHandler.ashx?q=c3R1ZHlfaWQ...
OUT: /Txtranscription/transcription/TranscriptionHandler.ashx?q=c3R1ZHlfaWQ...
EXPECTED: /transcription?encoded=c3R1ZHlfaWQ...
### override handling of /Txtranscription/transcription/TranscriptionHandler.ashx
location /Txtranscription/transcription/TranscriptionHandler.ashx {
add_header Access-Control-Allow-Origin $cors_header;
access_log logs/vapi.proxy.log lfupstream;
error_log logs/vapi.error.log error;
rewrite ^/Txtranscription/transcription/TranscriptionHandler\.ashx\?q=(.*)$ /transcription?encoded=$1 break;
proxy_pass http://vapi;
}
You shouldn't need to rewrite the request at all, you can append a path to a proxy_pass directive and Nginx will replace the matching part of the location block from the original request URI with the URI of your proxy_pass directive.
So this should work:
location /Txtranscription/transcription/TranscriptionHandler.ashx {
set $args encoded=$arg_q;
....
proxy_pass http://vapi/transcription$is_args$args;
Example:
location ~ ^/connector(/?)(.*)$ {
proxy_buffer_size 64k;
proxy_buffers 16 32k;
proxy_http_version 1.1;
proxy_set_header X-Real-IP $remote_addr;
proxy_set_header Connection "Keep-Alive";
proxy_set_header Proxy-Connection "Keep-Alive";
proxy_set_header Authorization "";
set $upstream_endpoint http://YOUR-END-POINT/$2$is_args$args;
proxy_pass $upstream_endpoint;
}
The magic is -> location ~ ^ /admin (/?)(.*)$
And then -> /$2$is_args$args;

How to configure Nginx to try two upstreams before 404ing?

Given an Nginx configuration roughly like this:
upstream A {
server aa:8080;
}
upstream B {
server bb:8080;
}
server {
listen 80;
location #backendA {
proxy_pass http://A/;
}
location #backendB {
proxy_pass http://B/;
}
location / {
# This doesn't work. :)
try_files #backendA #backendB =404;
}
}
Basically, I would like Nginx to try upstream A, and if A returns a 404, then try upstream B instead, and failing that, return a 404 to the client. try_files does this for filesystem locations, then can fall back to a named location, but it doesn't work for multiple named locations. Is there something that will work?
Background: I have a Django web application (upstream A) and an Apache/Wordpress instance (upstream B) that I would like to coexist in the same URL namespace for simpler Wordpress URLs: mysite.com/hello-world/ instead of mysite.com/blog/hello-world/.
I could duplicate my Django URLs in the Nginx locations and use wordpress as a catch-all:
location /something-django-handles/ {
proxy_pass http://A/;
}
location /something-else-django-handles/ {
proxy_pass http://A/;
}
location / {
proxy_pass http://B/;
}
But this violates the DRY principle, so I'd like to avoid it if possible. :) Is there a solution?
After further googling, I came upon this solution:
location / {
# Send 404s to B
error_page 404 = #backendB;
proxy_intercept_errors on;
log_not_found off;
# Try the proxy like normal
proxy_set_header X-Forwarded-For $remote_addr;
proxy_set_header Host $host;
proxy_set_header X-Real-IP $remote_addr;
proxy_pass http://A;
}
location #backendB {
# If A didn't work, let's try B.
proxy_set_header X-Forwarded-For $remote_addr;
proxy_set_header Host $host;
proxy_set_header X-Real-IP $remote_addr;
proxy_pass http://B;
# Any 404s here are handled normally.
}

Nginx - reverse proxy a Ghost blog with /subfolder redirect

I have a working nginx instance with the rules below. But I'm having difficulties pointing all the requests to domain.com/ghost
I tried modifying the location / {} block to location /ghost/ {} but with no success. I just get a 404 from the ghost app. Any suggestions?
server {
listen 80;
server_name domain.com;
root /home//user/ghost/;
index index.php;
# if ($http_host != "domain.com") {
# rewrite ^ http://domain.com$request_uri permanent;
# }
location / {
proxy_set_header X-Real-IP $remote_addr;
proxy_set_header X-Forwarded-For $remote_addr;
proxy_set_header Host $host;
proxy_pass http://127.0.0.1:2368;
}
location ~* \.(?:ico|css|js|gif|jpe?g|png|ttf|woff)$ {
access_log off;
expires 30d;
add_header Pragma public;
add_header Cache-Control "public, mustrevalidate, proxy-revalidate";
proxy_pass http://127.0.0.1:2368;
}
location = /robots.txt { access_log off; log_not_found off; }
location = /favicon.ico { access_log off; log_not_found off; }
location ~ /\.ht {
deny all;
}
}
I'm using a regexp location directive for a similar proxy setup. This is the minified configuration file:
worker_processes 1;
pid /path/to/file.pid;
worker_priority 15;
events {
worker_connections 512;
accept_mutex on;
}
http {
server {
error_log /path/to/log/error.log error;
listen 127.0.0.1:9000;
server_name example.com;
location ~* (/ghost) {
expires epoch;
proxy_no_cache 1;
proxy_pass http://localhost:1234;
}
location / {
proxy_pass http://localhost:1234;
}
}
}
Have solved similar problem with other apps which have no support for subfolders. Both apps are built on one platform, so they both tries to work in /fx dir. I had to place one of them in to subfolder /gpms .
The idea is to redirect requests with referer from subfolder to destinations which links outside of subfolder - i just add subfolder to beginning of such uris. It is not ideal, but it works.
Here is my nginx config:
server {
listen 80;
server_name mydomain.com;
location / {
rewrite ^/$ /fx/;
proxy_pass http://127.0.0.1:56943/;
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_read_timeout 300;
}
error_log /var/log/nginx/debug.log debug;
set $if_and_hack "";
if ( $http_referer ~ '^http://mydomain.com/gpms/.*$' ) {
set $if_and_hack "refgpms";
}
if ( $uri !~ '^/gpms/.*$' ) {
set $if_and_hack "${if_and_hack}_urinogpms";
}
if ( $if_and_hack = "refgpms_urinogpms" ) {
rewrite ^/(.*)$ http://$host/gpms/$1;
}
location /gpms/ {
proxy_set_header X-Real-IP $remote_addr;
proxy_set_header X-Forwarded-For $proxy_add_x_forwarded_for;
proxy_cookie_path /fx /;
proxy_pass http://127.0.0.1:12788/fx/;
proxy_redirect default;
}
}
External links will be broken, but it is not critical for me and i guess it may be corrected.
$if_and_hack is for overcome nginx limitation on nested conditions.
By the way i have got a cookies issue, because they was set with path, and hit browser bug with not sending cookies for a new path after redirect, so i just remove path from cookies.
Note full link form in rewrite - this form of rewrite immediately redirects browser to new page, you should not change it to just "/gpms/$1".
As alternative, i guess, it may be possible to use nginx module to inspect html content and modify links. I have not tried this. Or consider to use subdomains instead of subfolders.
Good news! As of version 0.4.0 Ghost now supports subdirectory installation. And there are already people who've figured this out and created tutorials.

Resources