I would like to create a location which catches both http://example.com and http://example.com/ and another location which catches everything else. The first one will serve static html and the other one is for the api and other stuff. I've tried with this:
location ~ /?$ {
root /var/www/prod/client/www;
}
location ~ /.+ {
# https://stackoverflow.com/questions/21662940/nginx-proxy-pass-cannot-have-uri-part-in-location
rewrite ^/(.*) /$1 break;
proxy_set_header X-Real-IP $remote_addr;
proxy_set_header X-Forwarded-For $proxy_add_x_forwarded_for;
proxy_set_header Host $http_host;
proxy_set_header X-NginX-Proxy true;
proxy_connect_timeout 1s;
proxy_send_timeout 30s;
proxy_read_timeout 300s;
send_timeout 300s;
proxy_redirect off;
proxy_pass http://backendPro;
}
But does not work. I've tried with many options in first location, but when it matches first then second is not matching and vice-versa:
location / {
location ~ \/?$ {
location ~ ^/?$ {
It is actually much simpler:
location = / {
# Exact domain match, with or without slash
}
location / {
# Everything except exact domain match
}
Because location = / is more specific, it is always preferred if only the domain name is called (order of the location blocks does not matter).
You need regex in Nginx much less than you would think, because normal location blocks match every URL that matches the beginning, so location /bla matches every URL on the domain which starts with /bla (like /blabla, or /bla/blu, or /bla.jpg). I would mainly recommend regex if you need capturing groups and do something with those.
Related
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;
}
Today I used two servers for nginx, the content of nginx.conf as follows:
#192.168.2.98
server {
listen 8091;
location ^~ /ttank {
alias /develop/servers-running/front/vue-public/dist;
index index.html;
try_files $uri $uri/ /ttank/index.html;
}
}
#192.168.2.97
location /ttank {
proxy_pass http://192.168.2.98:8091;
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_redirect off;
}
I can access the 192.168.2.98:8091/ttank by enter address: http://192.168.2.98:8091/ttank in chrome, I also can access 192.168.2.98's ttank by entering the address http://192.168.2.97/ttank/, but when I change the addres http://192.168.2.97/ttank/ into http://192.168.2.97/ttank, my chrome entered into waiting status forever, the only difference between two addresses is the last "/", I don't know how to modify the config file for removing the last "/" when accessing ttank by 192.168.2.97?
Try usinge a rewrite rule to get rid of the ending slashes
location /ttank {
rewrite ^/(.*)/$ /$1 break;
...;
...;
proxy_pass ...;
}
it should do it
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.
I need to rewrite any root subdomain requests and append locale params if they aren't already there. e.g. -> de.example.com needs to be rewritten as -> de.example.com/?locale=de. then I proxy it off to the app.
2 questions:
1) is this the correct approach? or should I be using regex instead here? (new to this
so if other problems, please lmk)
2) is there a way to log things inside the location block? Having trouble getting same config working on another server, logging would help. (e.g logging what args is if it isn't matching, or if it matches on another location block).
It only needs to happen on the root page so this is my current config
#existing default (nonsubdomain block)
server {
server_name _;
root /var/www/web_app;
try_files $uri/index.html $uri.html $uri #app;
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_server;
}
}
#just added for subdomain
server {
server_name de.example.com;
root /var/www/web_app;
location / {
try_files $uri/index.html $uri.html $uri #app;
}
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_server;
}
location = / {
if ($args != locale=de ){
rewrite ^ $scheme://de.example.com/?locale=de permanent;
}
proxy_set_header X-Forwarded-For $proxy_add_x_forwarded_for;
proxy_set_header Host $http_host;
proxy_redirect off;
proxy_pass http://app_server;
}
}
1) is this the correct approach? or should I be using regex instead here? (new to this so if other problems, please lmk)
You should use $arg_locale != de instead of $args != locale=de. Look at the docs: http://nginx.org/en/docs/http/ngx_http_core_module.html#var_arg_
2) is there a way to log things inside the location block? Having trouble getting same config working on another server, logging would help. (e.g logging what args is if it isn't matching, or if it matches on another location block). It only needs to happen on the root page so this is my current config
Debug log: http://nginx.org/en/docs/debugging_log.html
(sorry for my bad english)
i have a URL like this:
http://www.domain.com/resize.php?pic=images/elements/imagename.jpg&type=300crop
that php checks if that image exists and serves, if not, creates image on disk with the size specified in the type parameter and returns it.
what I wanted is to check if the image exists on disk at that size, with nginx, so run only resize.php when necessary to create the image.
I tried this, but i think that location directive doesn't operate on query parameters ($args) using regex, then loncation does not match with sample URL :(
any help please?
I need to rewrite the parameters ($args) and use them in the try_files directive... is this possible?
location ~ "^/resize\.php\?pic=images/(elements|gallery)/(.*)\.jpg&type=([0-9]{1,3}[a-z]{0,4})$)" {
try_files /images/$1/$2.jpg /imagenes/elements/thumbs/$3_$2.jpg #phpresize;
}
location #phpresize {
try_files $uri =404;
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_buffering on;
proxy_pass http://www.localhost.com:8080;
}
You cannot match query string in location (e.g., see here and here). The only way to process requests differently depending on the query string contents is to use if and conditional rewrites.
However, if it is OK to handle requests to /resize.php which do not have expected query parameters using the #phpresize location config, you can try something like this:
map $arg_pic $image_dir {
# A subdirectory with this name should not exist.
default invalid;
~^images/(?P<img_dir>elements|gallery)/.*\.jpg$ $img_dir;
}
map $arg_pic $image_name {
# The ".*" match here might be insecure - using something like "[-a-z0-9_]+"
# would probably be better if it matches all your image names;
# choose a regexp which is appropriate for your situation.
~^images/(elements|gallery)/(?P<img_name>.*)\.jpg$ $img_name;
}
map $arg_type $image_type {
~^(?P<img_type>[0-9]{1,3}[a-z]{0,4})$ $img_type;
}
location ~ "^/resize.php$" {
try_files /images/${image_dir}/${image_name}.jpg /imagenes/elements/thumbs/${image_type}_${image_name}.jpg #phpresize;
}
location #phpresize {
# No changes from your config here.
try_files $uri =404;
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_buffering on;
proxy_pass http://www.localhost.com:8080;
}