Nginx location behave with and without location regex - nginx

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 {

Related

Nginx configuration for rewrite rule

So I have this configuration at the moment in nginx:
autoindex off;
location / {
try_files $uri $uri.html $uri/ #extensionless-php;
index index.html index.htm index.php;
}
location #extensionless-php {
rewrite ^(.*)$ $1.php last;
}
# pass PHP scripts to FastCGI server
#
location ~ \.php$ {
include snippets/fastcgi-php.conf;
# With php-fpm (or other unix sockets):
fastcgi_pass unix:/var/run/php/php7.1-fpm.sock;
# With php-cgi (or other tcp sockets):
#fastcgi_pass 127.0.0.1:9000;
}
Now, I want to get something 'special'. I want to get an url (http://project2.local/camera?camera_id=1) to be rewritten as http://project2.local/camera/1 I've tried this code;
location / {
rewrite ^/?camera\.php$ /camera/%1? redirect;
}
location /camera {
rewrite ^/camera/([^/]*)$ /camera.php?camera_id=$1 break;
}
but that downloads something empty when I navigate to that place.. What am I doing wrong here?
Try:
location /camera {
rewrite ^/camera/([^/]*)$ /camera.php?camera_id=$1 last;
}
The rewrite...break will prevent the camera.php URI being processed by the PHP location. You need to use last as per your existing configuration. See this document for details.
You also added: location / { rewrite ^/?camera\.php$ /camera/%1? redirect; }, but it seems wrong and superfluous for a number of reasons:
You cannot have two location / blocks (perhaps you meant you added the line of code to the existing location / block)
I do not recognise the %1 term (the value of the parameter would be $arg_camera_id)
It will never match anything (URIs ending with .php are processed by the PHP location)

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 deny doesn't work for folder files

I'm trying to restrict access to my site to allow only specific IPs and I've got the following problem: when I access www.example.com deny works perfectly, but when I try to access www.example.com/index.php it returns "Access denied" page AND php file is downloaded directly in browser without processing.
I do want to deny access to all the files on the website for all IPs but mine. How should I do that?
Here's the config I have:
server {
listen 80;
server_name example.com;
root /var/www/example;
location / {
index index.html index.php; ## Allow a static html file to be shown first
try_files $uri $uri/ #handler; ## If missing pass the URI to front handler
expires 30d; ## Assume all files are cachable
allow my.public.ip;
deny all;
}
location #handler { ## Common front handler
rewrite / /index.php;
}
location ~ .php/ { ## Forward paths like /js/index.php/x.js to relevant handler
rewrite ^(.*.php)/ $1 last;
}
location ~ .php$ { ## Execute PHP scripts
if (!-e $request_filename) { rewrite / /index.php last; } ## Catch 404s that try_files miss
expires off; ## Do not cache dynamic content
fastcgi_pass 127.0.0.1:9001;
fastcgi_param HTTPS $fastcgi_https;
fastcgi_param SCRIPT_FILENAME $document_root$fastcgi_script_name;
include fastcgi_params; ## See /etc/nginx/fastcgi_params
}
}
That is because your deny/allow rule applies to just one location.
Remove that and try:
server {
listen 80;
server_name example.com;
root /var/www/example;
if ($remote_addr != "YOUR.PUBLIC.IP") {return 403;}
...
}
As the test is outside any specific locationblock, it will apply to all cases.
Note also that IF is not evil here since it just "returns".
OK, so I've found the solution. Nginx processes the most exact regex which in this case is the regex for php files. To make the config work all further locations must be defined within / location rule except for #handler (you cannot put under any rule - only as root)
server {
listen 80;
server_name example.com;
root /var/www/example;
location / {
index index.html index.php; ## Allow a static html file to be shown first
try_files $uri $uri/ #handler; ## If missing pass the URI to front handler
expires 30d; ## Assume all files are cachable
allow my.public.ip;
deny all;
location ~ .php/ { ## Forward paths like /js/index.php/x.js to relevant handler
rewrite ^(.*.php)/ $1 last;
}
location ~ .php$ { ## Execute PHP scripts
if (!-e $request_filename) { rewrite / /index.php last; } ## Catch 404s that try_files miss
expires off; ## Do not cache dynamic content
fastcgi_pass 127.0.0.1:9001;
fastcgi_param HTTPS $fastcgi_https;
fastcgi_param SCRIPT_FILENAME $document_root$fastcgi_script_name;
include fastcgi_params; ## See /etc/nginx/fastcgi_params
}
}
location #handler { ## Common front handler
rewrite / /index.php;
}
}

Can't serve "hidden" wordpress install

I'm switching a Wordpress site from Apache to Nginx.
We're trying to obfuscate the fact that it's a Wordpress site (I don't know why, but those are the requirements).
There are a few calls to static assets within the wordpress directory, so it's not perfect.
For the most part, it's working (www.example.com and other pages within show up properly), but I can't get the Admin page to work.
When you go to example.com/wp-admin, the server should load /var/example.com/docroot/wordpress/wp-admin/index.php, but I keep getting a 404.
I'm not sure where I've gone wrong. This is my server conf:
server {
server_name *.example.com;
root /var/example.com/docroot;
access_log logs/access.log;
error_log logs/error.log debug ;
gzip off;
# Add trailing slash to */wp-admin requests.
rewrite /wp-admin$ $scheme://$host$uri/ permanent;
# Rewrite wp-content to pretend we don't use Wordpress
location ~ ^/content/(.*)$ {
alias /var/example.com/docroot/wordpress/wp-content/$1;
}
location ~ ^/wp-content/(.*)$ {
alias /var/example.com/docroot/wordpress/wp-content/$1;
}
location ~ ^/includes/(.*)$ {
alias /var/example.com/docroot/wordpress/wp-includes/$1;
}
location ~ ^/wp-includes/(.*)$ {
alias /var/example.com/docroot/wordpress/wp-includes/$1;
}
location /wp-admin {
alias /var/example.com/docroot/wordpress/wp-admin;
}
# Basic php configuration
location ~ \.php$ {
include fastcgi_params;
fastcgi_split_path_info ^(.+\.php)(/.+)$;
fastcgi_index index.php;
fastcgi_param SCRIPT_FILENAME $document_root$fastcgi_script_name;
try_files $uri =404;
}
location / {
try_files $uri $uri/ /index.php?$args;
}
# static assets and blocking specific access
include sites-enabled/common.conf;
}
The two things I did to get this to work:
Proxy_pass instead of alias
location /wp-admin {
proxy_pass $scheme://www.dev4.railrode.net/wordpress/wp-admin/;
}
And for the try_files directives, added a wordpress$uri option:
try_files $uri /wordpress$uri =404

nginx server configuration: subdomain to folder

I migrated from Apache 2 to nginx and I've got problems to handly my subdomain control.
What I want: When x.domain.tld is requested, internally rewrite to domain.tld/x
The problem I've got is that nginx always redirects the page by telling the browser to redirect to. But what I really want is to do this internally, like Apache 2 did.
Also, if I only request x.domain.tld, nginx returns a 404. It only works when I do x.domain.tld/index.php
Here's my config:
server {
listen 80 default;
server_name _ domain.tld www.domain.tld ~^(?<sub>.+)\.domain\.tld$;
root /home/domain/docs/;
if ($sub) {
rewrite (.*) /$sub;
}
# HIDDEN FILES AND FOLDERS
rewrite ^(.*)\/\.(.*)$ #404 break;
location = #404 {
return 404;
}
# PHP
location ~ ^(.*)\.php$ {
if (!-f $request_filename) {
return 404;
}
include /etc/nginx/fastcgi_params;
fastcgi_pass unix:/etc/nginx/sockets/domain.socket;
}
}
Thanks!
As I found this Q&A on Google while looking for a solution for the same problem, I wanted to post the solution I finally used.
The first server block by MTeck looks pretty nice, but for the subdomains part you could simply do the following:
server {
listen 80;
server_name "~^(?<sub>.+)\.domain\.tld$";
root /path/to/document/root/$sub;
location / { try_files $uri $uri/ /index.php; }
location ~ \.php {
include fastcgi_params;
fastcgi_pass unix:/etc/nginx/sockets/domain.socket;
}
}
This makes the root configuration directive dependent on the subdomain.
I spent hours beating my head against the wall and this is what works for me
server {
listen 80;
server_name ~^(?P<sub>.+)\.example\.com$; #<-- Note P before sub, it was critical for my nginx
root /var/www/$sub; #<-- most important line cause it defines $document_root for SCRIPT_FILENAME
location / {
index index.php index.html; #<-- try_files didn't work as well
}
location ~ \.php$ {
fastcgi_pass 127.0.0.1:9000; #<-- probably you have another option here e.g. fastcgi_pass unix:/var/run/php5-fpm.sock;
fastcgi_index index.php;
fastcgi_param SCRIPT_FILENAME $document_root/$fastcgi_script_name;
include fastcgi_params;
}
}
You should take a look at http://wiki.nginx.org/IfIsEvil. You're doing a whole lot wrong in this configuration file.
server {
server_name domain.tld www.domain.tld;
location / {
try_files $uri /index.php;
}
location ~ \.php {
include fastcgi_params;
fastcgi_pass unix:/etc/nginx/sockets/domain.socket;
}
}
server {
server_name "~^(?<sub>.+)*\.(?<domain>.*)$";
return 301 $scheme://$domain/$sub$request_uri;
}
If what you want is to keep that internal, you won't be able to rewrite it. By definition, a cross site rewrite needs to be sent back to the browser. You'll have to proxy the request.
server {
server_name "~^(?<sub>.+)*\.(?<domain>.*)$";
proxy_pass http://$domain/$sub$request_uri;
}
You should read the Nginx wiki. All of this is explained in depth.
This will work for www also.
server {
listen 80 default_server;
listen [::]:80 default_server;
index index.php index.html index.htm index.nginx-debian.html;
server_name ~^www\.(?P<sub>.+)\.domain\.com$ ~^(?P<sub>.+)\.domain\.com$;
root /var/www/html/$sub;
location / {
try_files $uri $uri/ /index.php?$args;
}
}

Resources