Nginx to host app in different location [closed] - php

Closed. This question does not meet Stack Overflow guidelines. It is not currently accepting answers.
This question does not appear to be about a specific programming problem, a software algorithm, or software tools primarily used by programmers. If you believe the question would be on-topic on another Stack Exchange site, you can leave a comment to explain where the question may be able to be answered.
Closed 7 years ago.
Improve this question
I'm trying to serve CachetHQ in nginx + php-fpm in a specific location. The docs gives this as example that serves in status.example.com (which works):
server {
listen 80;
server_name status.example.com;
root /var/www/Cachet/public;
index index.php;
location / {
try_files $uri /index.php$is_args$args;
}
location ~ \.php$ {
include fastcgi_params;
fastcgi_pass 127.0.0.1:9000;
fastcgi_param SCRIPT_FILENAME $document_root$fastcgi_script_name;
fastcgi_index index.php;
fastcgi_keep_conn on;
}
}
However, instead of serving in status.example.com, I would like to serve in example.com/status.
I was expecting that this would work, but from error.log I see it's trying /etc/nginx/htmlindex.php, but it should be /mnt/data/site/www-cachet/public/index.php:
location /status/ {
index index.php;
root /mnt/data/site/www-cachet/public;
try_files $uri index.php$is_args$args;
location ~ ^/status/.+\.php$ {
root /mnt/data/site/www-cachet/public;
include fastcgi_params;
fastcgi_pass unix:/tmp/php-fpm.sock;
fastcgi_param SCRIPT_FILENAME $document_root$fastcgi_script_name;
fastcgi_index index.php;
fastcgi_keep_conn on;
}
}

Let me start with the original configuration that you claim works, and try to modify it for your requirements, results below:
location ^~ /status {
alias /var/www/Cachet/public;
index index.php;
location = /status {
return 302 /status/;
}
location / {
try_files $uri /status/index.php$is_args$args;
}
location ~ \.php$ {
include fastcgi_params;
fastcgi_pass 127.0.0.1:9000;
rewrite ^/status/(.*) /$1;
rewrite ^(.*)/ $1/index.php; # who knows what fastcgi_index is for?
fastcgi_param SCRIPT_FILENAME $document_root$uri;
fastcgi_keep_conn on;
}
}
Basically, you want to use alias instead of root here, and probably also have an absolute path in the final try_files as well. I don't think adding extra prefixes within nested locations is needed, but you might want to make sure that the root location is a final match with the ^~ modifier.
The main trick, I guess, is that even with the alias directive things aren't as dandy as with a proper root, so, you have to make sure that the SCRIPT_FILENAME is set correctly. This part doesn't seem to be documented very clearly, and I'm too lazy to test out whether $fastcgi_script_name ngx variable and fastcgi_index directive play nice with alias -- instead of trying to determine how those work (or not), we simply do a couple of rewrite rules as applicable, and construct SCRIPT_FILENAME based on the results of our rewrite rules instead. :-)
However, with that said, I'd think the second rewrite rule (as well as the fastcgi_index it replaces) might as well be a no-op, because how were we supposed to end up in a \.php$ location if $uri didn't end in .php already?
(Likewise, you're free to try to remove the first rewrite rule, too, and replace $uri in SCRIPT_FILENAME with $fastcgi_script_name, and see if things still work, but the internet from 2009 may indicate that they didn't.)

Your try_files is not correct.
You can do it like this:
index index.php;
root /mnt/data/site/www-cachet/public;
location / {
if (!-e $request_filename) {
rewrite ^(.*)$ /index.php?$1 last;
break;
}
}
location ~ ^/status/.+\.php$ {
root /mnt/data/site/www-cachet/public;
include fastcgi_params;
fastcgi_pass unix:/tmp/php-fpm.sock;
fastcgi_param SCRIPT_FILENAME $document_root$fastcgi_script_name;
fastcgi_index index.php;
fastcgi_keep_conn on;
}

After so many hours trying a lot of combinations, the way I got it working was:
location ^~ /status {
alias /mnt/data/site/www-cachet/public;
try_files $uri $uri/ #status;
location = /status/ {
rewrite /status/$ /status/index.php;
}
location ~ ^/status/(.+\.php)$ {
fastcgi_pass unix:/tmp/php-fpm.sock;
fastcgi_index index.php;
fastcgi_param SCRIPT_FILENAME /mnt/data/site/www-cachet/public/$1;
include fastcgi_params;
}
}
location #status {
rewrite /status/(.*)$ /status/index.php?/$1 last;
}
The most important thing was fastcgi_param, I had to set it to an absolute path instead of $document_root$fastcgi_script_name or something like it. I'm not sure if it's a good pratice, but adding alias to the block just doesn't work, and neither nginx or FastCGI show us the path of the file they're trying to read.
Nevertheless I couldn't get CachetHQ to work well. Problem is that all paths in source code are absolute, so they won't point to the subdirectory which our files are hosted. The solution was do something that I was reluctant since beginning: host it in a subdomain.

Related

NGINX - No input file specified

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.

Increase fastcgi_read_timeout for single route

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.

Nginx configuration for two versions of PHP

I'm trying to set up an nginx environment where legacy code and new MVC-style code can co-exist, so that I can gradually refactor it page by page. The legacy code needs an older version of PHP (it runs best on 5.3, but I had trouble compiling that, so I went with 5.4 and will fix anything that breaks), but it is easily distinguishable by URL, because it has literal file names like http://sub.domain.com/search.php?category=4, etc. instead of new style like http://sub.domain.com/search/category/4 - the key difference is the presence of .php.
The new code runs fine with the following in the nginx config:
server {
listen 80;
server_name *.myproject.dev;
root /var/www/myproject/public;
index index.php index.html index.htm;
try_files $uri $uri/ #rewrite;
location #rewrite {
rewrite ^/(.*)$ /index.php?_url=/$1;
}
location ~ ^(.+\.php)(/.*)?$ {
fastcgi_param PATH_INFO $fastcgi_path_info;
fastcgi_param PATH_TRANSLATED $document_root$fastcgi_path_info;
fastcgi_param SCRIPT_FILENAME $document_root$fastcgi_script_name;
fastcgi_pass unix:/var/run/php5-fpm.sock;
fastcgi_split_path_info ^(.+\.php)(/.+)$;
include fastcgi_params;
}
}
(I will admit that I don't completely understand all that code - it came from various guides and such.)
With the help of this great tutorial I compiled and installed PHP 5.4 in its own location listening on port 9001. It works fine using a separate domain for the old code, but what I want to do is use a single domain, but call the old code if .php is found in the URL, and do the requisite rewrite on anything else and use the new code. I found this post on ServerFault and tried incorporating its ideas in my situation like this:
server {
listen 80;
server_name *.myproject.dev;
root /var/www/myproject/public;
index index.php index.html index.htm;
try_files $uri $uri/ #rewrite;
location #rewrite {
rewrite ^/(.*)$ /index.php?_url=/$1;
}
location ~ ^(.+\.php)(/.*)?$ {
fastcgi_param PATH_INFO $fastcgi_path_info;
fastcgi_param PATH_TRANSLATED $document_root$fastcgi_path_info;
fastcgi_param SCRIPT_FILENAME $document_root$fastcgi_script_name;
fastcgi_pass unix:/var/run/php5-fpm.sock;
fastcgi_split_path_info ^(.+\.php)(/.+)$;
include fastcgi_params;
# Anything with ".php" is directed to the old codebase
location ~* \.php {
root /var/www/myproject/oldcode;
fastcgi_pass 127.0.0.1:9001;
}
}
}
But the rewrite adds index.php to the new code, so in the end, everything matches the .php test, which is not the intent. I tried putting those final four lines earlier in the file with several variations, but that didn't help (either a blank page or still only going to the old code location, depending on the details). Does someone know enough about nginx config syntax to help me rearrange it so that it does what I want?
If your new code only uses /index.php and without any path_info, you could use a prefix location:
location ^~ /index.php { ... }
location ~* \.php { ... }
The first location takes precedence due to the ^~ operator. Or an exact match (which also takes precedence):
location = /index.php { ... }
location ~* \.php { ... }

nginx rewrite rules by subdirectory

I am trying to achieve the following result with an nginx configuration:
A PHP app is running in a subdirectory of a server, lets say
server.com/app/. Files in images/ and styles/ (for example) should be accessible, php files in api/ should be executed, and in all other cases nginx should pass the whole string after app/ to PHP as a GET variable, say path.
I really have no clue what I am doing here, and I can not seem to find anything useful for this on the web, so if you can chip in, thank you.
I am running php5-fpm currently like this:
location /app {
index index.html index.php;
access_log /{...}/access.log;
error_log /{...}/error.log;
location ~ \.php {
try_files $uri = 404;
fastcgi_pass php5-fpm-sock;
fastcgi_index index.php;
fastcgi_param SCRIPT_FILENAME $document_root$fastcgi_script_name;
include fastcgi_params;
}
}
Please ask if you need any more details.
EDIT
For now I found that this works
location /{path}/ {
index index.php;
access_log /{path}/access.log;
error_log /{path}/error.log;
location ~\.php {
try_files $uri = 404;
fastcgi_pass php5-fpm-sock;
fastcgi_index index.php;
fastcgi_param SCRIPT_FILENAME $document_root$fastcgi_script_name;
include fastcgi_params;
}
location ~ {
try_files $uri $uri/ /{path}/index.php?path=$uri;
}
}
However I am worried that this might allow unwanted file access. Any comments?
You can probably simplify it by moving the try_files directive out of the location sub-block so that your config file ends up looking like:
location /app {
index index.php;
try_files $uri $uri/ /app/index.php?path=$uri;
access_log /{path}/access.log;
error_log /{path}/error.log;
location ~\.php {
try_files $uri =404;
fastcgi_pass php5-fpm-sock;
fastcgi_index index.php;
fastcgi_param SCRIPT_FILENAME $document_root$fastcgi_script_name;
include fastcgi_params;
}
}
The key thing is the try_files directive - nginx will try each location in the order specified. $uri looks for a file matching the exact path specified (so /api/random.php loads correctly because it's a file), $uri/ looks for a folder matching the path, and attempts to load the index from the folder, and finally /app/index.php?path=$uri loads the page /app/index.php. This is then picked up by the location ~\.php block and passed to php-fpm.
The main thing I'd be concerned about is that your access and error.log files would be publicly accessible by virtue of being stored in the web directory. If possible, shift them somewhere else (like /var/log maybe?)

Nginx alias with laravel4

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 :).

Categories