More accurate nginx location matching - nginx

I have the following nginx rule
location /api {
proxy_pass http://flask:5000/api;
proxy_set_header Host $host;
proxy_set_header X-Forwarded-For $proxy_add_x_forwarded_for;
}
It will match the following path, which is what I'm expecting
http://localhost/api
http://localhost/api/
http://localhost/api/a
http://localhost/api?
http://localhost/api?name=value
However, it will also match the following, which I'm not expecting
http://localhost/apii
http://localhost/apiX
May I know how can I avoid from matching unwanted http://localhost/apii and http://localhost/apiX and http://localhost/apiXX and ...

This requires two location blocks - one matching specifically /api and one for everything in the path /api/. In this way urls like /apio will not be captured.
Example:
location = /api {
proxy_pass http://flask:5000/api;
proxy_set_header Host $host;
proxy_set_header X-Forwarded-For $proxy_add_x_forwarded_for;
}
#Querystrings and /api, matches the first, any /api/* matches this one
location /api/ {
proxy_pass http://flask:5000/api;
proxy_set_header Host $host;
proxy_set_header X-Forwarded-For $proxy_add_x_forwarded_for;
}
Reference http://nginx.org/en/docs/http/ngx_http_core_module.html#location

One possibility is to use a regular expression. As the proxy_pass is not actually transforming the URI, the uri element can be safely removed.
location ~ ^/api($|/) {
proxy_pass http://flask:5000;
proxy_set_header Host $host;
proxy_set_header X-Forwarded-For $proxy_add_x_forwarded_for;
}
Note that regular expression location blocks are evaluated in order. See this document for details.

It's actually really simple.
Just change location /api { to location /api/ {
Nginx will add a trailing slash to any request ending /api so there is no need to add a separate block for them. This block will behave as you expected your original one to.

Related

Nginx location to FLASK route

I have 2 docker containers running. 1 is FLASK and 2 is Nginx.
This is the configuration of the Nginx location
location /search/?(.*) {
proxy_pass http://backend:8080/search/;
proxy_http_version 1.1;
proxy_set_header Upgrade $http_upgrade;
proxy_set_header Connection 'upgrade';
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_request_headers on;
}
The FLASK is running on port 8080 and the route #app.route('/search', methods=['GET']) and running with app.config['SERVER_NAME'] = 'mydomain.com'
When I try to send a GET request to "mydomain.com" (going through the NGINX) from external I get
Cannot GET /search
When I remove app.config['SERVER_NAME'] = 'mydomain.com' from the FLASK I can send GET to EXTERNAL_IP:8080 (Directly to the backend not though the NGINX).
But when I leave the app.config['SERVER_NAME'] = 'mydomain.com' and try to GET mydomain.com:8080 I get 404 Not Found
What am I missing here?
I want all requests to go though the NGINX and I want to use mydomain.com
I think your main mistake is that you trying to match the whole request URI including the query part while location directive (as well as the rewrite one) works with the normalized URI which doesn't include the query part at all (check the location directive documentation to find out what URI normalization is). Looks like you are also trying to use a regex while regex location should be declared using a ~ (or ~*) modifier. Nevertheless you don't need any regex locations at all for your particular case. To proxy a single API endpoint preservig the Host HTTP header value, you can try this one:
location = /search {
proxy_pass http://backend:8080;
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;
}
You don't need to specify an URI with the proxy_pass directive since you are not changing your request URI. If your API endpoint is /search/ rather than /search, change the location accordingly. If it is an URI path prefix rather than a single API endpoint, use a prefix location /search/ { ... } instead of exact match location.

NGINX: alias or proxy based on query string

I'm looking for a way to allow a proxy_pass when certain querystrings are in the url and send the URI to an alias the rest of the time.
Here's how I have the in one environment, the location block is configured like this:
location /my-route {
alias /assets/coming-soon/;
index index.html;
}
In another, it's configured like this:
location /my-route {
proxy_pass http://tool_servers/;
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-Host $server_name;
}
I want to combine the two and pass the bare uri to to the coming-soon page, but URIs with ?filter=test to tool_servers.
Proxy config cannot go inside an if ($arg_filter = "test") block (I tried). Is there another work-around?

Nginx - proxy_pass to google storage bucket does not use the index directive

I am trying to set my root(/) location to be passed to a google bucket.
Here is my configuration:
listen 80;
location / {
rewrite /(.*) /$1 break;
proxy_pass https://storage.googleapis.com/my-google-bucket-name/$1$is_args$args;
proxy_redirect off;
index my_main.html;
proxy_set_header Host "storage.googleapis.com";
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_set_header Upgrade $http_upgrade;
proxy_set_header Connection "upgrade";
}
This seems to work but the index directive does not set the default page (to my_main.html)
e.g. when i go to http://my_enginx_url/ instead of reaching "my_main.html" i reach the google bucket root page that shows an XML file with all the files in that bucket.
P.S
Both
http://my_enginx_url/another_page.html,
http://my_enginx_url/yet_another_page.html
are working fine.
Any ideas?
Because the index directive tells Nginx the names of files to look for within your file system which are appropriate for serving a request ending with a /
You are proxying the request to another server, so it's not applicable here.
To achieve your desired result create another location directive above your current one and use = to tell Nginx this is to handle only requests for an exact match with http://my_enginx_url/
Something like this:
location = / {
proxy_pass https://storage.googleapis.com/my-google-bucket-name/my_main.html;
......
}

forward matched specific location and proxy redirect it in nginx

I am trying to forward specific uri if matched to backend in nginx. For example
forward https://www.hostname.com/*/a/b/c to https://int.hostname.com/*/a/b/c (Where * is a variable auto populated from regex)
Current configuration looks like below and have no idea how to proceed on above
location /a/b/c/ {
proxy_set_header Host $proxy_host;
proxy_set_header X-Forwarded-Proto $scheme;
proxy_set_header X-Real-IP $remote_addr;
proxy_set_header X-Forwarded-For $proxy_add_x_forwarded_for;
proxy_read_timeout 180m;
proxy_pass http://int.hostname.com/v2/e/t/a/b/c;
proxy_redirect default;
}
If you want your location to match any URI that ends with /a/b/c/, you will need to use regular expression syntax. See this document for details.
The URI suffix of the proxy_pass statement is optional. In the absence of a URI suffix, the original URI will be passed unmodified. See this document for details.
For example:
location ~ /a/b/c/$ {
...
proxy_pass http://int.hostname.com;
...
}

Nginx location rules conflict with controller

So I have an nginx rule location set like this:
location /foo {
proxy_pass http://<a-service-discovery-url>/foo/;
proxy_redirect default;
proxy_set_header X-Real-IP $remote_addr;
proxy_set_header X-Forwarded-For $proxy_add_x_forwarded_for;
}
Then I have a controller url like:
/foo-bar/bizz
The weird thing is that when I hit the controller in /foo-bar/bizz I get redirected to /foo again which is not desired.
I've tried many rule combinations all resulting in undesired behaviors:
location /foo/
or
location = /foo
or
location = /foo/
Also any regex defined with ~ won't work because the proxy_pass contains the world foo which is in the location rule.
having the trailing slash is not desired because then the user will have to explicitly write it.
Any help would be appreciated.
Thanks.
Have you tried dropping the trailing slash from the proxy_pass url when you add it to the location.
location /foo/ {
proxy_pass http://<a-service-discovery-url>/foo;
proxy_redirect default;
proxy_set_header X-Real-IP $remote_addr;
proxy_set_header X-Forwarded-For $proxy_add_x_forwarded_for;
}

Resources