Nginx, PHP and rewrite - nginx

How do I make PHP-FPM rules play nicely with Nginx rewrite rules?
Current config file
server {
location / {
location ~ \.php$ {
try_files $uri =404;
fastcgi_split_path_info ^(.+\.php)(/.+)$;
fastcgi_pass 127.0.0.1:9000;
fastcgi_param PATH_INFO $fastcgi_path_info;
fastcgi_param PATH_TRANSLATED $document_root$fastcgi_script_name;
include fastcgi.conf;
}
if (!-e $request_filename){
rewrite ^(.*)$ /index.php?routestring=$1 break;
}
rewrite ^/(admincp/)$ /index.php?routestring=$1 break;
}
}

Change your location block to the following. Also try to avoid if statements, read about it (and more) here: http://wiki.nginx.org/Pitfalls
I've replaced the if (!-e ...) part with the #missing block in the config below.
server {
root /your/root/path
index index.php index.html index.htm;
server_name your.domain.com;
rewrite ^/(admincp/)$ /index.php?routestring=$1 break;
location / {
# First attempt to serve request as file, then
# as directory, then fall back to index.php
try_files $uri $uri/ /index.php?$args;
}
# pass the PHP scripts to FastCGI server listening on 127.0.0.1:9000
location ~ \.php$ {
# Move to the #missing part when the file doesn't exist
try_files $uri #missing;
# Fix for server variables that behave differently under nginx/$
fastcgi_split_path_info ^(.+\.php)(/.+)$;
# Include the standard fastcgi_params file included with ngingx
include fastcgi_params;
fastcgi_param PATH_INFO $fastcgi_path_info;
fastcgi_index index.php;
# Override the SCRIPT_FILENAME variable set by fastcgi_params
fastcgi_param SCRIPT_FILENAME $document_root$fastcgi_script_nam$
# Pass to upstream PHP-FPM; This must match whater you name you$
#fastcgi_pass phpfpm;
fastcgi_pass 127.0.0.1:9000;
}
location #missing {
rewrite ^(.*)$ /index.php?routestring=$1 break;
}
}

Related

nginx configure /folder run from a different path than the /

I am having an issue running /folder from a different path than the main website.
my nginx.conf for that section look like this:
location ~ \.php$ {
try_files $uri = 404;
fastcgi_split_path_info ^(.+\.php)(/.+)$;
fastcgi_param SCRIPT_FILENAME $request_filename;
fastcgi_pass unix:/var/run/php/php7.2-fpm.sock;
fastcgi_index index.php;
include fastcgi_params;
include fastcgi.conf;
}
location ~ /folder {
alias /srv/http/folder;
try_files $uri $uri/ #folder;
location ~ \.php$ {
fastcgi_param SCRIPT_FILENAME $request_filename;
fastcgi_pass unix:/var/run/php/php7.2-fpm.sock;
include fastcgi.conf;
}
}
location #folder {
rewrite /folder/(.*)$ /folder/index.php?/$1 last;
}
In the error.log I can see the following:
2020/06/03 09:05:26 [error] 25966#25966: *1 FastCGI sent in stderr: "Primary script unknown" while reading response header from upstream, client: 172.21.2.46, server: example.com, request: "GET /folder/xxx_v6.15.11/Resources/images/redcaplogo.gif HTTP/1.1", upstream: "fastcgi://unix:/var/run/php/php7.2-fpm.sock:", host: "example.com"
Any suggestion how to fix this?
Regex locations are matched from first to last, and the first found match processed by nginx. When you get a request for /folder/script.php, it is processed by the first location block. Try to swap this two locations. Additionaly, why are you do not include fastcgi_params in your second location block?
Update
I did some debugging, lets look at you code (assuming location block already swapped):
location ~ /folder {
alias /srv/http/folder;
try_files $uri $uri/ #folder;
location ~ \.php$ {
fastcgi_param SCRIPT_FILENAME $request_filename;
fastcgi_pass unix:/var/run/php/php7.2-fpm.sock;
include fastcgi_params;
include fastcgi.conf;
}
}
location ~ \.php$ {
try_files $uri =404;
fastcgi_split_path_info ^(.+\.php)(/.+)$;
fastcgi_param SCRIPT_FILENAME $request_filename;
fastcgi_pass unix:/var/run/php/php7.2-fpm.sock;
fastcgi_index index.php;
include fastcgi_params;
include fastcgi.conf;
}
location #folder {
rewrite /folder/(.*)$ /folder/index.php?/$1 last;
}
If we get a request /folder/some/path (and there is no some/path file or directory inside the folder), inside the nested location internal nginx variables would have following values:
$request_filename: empty string (there is no real file or folder /some/path inside th folder directory);
$uri: /folder/check.php;
$document_root: /srv/http/folder.
If we get a request /folder/some/path/script.php (and there is a real PHP script with this name), inside the nested location internal nginx variables would have following values:
$request_filename: /srv/http/folder/some/path/script.php;
$uri: /folder/some/path/check.php;
$document_root: /srv/http/folder.
Additionally, when you get a request for a static resource from your folder, for example /folder/some/path/static.css, the try_files $uri ... directive will search folder/some/path/static.css file in a /srv/http/folder directory, which leads to check the existence of /srv/http/folder/folder/some/path/static.css file.
One of possible solutions to get a file subpath inside the folder directory:
location ~ ^/folder(?<subpath>.*) {
alias /srv/http/folder;
try_files $subpath $subpath/ #folder;
location ~ \.php$ {
fastcgi_param SCRIPT_FILENAME $document_root$subpath;
fastcgi_pass unix:/var/run/php/php7.2-fpm.sock;
include fastcgi_params;
include fastcgi.conf;
}
}
location ~ \.php$ {
try_files $uri =404;
fastcgi_split_path_info ^(.+\.php)(/.+)$;
fastcgi_param SCRIPT_FILENAME $request_filename;
fastcgi_pass unix:/var/run/php/php7.2-fpm.sock;
fastcgi_index index.php;
include fastcgi_params;
include fastcgi.conf;
}
location #folder {
rewrite ^/folder/(.*)$ /folder/index.php?/$1 last;
}
This could be simplified if your real folder directory name is the same as your /folder URI prefix:
location ~ ^/folder {
root /srv/http;
try_files $uri $uri/ #folder;
location ~ \.php$ {
fastcgi_param SCRIPT_FILENAME $document_root$uri;
fastcgi_pass unix:/var/run/php/php7.2-fpm.sock;
include fastcgi_params;
include fastcgi.conf;
}
}
...
As nginx documentation states:
When location matches the last part of the directive’s value:
location /images/ {
alias /data/w3/images/;
}
it is better to use the root directive instead:
location /images/ {
root /data/w3;
}

NGINX location giving 404 error, even though the directory exists [duplicate]

lets say I've a path like:
/var/www/myside/
that path contains two folders... let's say
/static and /manage
I'd like to configure nginx to have an access to:
/static folder on / (eg. http://example.org/)
this folder has some .html files.
/manage folder on /manage (eg. http://example.org/manage) in this case this folder contains Slim's PHP framework code - that means the index.php file is in public subfolder (eg. /var/www/mysite/manage/public/index.php)
I've tried a lot of combinations such as
server {
listen 80;
server_name example.org;
error_log /usr/local/etc/nginx/logs/mysite/error.log;
access_log /usr/local/etc/nginx/logs/mysite/access.log;
root /var/www/mysite;
location /manage {
root $uri/manage/public;
try_files $uri /index.php$is_args$args;
}
location / {
root $uri/static/;
index index.html;
}
location ~ \.php {
try_files $uri =404;
fastcgi_split_path_info ^(.+\.php)(/.+)$;
include fastcgi_params;
fastcgi_param SCRIPT_FILENAME $document_root$fastcgi_script_name;
fastcgi_param SCRIPT_NAME $fastcgi_script_name;
fastcgi_index index.php;
fastcgi_pass 127.0.0.1:9000;
}
}
The / works correctly anyway manage doesn't. Am I doing something wrong? Does anybody know what should I change?
Matthew.
To access a path like /var/www/mysite/manage/public with a URI like /manage, you will need to use alias rather than root. See this document for details.
I am assuming that you need to run PHP from both roots, in which case you will need two location ~ \.php blocks, see example below. If you have no PHP within /var/www/mysite/static, you can delete the unused location block.
For example:
server {
listen 80;
server_name example.org;
error_log /usr/local/etc/nginx/logs/mysite/error.log;
access_log /usr/local/etc/nginx/logs/mysite/access.log;
root /var/www/mysite/static;
index index.html;
location / {
}
location ~ \.php$ {
try_files $uri =404;
fastcgi_pass 127.0.0.1:9000;
include fastcgi_params;
fastcgi_param SCRIPT_FILENAME $request_filename;
fastcgi_param SCRIPT_NAME $fastcgi_script_name;
}
location ^~ /manage {
alias /var/www/mysite/manage/public;
index index.php;
if (!-e $request_filename) { rewrite ^ /manage/index.php last; }
location ~ \.php$ {
if (!-f $request_filename) { return 404; }
fastcgi_pass 127.0.0.1:9000;
include fastcgi_params;
fastcgi_param SCRIPT_FILENAME $request_filename;
fastcgi_param SCRIPT_NAME $fastcgi_script_name;
}
}
}
The ^~ modifier causes the prefix location to take precedence over regular expression locations at the same level. See this document for details.
The alias and try_files directives are not together due to this long standing bug.
Be aware of this caution in the use of the if directive.

Override location directives in nginx not working

I want to override the permissions to /folder/script.php and have the following rules:
location ^~ /folder/script.php{
allow all;
} #shouldn't ^this one with ^~ override the others?
location ~ /folder/(.+)\.php$ {
deny all;
return 404;
allow 127.0.0.1;
}
location ~ ^/folder {
return 404;
}
location / {
# First attempt to serve request as file, then
# as directory, then trigger 404
try_files $uri $uri/ =404;
server_name_in_redirect off;
}
location ~ \.php$ {
try_files $uri =404;
#fastcgi_split_path_info ^(.+\.php)(/.+)$;
# NOTE: You should have "cgi.fix_pathinfo = 0;" in php.ini
#fastcgi_pass /tmp/php5-fpm.sock;
#fastcgi_pass /var/run/php5-fpm.sock;
fastcgi_pass 127.0.0.1:9000;
fastcgi_index index.php;
fastcgi_param SCRIPT_FILENAME $root_folder$fastcgi_script_name;
fastcgi_param DOCUMENT_ROOT $root_folder;
# send bad requests
fastcgi_intercept_errors on;
include fastcgi_params;
}
but whenever I access admin.php I still get a 404 error and/or the script.php file is served to download, not interpreted. Could someone explain me why? Tyvm
The commands to execute a php script are:
try_files $uri =404;
fastcgi_pass 127.0.0.1:9000;
fastcgi_param SCRIPT_FILENAME $root_folder$fastcgi_script_name;
fastcgi_param DOCUMENT_ROOT $root_folder;
fastcgi_intercept_errors on;
include fastcgi_params;
I'm not sure where you define $root_folder, normally $document_root is used. The above (or similar) code must appear in each and every location block that is expected to execute php scripts.
So your configuration should look something like this:
location / {
try_files $uri $uri/ =404;
server_name_in_redirect off;
}
location ^~ /folder { deny all; }
location = /folder/script.php {
try_files $uri =404;
fastcgi_pass 127.0.0.1:9000;
fastcgi_param SCRIPT_FILENAME $root_folder$fastcgi_script_name;
fastcgi_param DOCUMENT_ROOT $root_folder;
fastcgi_intercept_errors on;
include fastcgi_params;
}
location ~ \.php$ {
try_files $uri =404;
fastcgi_pass 127.0.0.1:9000;
fastcgi_param SCRIPT_FILENAME $root_folder$fastcgi_script_name;
fastcgi_param DOCUMENT_ROOT $root_folder;
fastcgi_intercept_errors on;
include fastcgi_params;
}
I have taken the liberty of simplifying your configuration a little. It seems that only the file /folder/script.php is executable within the /folder hierarchy, so an exact match (location =) is used, and /folder is denied. The allow 127.0.0.1; does nothing as it comes after the deny all.
As you can see, the fastcgi_pass 127.0.0.1:9000; directive must appear in any location container that directly handles php code. I would put some or all of these directives into a separate file and use include to pull them in at each location.
The rest of the directives have been copied across from your question, but I don't know if they are required here.

Nginx rewrite downloading file

I am trying to rewrite a url with nginx but its downloading the php file instead of passing it
https://www.example.com/s.php?k=7eqx6si58Mn4fBf8n9oiF9lwIQ%3D%3D&b=5
Need to show as
https://www.example.com/s/7eqx6si58Mn4fBf8n9oiF9lwIQ%3D%3D&b=5
I tried the following but its not working
location ~ ^/s.php(.*)$ {
rewrite ^/s/$ /s.php?k= last;
}
I also have the following location block
location ~* \.php$ {
root /var/www/example.com/public_html/www;
try_files $uri =404;
fastcgi_pass unix:/run/php5-fpm.sock;
fastcgi_index index.php;
fastcgi_param SCRIPT_FILENAME $document_root$fastcgi_script_name;
include fastcgi_params;
}

How can Nginx use try_files only if file exists?

I have fully worked example of virtual host for a project on Symfony from ()[].
There is a code:
server {
listen 80;
server_name localhost www.localhost;
root /vagrant/web;
error_log /var/log/nginx/error.log;
access_log /var/log/nginx/access.log;
location / {
# try to serve file directly, fallback to app.php
try_files $uri /app_dev.php$is_args$args;
}
# DEV
# This rule should only be placed on your development environment
# In production, don't include this and don't deploy app_dev.php or config.php
location ~ ^/(app_dev|config)\.php(/|$) {
fastcgi_pass unix:/var/run/php5-fpm.sock;
fastcgi_split_path_info ^(.+\.php)(/.*)$;
include fastcgi_params;
fastcgi_param SCRIPT_FILENAME $document_root$fastcgi_script_name;
fastcgi_param HTTPS off;
}
# PROD
location ~ ^/app\.php(/|$) {
fastcgi_pass unix:/var/run/php5-fpm.sock;
fastcgi_split_path_info ^(.+\.php)(/.*)$;
include fastcgi_params;
fastcgi_param SCRIPT_FILENAME $document_root$fastcgi_script_name;
fastcgi_param HTTPS off;
# Prevents URIs that include the front controller. This will 404:
# http://domain.tld/app.php/some-path
# Remove the internal directive to allow URIs like this
#internal;
}
}
But I want to improve it a bit for me. How can I load maintenance.html by default instead of app_dev.php?
P.S. I need a behaviour like with try_files $uri /maintenance.html$is_args$args; instead of try_files $uri /app_dev.php$is_args$args;, but ONLY if maintenance.html exists
Solution from here with bit of comments
location / { #can be any location or even in server
if (-f $document_root/maintenance.html) {
return 503; #503 for search engines
}
... # the rest of your config goes here
}
error_page 503 #maintenance;
location #maintenance {
rewrite ^(.*)$ /maintenance.html break;
}
I solved it with:
try_files $uri /maintenance.html$is_args$args /app_dev.php$is_args$args;

Resources