Intercept all nginx locations for auth - nginx

I'm wondering how to explicitly set up auth checks in one place for every location. Doing something like below seems like it's prone to errors (missing an entry, typos, unnecessary duplication, etc)
nginx.conf
location / {
auth_request /someAuth;
auth_request_set $someVar $someOtherVar;
proxy_pass https://somewhere.com:1234;
proxy_set_header X-Forwarded-For $remote_addr;
}
location /foo {
auth_request /someAuth;
auth_request_set $someVar $someOtherVar;
proxy_pass https://somewhereElse.com:6578;
proxy_set_header X-Forwarded-For $remote_addr;
}
location /bar {
auth_request /someAuth;
auth_request_set $someVar $someOtherVar;
proxy_pass https://somewhereOther.com:9876;
proxy_set_header X-Forwarded-For $remote_addr;
}

Maybe using a map directive in a way like
map $uri $proxy {
~^/foo https://somewhereElse.com:6578;
~^/bar https://somewhereOther.com:9876;
default https://somewhere.com:1234;
}
server {
...
location / {
auth_request /someAuth;
auth_request_set $someVar $someOtherVar;
proxy_pass $proxy;
proxy_set_header X-Forwarded-For $remote_addr;
}
}
Please note that such a configuration would require a resolver directive.

Related

How to use vue.js with Nginx?

I want to build a single page application with Vue.js using Nginx as my webserver and a my own Dropwiward REST API. Moreover I use Axios to call my REST request.
My nginx config looks like
server {
listen 80;
server_name localhost;
location / {
root path/to/vue.js/Project;
index index.html index.htm;
include /etc/nginx/mime.types;
}
location /api/ {
rewrite ^/api^/ /$1 break;
proxy_pass http://localhost:8080/;
}
}
Currently I can just call my localhost/api/path/to/rescource to get the the information from the backend.
I build the Front end with HTML and javascript(vue.js) which has worked so far. However when I want to build a single page application most tutorials mention node.js. How can I use Nginx instead?
Add the following code to your Nginx Config, as detailed in the VueRouter docs, here:
location / {
try_files $uri $uri/ /index.html;
}
Also, you need to enable history mode on VueRouter:
const router = new VueRouter({
mode: 'history',
routes: [...]
})
I struggled with same problem. But I found how can I do. You just add this to your nginx.conf.
location / {
root /home/admin/web/domain.com/public_html/; #-> index.html location
index index.html;
include /etc/nginx/mime.types;
try_files $uri $uri/ /index.html;
}
This worked for me:
location /static/ {
root /root/bdn/bdn/server/;
}
location /media/ {
root /root/bdn/bdn/server/;
}
location ^~ /admin/ { # Define routes to be directed to backend as proxy
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;
proxy_pass http://unix:/run/gunicorn.sock;
}
location ^~ /api/ { # Define routes to be directed to backend as proxy
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;
proxy_pass http://unix:/run/gunicorn.sock;
}
location ^~ /api-auth/ {
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;
proxy_pass http://unix:/run/gunicorn.sock;
}
location ^~ /{
root /root/bdn/bdn/server/templates/;
index index.html;
}
error_page 404 /; # PARTICULARLY THIS ERROR REDIRECTION

Nginx proxy when $http_user_agent matches mobile

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.

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;
}

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.
}

how to reverse proxy via nginx a specific url?

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/;
}
}

Resources