nginx location block matching order query - nginx

I have the following in my conf file:
server {
listen 80;
server_name a.mydomain.com;
location /f/ {
alias /var/www/sites/mydomain/photos/;
expires 1y;
}
location ~ \.(php|html)$ {
include php.conf;
}
location / {
return 301 http://www.mydomain.com$request_uri;
}
}
Where php.conf is
fastcgi_param SCRIPT_FILENAME $document_root$fastcgi_script_name;
fastcgi_param PHP_VALUE "include_path=.:/usr/share/pear:/var/www/sites/mydomain/conf";
include /etc/nginx/fastcgi_params;
fastcgi_index index.php;
try_files $uri =404;
fastcgi_pass 127.0.0.1:9000;
What puzzles me, is that my final location ("location /") block, does exactly what I want it to. Any request other than those starting with /f/ get redirect to the parent www domain.
Which is great, it's what I want.
But, the documentation states otherwise. It says that the regex php block I have should match before (and take precedence) over the final "/" block?
Doesn't it?
"The order in which location directives are checked is as follows:
Directives with the = prefix that match the query exactly (literal string). If found, searching stops.
All remaining directives with conventional strings. If this match used the ^~ prefix, searching stops.
Regular expressions, in the order they are defined in the configuration file.
If #3 yielded a match, that result is used. Otherwise, the match from #2 is used."

Related

Location blocks in nginx not getting desired outcome - maybe ordering?

I've got a website using nginx that's got a load of redirects to retain the juice and UI that old backlinks give me but they're not all working as I need them to. I suspect it could be an ordering issue but I'm not sure so I'd appreciate some help.
I'm pretty sure I'm almost there but I can't work out a way for it all to work together!
location / {
try_files $uri $uri/ #extensionless-php;
}
location #redirector {
rewrite ^(.*)$ /redirection-check/?request=$request_uri;
}
location #extensionless-php {
rewrite ^(.*?)/?$ $1.php;
}
location ~ ^([^.\?]*[^/])$ {
try_files $uri #addslash;
}
location #addslash {
return 301 $uri/;
}
location ~ \.php$ {
try_files $uri $uri/ #redirector;
fastcgi_split_path_info ^(.+\.php)(/.+)$;
fastcgi_pass unix:/run/php/php5.6-fpm.sock;
fastcgi_param SCRIPT_FILENAME $document_root$fastcgi_script_name;
fastcgi_index index.php;
include fastcgi_params;
}
The way it should work is...
If someone lands on domain.com/page or domain.com/page.php then 301 to domain.com/page/
Interpret domain.com/page/ as domain.com/page.php
If domain.com/page.php doesn't exist then go to domain.com/redirection-check/?request=the404request. This is a 301/404 handler with a BUNCH of old urls in a big php array so they're not all listed in nginx config files.
You have a location ~ \.php$ block to process URIs that end with .php. This will handle both internally rewritten URIs (as generated by your #extensionless-php block) and externally presented URIs (such as in your 1st requirement).
To handle externally presented URIs differently, you need to look at the original request which is available as $request_uri.
The $request_uri contains the original request including the optional query string, and can be tested using a map or if directive.
For example:
if ($request_uri ~ ^(.*)\.php(\?|$)) { return 301 $1/; }
See this caution on the use of if.

Set nginx root to a public folder while keeping the parent directory name in the URL

In our web project we have a a directory called public. We set the root in the nginx config to this public folder so that only the files in the public folder are accessible through the URL.
Our config looks somewhat like this:
server {
listen 80;
server_name example.com
root /srv/nginx/example.com/v1/public;
index index.html index.php;
location / {
try_files $uri $uri/ /index.php;
add_header Access-Control-Allow-Origin *;
}
location ~ \.php$ {
fastcgi_intercept_errors on;
fastcgi_index index.php;
include fastcgi_params;
fastcgi_param SCRIPT_FILENAME $document_root$fastcgi_script_name;
fastcgi_pass php-fpm;
}
}
So now we can access srv/nginx/example.com/v1/public through the URL example.com. Great.
But how can we set our URLs to example.com/v1 with the root at /srv/nginx/example.com/v1/public? Also if we upload a new version it should be available through the URL with example.com/v2 with the root at /srv/nginx/example.com/v2/public without changing config files.
One way I think I can achieve this is by making multiple server blocks each time we upload a new version. But like I said I don't wish to change the nginx config each time we upload a new version and have the risk of doing something wrong.
What other ways are there? And how can I use these?
Use a regular expression location block to split the URI into two components and use an alias directive to construct the path to the target file (which is represented by the $request_filename variable).
For example:
server {
listen 80;
server_name example.com
root /var/empty;
index index.html index.php;
add_header Access-Control-Allow-Origin *;
location ~ ^/(?<prefix>[^/]+)/(?<suffix>.*)$ {
alias /srv/nginx/example.com/$prefix/public/$suffix;
if (!-e $request_filename) { rewrite ^ /$prefix/index.php last; }
location ~ \.php$ {
if (!-f $request_filename) { return 404; }
fastcgi_intercept_errors on;
include fastcgi_params;
fastcgi_param SCRIPT_FILENAME $request_filename;
fastcgi_pass php-fpm;
}
}
}
Avoid the use of try_file with alias due to this issue. See this caution on the use of if.

nginx aliases and dynamic directory names

I have spent muy tiempo on this and I can't get a solution.
I need a way to point the same url but with different root directory to the same application. I don't want to use rewrites because the root directoy name has to be processed by the application and rewrite discards it.
http://www.host.com/a/ --> /var/www/html/project/
http://www.host.com/b/ --> /var/www/html/project/
http://www.host.com/c/ --> /var/www/html/project/
I've managed to configure in nginx an alias directory with a fixed name vdirectory and make nginx forward the request to fastcgi.
location /vdirectory {
alias /var/www/html/project/;
try_files $uri $uri/ /vdirectory/index.php;
location ~ \.php$ {
fastcgi_pass unix:/var/run/php5-fpm.sock;
include fastcgi_params;
fastcgi_param SCRIPT_FILENAME $request_filename;
}
}
The above works OK.
Since I don't want to use fixed root directory names but arbitrary ones, this is what I've managed so far:
location ~ ^/(.?)$ {
alias /var/www/html/project/;
try_files $uri $uri/ /$1/index.php;
location ~ \.php$ {
fastcgi_pass unix:/var/run/php5-fpm.sock;
include fastcgi_params;
fastcgi_param SCRIPT_FILENAME $request_filename;
}
}
Needless to say, it returns 404. It is a good sign because it means regex has recognized the path, but the request isn't forwarded correctly.
The only difference between the working config and the wrong one is /vdirectory vs ~ ^/(.?)$
alias works differently when inside a regular expression location block. See this document for details. You will need to capture the remainder of the URI and append that to the alias value. For example:
location ~ ^/(?<prefix>[^/]+)/(?<name>.*)$ {
alias /var/www/html/project/$name;
if (!-e $request_filename) { rewrite ^ /$prefix/index.php last; }
location ~ \.php$ {
if (!-f $request_filename) { return 404; }
fastcgi_pass unix:/var/run/php5-fpm.sock;
include fastcgi_params;
fastcgi_param SCRIPT_FILENAME $request_filename;
}
}
I avoid using try_files and alias within the same block due to long term issues. See this caution on the use of if.

Nginx location behave with and without location regex

To include my small project (not based on one of the known frameworks) into existing website, I've added the following config to Nginx
server {
listen 80 default_server;
server_name localhost;
access_log /var/log/nginx/dev.access.log;
error_log /var/log/nginx/dev.error.log;
root /var/www;
index index.php;
[...]
location /www.my-project.com {
alias /var/www/www.my-project.com/web;
index index.php;
if (-f $request_filename) { break; }
rewrite ^(.*)$ /www.my-project.com/index.php last;
location ~ /[^/]+/index\.php$ {
include fastcgi_params;
fastcgi_pass unix:/var/run/fcgi.sock;
fastcgi_param SCRIPT_FILENAME $document_root/index.php;
}
}
All works fine (except that I wish to prevent to list subdir name in location directive), so I can call http://localhost/www.my-project.com. But when calling http://localhost/www.my-project.com.blabla the location directive from above is called and my internal error page is served. So I tried to change location directive to
location ~ ^/www\.my-project\.com(/|$) {
But that causes any existing file (CSS, JS...) to be rewritten to index.php, which then returns an 404 itself. Why does a change of location causes this horrible behaviour, I can see no logical difference between location /www.my-project.com and location ~ ^/www\.my-project\.com(/|$).
I'd suggest excluding the assets from the rewrite, you can do that by adding a new location, something like this
location /(css|js|images) {
root /var/www/www.my-project.com/web;
try_files $uri =404;
}
And for the location issue, you can match exact locations using =
location = /www.my-project.com {

howto setup window nginx virtual directory with php support?

Ngigx + PHP-FPM setup and working in root-directory, but I'm having trouble getting virtual directories to work.
I want //localhost/pb/test.php to execute c:\opt\php\public\test.php but it breaks with "no input file specified". In fact, not even .html files works, but once working, I want the php-directive to work under /pb as well.
current nginx.conf:
server {
listen 80;
server_name localhost;
location / {
root html;
index index.html index.htm index.php;
}
location /pb/ {
root /opt/php/public;
index index.html index.htm index.php;
}
location ~ \.php$ {
fastcgi_pass 127.0.0.1:9123;
fastcgi_index index.php;
fastcgi_param SCRIPT_FILENAME $document_root$fastcgi_script_name;
include fastcgi_params;
}
}
http://nginx.org/en/docs/http/ngx_http_core_module.html#location explains how nginx matches locations.
in this case your prefix location /pb/ will match, and nginx will never get to the *.php matching location
what I would try is to set up a named location (the #bit makes it a named location):
location #fastcgi {
fastcgi_pass 127.0.0.1:9123;
fastcgi_index index.php;
fastcgi_param SCRIPT_FILENAME $document_root$fastcgi_script_name;
include fastcgi_params;
}
and then refer to that in try_files directives from other locations, like this:
location /pb/ {
root /opt/php/public;
index index.html index.html;
try_files $uri #fastcgi;
}
location ~ \.php$ {
alias #fastcgi;
}
the try files above would first try an exact match file name and if it doesn't find that it will pass the request to the #fastcgi location
alternatively you could offcourse simply repeat the fastcgi bits in a nested location block inside your /pb/ location

Resources