In NGINX 'location ~ .*' does not match any string - nginx-location

In the following site config file i am trying to:
Load index.php on the first visit.
Load files as they appear in the /uploads/ directory.
Any other request should still be handled by index.php.
server {
listen 80 default_server;
listen [::]:80 default_server;
root /home/va/www/example;
# Add index.php to the list if you are using PHP
# index index.php;
server_name example.dev;
location ~ .*
{
try_files /dev/null #php;
}
location /uploads/
{
try_files $uri =404;
expires 30d;
}
location #php
{
include snippets/fastcgi-php.conf;
#pretty url
fastcgi_param SCRIPT_FILENAME $document_root/index.php;
fastcgi_pass unix:/var/run/php/php7.4-fpm.sock;
}
}
However, the last part breaks. In other words:
/ works
/?test=test works
/uploads/test.jpeg works
/random_string does not work and returns 404 error
My understanding is that location ~ .* has no choice but to match everything. Where is the 404 error coming from?

Ok. After working on it some more, and completely rewriting the logic, i have gotten a muse from The MediaWiki Nginx guide. The final solution is:
server {
listen 80 default_server;
listen [::]:80 default_server;
root /home/va/www/example;
server_name example.dev;
location = /
{
return 301 /home;
}
location = /index.php
{
include snippets/fastcgi-php.conf;
#pretty url
fastcgi_param SCRIPT_FILENAME $document_root/index.php;
fastcgi_pass unix:/var/run/php/php7.4-fpm.sock;
}
location /uploads/
{
try_files $uri =404;
expires 30d;
}
location /
{
rewrite ^/(?<pagename>.*)$ /index.php;
}
location /classes/ { deny all; }
location /config/ { deny all; }
}
I will then use $_SERVER['REQUEST_URI'] within PHP to route the request. Hopefully this solution will help somebody.

Related

Convert /#<handle> to /users/profile/<handle> with nginx

I'm looking for an nginx rule that would do this:
input url: http://domain.com/#johndoe
what our backend sees: http://domain.com/users/profile/johndoe
Example: http://medium.com/#stuartkhall
The current rule I'm using (removed things that don't have to do with this question):
server {
listen 80 default_server;
listen [::]:80 default_server ipv6only=on;
server_name _;
root /var/html;
location / {
try_files $uri $uri/ /index.php$is_args$args;
}
location ~ \.php$ {
include fastcgi_params;
fastcgi_pass mainphp;
fastcgi_param SCRIPT_FILENAME $document_root$fastcgi_script_name;
}
}
What kind of rule I can add to my current nginx config? I experimented with a rewrite but wasn't able to get it to work.
Better practice is location + return instead of rewrite, so try this (place before any location):
location ~ ^/#(.*)$ {
return 301 /users/profile/$1;
}
or identical rewrite in case you prefer it
rewrite ^/#(.*)$ /users/profile/$1 last;

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

Nginx proxy_pass to another port with Wordpress

My problem is following: I use Wordpress on Nginx with "pretty links". I also run 2 other services on ports 88 and 1234 and I want to make a subdomains bugs.mydomain and mail.mydomain. I did the proxypass on location / but it's working only for the main directory, anything that is after the domain/ is falling into Wordpress "pretty links" mechanism. Do you have any idea how to solve this? My config files below:
The server config:
server {
listen <IP>:80;
root /usr/share/nginx/www/domain;
index index.html index.htm index.php;
server_name domain www.domain;
location / {
try_files $uri $uri/ /index.html;
if ( $host ~ "bugs.domain" ) {
proxy_pass http://domain:88;
}
if ( $host ~ "mail.domain" ) {
proxy_pass http://domain:1234;
}
}
location /doc/ {
alias /usr/share/doc/;
autoindex on;
allow 127.0.0.1;
deny all;
}
location ~ \.php$ {
try_files $uri =404;
fastcgi_split_path_info ^(.+\.php)(/.+)$;
fastcgi_pass unix:/var/run/php5-fpm.sock;
fastcgi_index index.php;
include fastcgi_params;
}
location ~ /\.ht {
deny all;
}
include /home/domain/public_html/nginx.conf;
}
the config for specified domain (with Wordpress):
#First there is many rewrites for the W3TC plugin, like minification, caches etc
if ($host ~* ^www\.(.*))
{
set $host_without_www $1;
rewrite ^/(.*)$ $scheme://$host_without_www/$1 permanent;
}
#
# unless the request is for a valid file, send to bootstrap
if (!-e $request_filename)
{
rewrite ^(.+)$ /index.php?q=$1 last;
}
Now, when I enter domain:88 or domain:1234 it works. When I enter bugs.domain the website loads, but no CSS or images works as the url is bugs.domain/somapath and this falls into the Wordpress bootstrap. I run out of the ideas.
why create only 1 server with if's in it, separate the servers
server {
listen 80;
server_name bugs.example.com;
proxy_pass http://example.com:88;
}
server {
listen 80;
server_name mail.example.com;
proxy_pass http://example.com:1234;
}
server {
listen 80;
# the rest of your main server
#
}
So the problem was completely different then I thought. it was failing on this line:
try_files $uri $uri/ /index.html;
The problem was, that file index.html didn't exist, I only had index.php. Changing it solved the problem.

Location route not matching

I have a location which simply for some reason isn't triggering. I've tried the routes in all sorts of different orders, and still it doesn't work. When a user comes along and requests /_hostmanager/ it should trigger, but instead it gets the index.php page from the route.
The server config file is:
server {
index index.php index.html;
root /var/www/html;
server_name _;
listen 80;
# Logging
error_log /var/log/httpd/elasticbeanstalk-error_log;
# Route standard requests
location / {
try_files $uri $uri/ /index.php;
}
# Proxy Hostmanager
location /_hostmanager/ {
proxy_pass http://127.0.0.1:8999/;
}
# Include PHP
location ~ \.php {
# CGI Configuration
fastcgi_param SCRIPT_FILENAME $document_root$fastcgi_script_name;
include /etc/nginx/fastcgi_params;
fastcgi_index index.php;
# Zero-day exploit defense
try_files $uri $uri/ /index.php =404;
# Use socket for connection
fastcgi_pass unix:/tmp/php5-fpm.sock;
}
# Cache control
location ~* \.(jpg|jpeg|gif|png|css|js|ico|xml)$ {
log_not_found off;
expires 360d;
}
# Disable hidden files
location ~ /\. {
deny all;
}
}
Can anyone spot what my (probably stupid!) error is?
Thanks in advance! :)
Nevermind, I worked it out! For some reason using the reload command on nginx wasn't working. stopped and started and voila!

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