NGINX proxy pass a portion of the request URL - nginx

I would like to do the following in my NGINX configuration: I want to proxy pass the path and query parameters but not include the first path parameter (path1).
Request URL
https://my-domain.com/path1/path2?query1=some-query
I want this to proxy_pass to
http://localhost:8000/path2?query1=some-query
I have tried with the following location block
location /path1/path2/ {
proxy_pass http://localhost:8000$request_uri;
proxy_http_version 1.1;
}
However, this does not go to the correct endpoint because I think it includes the path1 parameter too. I have several different path2 routes and so I want to be able to catch and redirect them all easily - without having to manually define each one like this:
location /path1/path2a/ {
proxy_pass http://localhost:8000/path2a?query1=some-query;
proxy_http_version 1.1;
}
location /path1/path2b/ {
proxy_pass http://localhost:8000/path2b?query1=some-query;
proxy_http_version 1.1;
}
location /path1/path2c/ {
proxy_pass http://localhost:8000/path2c?query1=some-query;
proxy_http_version 1.1;
}
ADDITIONAL EDIT:
I also cannot simply do
location /path1/ {
proxy_pass http://localhost:8000/;
proxy_http_version 1.1;
}
because I already have the location /path1/ block that gets upgraded to a WebSocket connection at a different endpoint:
location /path1/ {
proxy_pass http://localhost:9000/;
proxy_http_version 1.1;
proxy_set_header Upgrade $http_upgrade;
proxy_set_header Connection "Upgrade";
}
I have searched a lot online but cannot find a configuration that works for my specific scenario.

This is really simple:
location /path1/ {
proxy_pass http://localhost:8000/;
proxy_http_version 1.1;
}
Read this Q/A for details.
Update
This solution isn't usable after OP clarifies his question.
If all of the additional paths share common suffix path2:
location /path1/path2 {
rewrite ^/path1(.*) $1 break; # remove '/path1' URI prefix
proxy_pass http://localhost:8000;
proxy_http_version 1.1;
}
If they aren't, replace location /path1/path2 with location ~ ^/path1/(?:path2a|path2b|path2c).
If you need to pass to the backend query arguments that are different from those came with the request, use
set $args query1=some-query;
within the location block.

Related

Route different base path to same proxy pass Nginx

I want to pass different path to the same proxy_pass but I keep getting 502 Bad gateway.
These path use the same port number but different base path. How do I make it work from what I have which returns an error currently.
this is what my current location looks like
worker_processes 4;
# worker_process auto
events { worker_connections 1024; }
http {
server {
listen 80;
charset utf-8;
location ~ ^/api/v1/(wallet|card)/(.*)$ {
proxy_pass http://wallet-service:3007/api/v1/$1/;
proxy_http_version 1.1;
proxy_set_header Upgrade $http_upgrade;
proxy_set_header Connection 'Upgrade';
proxy_set_header Host $host;
proxy_cache_bypass $http_upgrade;
}
}
}
If you don't need an URI to be changed at all, don't use anything other than the upstream name:
location ~ ^/api/v1/(wallet|card)/ {
proxy_pass http://wallet-service:3007;
...
}
If an URI needs to be rewritten before being passed to the upstream, check this answer to see how to do it.

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

Hide a port from the content-security-policy so that script-src considers the url as self

I'm setting up the content-security-policy for my site , but the script url for my comments system contains a port number i.e http://dev.example.com:8080/client.js.
I have a few other URL's which use ports too and I'd prefer to hide which ports my site uses in case of possible security implications.
How can I hide these URL's containing port numbers so that the CSP considers the URL's as self?
For example instead of http://dev.example.com:8080/client.js I'd like it to be http://dev.example.com/comments/client.js.
I'm on an Nginx server and I've tried playing around with rewriting the URL, but can't get it working.
Here's what I've tried.
This allows me to change the script URL to http://dev.example.com/comments/client.js, but CSP still detects http://dev.example.com:8080/client.js.
location ~ /comments/ {
return 301 http://dev.example.com:8080/client.js;
}
Didn't work
location ~ /comments/ {
rewrite ^/comments/(.*) http://dev.example.com:8080/$1 last;
}
Just to be clear I know I can just throw the URL http://dev.example.com:8080/client.js straight into CSP e.g script-src 'self'
dev.example.com:8080/client.js;, but I want the URL to work with self e.g script-src 'self'.
Returns 502 bad gateway error
location /comments {
proxy_pass http://dev.example.com:8080/;
}
Also returns502 bad gateway.
location = /comments {
return 301 /comments/;
}
location ~ /comments/(?<ndpath>.*) {
proxy_redirect off;
proxy_set_header Host $host;
proxy_set_header X-Forwarded-Host $host;
proxy_set_header X-Forwarded-Server $host;
proxy_set_header X-Forwarded-For $proxy_add_x_forwarded_for;
proxy_http_version 1.1;
proxy_pass_request_headers on;
proxy_set_header Connection "keep-alive";
proxy_store off;
proxy_pass http://dev.example.com:8080/$ndpath$is_args$args;
gzip on;
gzip_proxied any;
gzip_types *;
}
What you are looking for is the concept of a reverse proxy. Described here.
In your case the simplest example is
location /comments {
proxy_pass http://localhost:8080/;
}

nginx reverse proxy "catch-all" 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 /

reroute nginx request url

I have a reverse nginx proxy where I want to route all request that come in with :
http://dns.com/content/xyz <β€”toβ€”> http://dns.com/content/1.0/xyz
I have an upstream :
upstream backend_api.content.com {
server localhost:8080 max_fails=5 fail_timeout=30;
keepalive 100;
}
and location :
#Content Service
location ~* ^/content/?(.*) {
set $proxy_pass "http://backend_api.content.com";
rewrite ^/content/1.0(/.*)$ /content/1.0$1 break;
proxy_pass $proxy_pass
proxy_http_version 1.1;
proxy_set_header Connection "";
proxy_set_header X-Real-IP $remote_addr;
proxy_set_header Host "api.stg.xxx.com";
proxy_set_header X-3scale-proxy-secret-token $secret_token;
proxy_set_header Original-Host $http_host;
proxy_set_header Authorization $outbound_auth_header;
proxy_set_header Original-Uri $scheme://$http_host$uri;
post_action /out_of_band_oauth_authrep_action;
}
but it seems like anything with http://dns/content/xyz fails and only when I give http://dns/content/1.0/xyz does it work.
You seem to be capturing part of the URI on the location ~* ^/content/?(.*) statement, but do nothing with it.
You also have a rewrite ^/content/1.0(/.*)$ /content/1.0$1 break; statement that does nothing, it simply writes the same URI back.
A quick and dirty solution might be to use two rewrite statements like this:
rewrite ^/content/1.0(/.*)$ /content/1.0$1 break;
rewrite ^/content(/.*)$ /content/1.0$1 break;
Which means that anything that does not match the first (non-) rewrite will be processed by the second, and get a /1.0 inserted.
Personally, I do not like it, and would rather use two location blocks:
location /content/1.0 {
set $proxy_pass "http://backend_api.content.com";
proxy_pass $proxy_pass;
proxy_http_version 1.1;
proxy_set_header ...
...
}
location /content {
rewrite ^/content(/.*)$ /content/1.0$1 last;
}
But check the evaluation order of your other location blocks. Note that prefix location blocks and regular expression location blocks have different evaluation rules. See this document for details.

Resources