I have the following Nginx configuration for forwarding requests to a PHP-FPM backend:
server {
...
location / {
try_files $uri $uri/ /index.php$is_args$args;
}
location ~* \.php$ {
fastcgi_split_path_info ^(.+?\.php)(/.*)$;
include fastcgi_params;
fastcgi_param SCRIPT_FILENAME $document_root/index.php;
fastcgi_param PATH_INFO $fastcgi_path_info;
fastcgi_param PATH_TRANSLATED $document_root$fastcgi_path_info;
fastcgi_pass 127.0.0.1:9000;
fastcgi_index index.php;
}
}
One specific route in the app needs a slightly longer php max_execution_time setting. I've configured this successfully and verified it works by setting a longer fastcgi_read_timeout in the above config.
However, I don't need this to be applied to every single route. I'm guessing I need a nested location somewhere but nothing I've tried seems to work!
The fastcgi_read_timeout directive does not appear to accept dynamic values, so a separate location block for the special route will be required. Looking at your configuration file, I assume the special route is a unique URI processed by the /index.php script. Something like this should work:
location ^~ /special/route/uri {
include fastcgi_params;
fastcgi_param SCRIPT_FILENAME $document_root/index.php;
fastcgi_pass 127.0.0.1:9000;
fastcgi_read_timeout 100s;
}
You can use a prefix location with the ^~ modifier (as above) to override the regex location that usually processes PHP files. Alternatively, you can use a regex location, but place it above the existing regex location so that it takes precedence.
See this document for location syntax.
Related
Just want to let everyone know before I posted this question I checked
every single thread on stackoverflow about this issue.
The aim:
Run two apps under one domain, first app on the root (/) and second app under the URI (/learn).
http://example.com/ - first app
http://example.com/learn - second app
The problem:
The main app works perfectly, but the learn app is showing a white page with "No input file specified.".
My file structure:
/srv/users/serverpilot/apps/main/public/index.php
/srv/users/serverpilot/apps/learn/public/index.php
My NGINX configuration:
root "/srv/users/serverpilot/apps/main/public";
location ^~ /learn {
root "/srv/users/serverpilot/apps";
try_files $uri /learn/public/index.php?$query_string;
location ~ \.php$ {
add_header X-debug-message $document_root$fastcgi_script_name always;
include fastcgi_params;
fastcgi_index index.php;
fastcgi_param SCRIPT_FILENAME $document_root$fastcgi_script_name;
fastcgi_pass unix:/srv/users/serverpilot/run/learn.php-fpm.sock;
}
}
location / {
try_files $uri $uri/ /index.php?$args;
location ~ \.php$ {
include fastcgi_params;
fastcgi_index index.php;
fastcgi_param SCRIPT_FILENAME $document_root$fastcgi_script_name;
fastcgi_pass unix:/srv/users/serverpilot/run/main.php-fpm.sock;
try_files $uri =404;
}
}
In addition:
I know the fastcgi_pass sockets are working because I've been
running these two apps under different domains but in the same
server in question.
I added the add_header X-debug-message $document_root$fastcgi_script_name" always; to see what the response header would show, and it shows that the
SCRIPT_FILENAME is
/srv/users/serverpilot/apps/learn/public/index.php which exists and is the exact file I am trying to run.
Oh lordy! What a wild hunt!
Okay the reason this configuration wasn't working is because aside from fastcgi_params you can also set php_value[doc_root] which will overwrite your $document_root which is commonly used in the SCRIPT_FILENAME parameter. So check your php.ini files always to make sure php_value[doc_root] is not set when you have apps that are being served from different directories otherwise it just wont pick them up. In the case that you are just serving a single app from a single directory you need not worry.
I have .php files in multiple directories (/jobs/marketing/, /jobs/content/ etc) that need to map cleanly to /jobs/name-of-file.php.
For example hitting the url:
/jobs/digital-marketing
needs to map to:
/jobs/marketing/digital-marketing.php
It's safe to assume the file name of each php file is unique across directories.
my current nginx setup is the following:
location /jobs {
expires max;
add_header Cache-Control public;
add_header Pragma public;
rewrite ^/jobs[\/]?$ /marketing/jobs.php last;
location ~* ^/jobs/([\-a-z0-9]*)$ {
try_files /marketing/jobs/engineering/$1.php
/marketing/jobs/marketing/$1.php
/marketing/jobs/business-development/$1.php
/marketing/jobs/content/$1.php;
}
location ~ ^/.+\.php($|/) {
fastcgi_split_path_info ^(.+\.php)(/.*)$;
fastcgi_param SCRIPT_FILENAME $document_root$fastcgi_script_name;
fastcgi_param SCRIPT_NAME $fastcgi_script_name;
fastcgi_param PATH_TRANSLATED $document_root$fastcgi_path_info;
fastcgi_param PATH_INFO $fastcgi_path_info;
fastcgi_pass unix:/run/php-fpm/php-fpm.sock;
include fastcgi_params;
fastcgi_read_timeout 3000;
}
}
This seems pretty close, except a plain text version of the file gets downloaded instead of nginx redirecting to it. I think I need to somehow catch the correct file with another location block, but I nothing seems to be working (that might not even be the correct approach).
Any ideas about how to achieve this? Or a better approach perhaps?
Thanks.
I belive that you are using try_files a bit wrong. What it does is
Checks the existence of files in the specified order and uses the
first found file for request processing; the processing is performed
in the current context.
You have one context with location ~* ^/jobs/([-a-z0-9]*)$ and another with location ~ ^/.+.php($|/)
So you are finding files but not processing them through PHP as your processing is in another context.
Therefore I belive you should add php processing in your try_files location.
location ~* ^/jobs/([\-a-z0-9]*)$ {
try_files /marketing/jobs/engineering/$1.php
/marketing/jobs/marketing/$1.php
/marketing/jobs/business-development/$1.php
/marketing/jobs/content/$1.php;
...
fastcgi_param ...;
fastcgi_pass ...;
}
To not write same config for both /jobs and .php locations you can cut it to file and include like you do with include fastcgi_params;
So ok, if your actual location directs to correct files - we're half way there. At this moment nginx is trying to download files - let's try to add another location directing those files to PHP parser - this one works for me:
location ~ ^/.+\.php($|/) {
fastcgi_split_path_info ^(.+\.php)(/.*)$;
fastcgi_param SCRIPT_FILENAME $document_root$fastcgi_script_name;
fastcgi_param SCRIPT_NAME $fastcgi_script_name;
fastcgi_param PATH_TRANSLATED $document_root$fastcgi_path_info;
fastcgi_param PATH_INFO $fastcgi_path_info;
fastcgi_pass unix:/run/php-fpm/php-fpm.sock;
include fastcgi_params;
fastcgi_read_timeout 3000;
}
Add this piece of code after your location and let me know if this works for you. You can read more about nginx with PHP here
Nginx returns a 404 when I query for an URL with a "path info" appended after the script name, e.g. http://example.com/index.php/hello.
Here is my config:
server {
listen 80;
root #PROJECT_ROOT#/;
index index.php index.html;
location ~ \.php$ {
fastcgi_pass unix:#PHP_FPM_SOCK#;
include fastcgi_params;
fastcgi_read_timeout 300s;
}
}
I don't get why \.php$ doesn't match that URL, and I've tried searching for similar problems but can't find anything useful.
Use
location ~ ^.+.php {
fastcgi_split_path_info ^(.+?.php)(/.*)$;
to match a .php in the uri split the parameters
This works for me:
location ~ \.php {
# Split the path appropriately
fastcgi_split_path_info ^(.+?\.php)(/.*)$;
# Work around annoying nginx "feature" (https://trac.nginx.org/nginx/ticket/321)
set $path_info $fastcgi_path_info;
fastcgi_param PATH_INFO $path_info;
# Make sure the script exists.
try_files $fastcgi_script_name =404;
# Configure everything else. This part may be different for you.
fastcgi_pass localhost:9000;
fastcgi_index index.php;
fastcgi_param SCRIPT_FILENAME $document_root$fastcgi_script_name;
include fastcgi_params;
}
My nginx configuration for laravel
server {
listen 80;
server_name app.dev;
rewrite_log on;
root /var/www/l4/angular;
index index.html;
location /{
# URLs to attempt, including pretty ones.
try_files $uri $uri/ /index.php?$query_string;
}
location /lara/ {
index index.php;
alias /var/www/l4/public/;
}
# Remove trailing slash to please routing system.
if (!-d $request_filename) {
rewrite ^/(.+)/$ /$1 permanent;
}
location ~ ^/lara/(.*\.php)$ {
alias /var/www/l4/public/$1;
fastcgi_pass unix:/var/run/php5-fpm.sock;
fastcgi_index index.php;
fastcgi_param SCRIPT_FILENAME $document_root$fastcgi_script_name;
include fastcgi_params;
}
}
Laravel route:
Route::get('/', function()
{
return View::make('index');
});
Route::get('x', function()
{
return "alpha";
});
my problem is,"http://app.dev/lara/index.php" is working but "http://app.dev/lara" and lara/x is not working.
In a nutshell, make the following edits. An explanation of why is below.
Replace
try_files $uri $uri/ /index.php?$query_string;
with
try_files $uri $uri/ /lara/index.php?$query_string;
Replace the last location directive with this
location ~ /lara/(.*)$ {
fastcgi_pass unix:/var/run/php5-fpm.sock;
fastcgi_index index.php;
include fastcgi_params;
fastcgi_param SCRIPT_FILENAME "/var/www/l4/public/index.php";
fastcgi_param REQUEST_URI /$1;
}
Restart nginx.
Now the why. I spotted a couple of mistakes with your nginx config. First, /index.php?$query_string in the try_files directive should be /lara/index.php?$query_string, otherwise nginx will try a request like http://app.dev/lara as /var/www/l4/angular/index.php?, which leads no where (unless you have an index.php there, and even is it will be served as text, not through fpm).
The second has to do with the location ~ ^/lara/(.*\.php)$ directive. I think restricting it to URIs that end with .php is wrong, because it won't work for http://app.dev/lara/x, which will make nginx only search for /var/www/l4/public/x, returning 404 of course. Changing the regex to ^/lara/(.*)$ should do the job of catching /lara/x. Now the fastcgi_param SCRIPT_FILENAME $document_root$fastcgi_script_name; directive is erroneous because for http://app.dev/lara/x, SCRIPT_FILENAME is /var/www/l4/public/x/lara/x, and removing the $1 in the alias directive won't make it any better. Instead, make the fastcgi_param like this fastcgi_param SCRIPT_FILENAME "/var/www/l4/public/index.php";, remove the alias directive, it's useless now, then move include fastcgi_params; above the fastcgi_param so it won't override SCRIPT_FILENAME value.
Done? Not yet :). Trying /lara/x will show a Laravel routing error, because it tries to find the route lara/x instead of x, this is because you're including fastcgi_params. Just add fastcgi_param REQUEST_URI /$1; after SCRIPT_FILENAME param directive. Now it should be working fine. Don't forget to restart nginx :).
I am trying to block the apc.php file on my webserver. If do the following it works but I am thinking there is a better way to do this and put the deny/allow rule below the general location ~ .php$ block. It doesnt seem right to have to have two blocks with the fastcgi params.
#Block to apc.php
location ~ /apc.php {
fastcgi_pass 127.0.0.1:9000;
fastcgi_index index.php;
fastcgi_param SCRIPT_FILENAME $document_root$fastcgi_script_name;
include fastcgi_params;
allow 192.168.3.0/24;
deny all;
}
# use fastcgi for all php files
location ~ \.php$
{
fastcgi_pass 127.0.0.1:9000;
fastcgi_index index.php;
fastcgi_param SCRIPT_FILENAME $document_root$fastcgi_script_name;
include fastcgi_params;
}
Since "deny" not allowed in if statement, you can use nested location like location / { location /uri/ {} }, however, it is not encouraged in Nginx manual:
"While nested locations are allowed by the configuration file parser,
their use is discouraged and may produce unexpected results."