nginx is not passing fastcgi query string - php

With some (or very much) trial and error i was able to modify my copy and pasted nginx fastcgi php configuration from somewhere years ago to be able to run my php application in a subfolder.
But the last final step i am not able to solve is how to get nginx to pass the query string to php to be able to access the GET parameters. This is my configuration mostly perfect with only the configuration parameters missing:
server {
listen 80;
server_name project.dev;
location /app/ {
alias /path/to/my/application/;
index index.php;
try_files $uri $uri/ /app/index.php;
location ~ \.php$ {
include fastcgi_params;
fastcgi_pass 127.0.0.1:9000;
fastcgi_param SCRIPT_FILENAME $document_root/index.php;
}
}
location / {
# configuration for static website
}
}
I read that there are different options you have to pass to try_files to get request parameters:
try_files $uri $uri/ /app/index.php$is_args$query_string;
try_files $uri $uri/ /app/index.php$is_args$args;
try_files $uri $uri/ /app/index.php?$query_string;
Unfortunately changing it to any of these results in my php script no longer being found because nginx resets the request to it's document root:
2016/11/25 11:54:48 [error] 45809#0: *1169 open() "/usr/local/Cellar/nginx-full/1.10.2/htmlindex.php" failed (2: No such file or directory), client: 127.0.0.1, server: project.dev, request: "GET /app/myurl?test=works HTTP/2.0", host: "project.dev", referrer: "http://project.dev/app/myurl?test=works"
Providing an absolute path for fastcgi_param SCRIPT_FILENAME does not work too producting the same error. Even setting a root configuration on the server level does not work correctly, because the separating slash for the path and the index.php is omitted everytime. But (if possible) i would prefer without setting a root directory at the server level because this project is consisting of many different folders and applications on the filesystem sharing no common directory.

You have an application installed under /path/to/my/app2/public and would like to access it using the URI /app.
Assuming that we can use /app2/ as an internal URI (which does not collide with any other public URIs served by this server - but importantly will not be seen by your customers).
You have one PHP file.
location ^~ /app {
rewrite ^/app(.*)$ /app2/public$1 last;
}
location ^~ /app2/ {
internal;
root /path/to/my;
index index.php;
try_files $uri $uri/ /app2/public/index.php$is_args$args;
location ~ \.php$ {
include fastcgi_params;
fastcgi_pass 127.0.0.1:9000;
fastcgi_param SCRIPT_FILENAME /path/to/my/app2/public/index.php;
}
}
The first location block simply alters the internal URI to match the document root (so we can use root instead of alias). The second location block serves the static content. The third location block invokes index.php.
How index.php gets the query string is program dependent. It will use one of the parameters defined in fastcgi_params. Usually either REQUEST_URI or QUERY_STRING. Either way, both variables should be preserved with the above configuration.
The ^~ modifier ensures that these location blocks take precedence over other regular expression location blocks (should any exist). See this document for details.

Related

Nginx can not read .php routes of laravel who not exist

I have created some Laravel routes with they have ".php" extention, such as
Route::get('/api/send.php', function(){
echo 'Hi There';
});
But when I open the route it shows 404 error in Nginx server... That is Nginx configurations
server {
listen 80 default_server;
listen [::]:80 default_server;
root /var/www/laravel/public;
# Add index.php to the list if you are using PHP
index index.php index.html index.htm index.nginx-debian.html;
server_name xxx.xxx.xxx.xxx;
location / {
# First attempt to serve request as file, then
# as directory, then fall back to displaying a 404.
try_files $uri $uri/ /index.php?$query_string;
}
location ~ \.php$ {
include snippets/fastcgi-php.conf;
fastcgi_pass unix:/var/run/php/php7.2-fpm.sock;
}
location ~ /\.ht {
deny all;
}
}
What is the problem? I have used the same code it worked before..
Thanks
SOLVED
It solved by changing
try_files $fastcgi_script_name =404;
in /etc/nginx/snippets/fastcgi-php.conf to
try_files $fastcgi_script_name /index.php?$query_string;
This is a very common problem with nginx configured to serve PHP applications, especially Laravel. You can reproduce it on sites like laravel.com, e.g: laravel.com/example.php.
The default configuration (what you're probably using in snippets/fastcgi-php.conf) is this:
fastcgi_param SCRIPT_FILENAME $document_root$fastcgi_script_name;
And fastcgi_script_name is...
request URI or, if a URI ends with a slash, request URI with an index file name configured by the fastcgi_index directive appended to it. This variable can be used to set the SCRIPT_FILENAME and PATH_TRANSLATED parameters that determine the script name in PHP. For example, for the “/info/” request with the following directives
That means, when a request URI contains .php it is treated as if it is a request for a PHP file, and if that PHP file doesn't exist an error is returned by nginx -- it never reaches your application.
The solution is to force fastcgi_script_name to always equal your application's entry point, in this case that's index.php. You can either edit snippets/fastcgi-php.conf or add it into your location block like this:
location ~ \.php$ {
include snippets/fastcgi-php.conf;
fastcgi_pass unix:/var/run/php/php7.2-fpm.sock;
fastcgi_param SCRIPT_FILENAME $document_root/index.php;
}
Your application will now receive every request, including those that have .php in the path.

How to configure Nginx for Ember.js + Wordpress?

The scenario is that I'd like to use Wordpress as a backend API provider for our Ember.js frontend app.
The Ember.js frontend needs to be served from the root, and the Wordpress instance ideally would be reachable by going to a subdirectory. So for example on localhost it would be http://localhost and http://localhost/wordpress
On the disk the two are deployed in /srv/http/ember and /srv/http/wordpress respectively.
I was trying to assemble the configuration going by the example on the Nginx site:
https://www.nginx.com/resources/wiki/start/topics/recipes/wordpress/
The config:
http {
upstream php {
server unix:/run/php-fpm/php-fpm.sock;
}
server {
listen 80;
server_name localhost;
root /srv/http/ember;
index index.html;
try_files $uri $uri/ /index.html?/$request_uri;
location /wordpress {
root /srv/http/wordpress;
try_files $uri $uri/ /index.php?$args;
}
location ~ \.php$ {
#NOTE: You should have "cgi.fix_pathinfo = 0;" in php.ini
include fastcgi.conf;
fastcgi_intercept_errors on;
fastcgi_pass php;
fastcgi_split_path_info ^(/wordpress)(/.*)$;
}
}
}
However this is obviously not the correct solution.
Upon trying to access the address http://localhost/wordpress/index.php I get the following in the logs:
2016/05/01 17:50:14 [error] 4332#4332: *3 FastCGI sent in stderr: "Primary script unknown" while reading response header from upstream, client: 127.0.0.1, server: localhost, request: "GET /wordpress/index.php HTTP/1.1", upstream: "fastcgi://unix:/run/php-fpm/php-fpm.sock:", host: "localhost"
The recipe isn't clear about where to put the root directive for the location of wordpress. I also tried with adding index index.php, which doesn't help either.
(Serving the Ember app works fine.)
From your question it seems that the location ~ \.php$ block is used by WordPress alone. However, it needs a root of /srv/http in order to find the script files for URIs beginning with /wordpress under the local path /srv/http/wordpress.
As there are two locations which both use the same WordPress root, it is possibly cleaner to make /srv/http the default (that is, inherited from the server block) and move root /srv/http/ember; into a separate location / block.
server {
listen 80;
server_name localhost;
root /srv/http;
location / {
root /srv/http/ember;
index index.html;
try_files $uri $uri/ /index.html?/$request_uri;
}
location /wordpress {
index index.php;
try_files $uri $uri/ /wordpress/index.php?$args;
}
location ~ \.php$ {
include fastcgi.conf;
fastcgi_intercept_errors on;
fastcgi_param SCRIPT_FILENAME $document_root$fastcgi_script_name;
fastcgi_pass php;
}
}
Notice that the default URI in location /wordpress is /wordpress/index.php and not /index.php as you originally had.
I have explicitly set SCRIPT_FILENAME as it may or may not appear in your fastcgi.conf file.
fastcgi_split_path_info has been removed as it is unnecessary in your specific case, and I think it would actually break WordPress the way you had it.

NGINX configuration wildcard

I am using Symfony2 (PHP) framework for my project and is having a small problem with regards to configuring my NGINX to catch request going to a 3rd party library I placed under "web" directory.
This is my configuration
server {
listen 80;
server_name test.com;
root /var/www/my-symfony-project/web;
rewrite ^/app\.php/?(.*)$ /$1 permanent;
location / {
index app.php;
try_files $uri #rewriteapp;
}
location #rewriteapp {
rewrite ^(.*)$ /app.php/$1 last;
}
location ~ ^/(app|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;
}
}
As you may have noticed that the root is pointed in "/var/www/my-symfony-project/web" directory.
Now, the problem is that I have this "some-plugin" folder inside the "web" directory and there are PHP files from there that are not handled by the Symfony2 routing.
I actually made it work when I have the following "location" block inside the "server" block illustrated above.
location ~ \.php$ {
fastcgi_pass unix:/var/run/php5-fpm.sock;
fastcgi_split_path_info ^(.+\.php)(/.*)$;
include fastcgi_params;
}
It seems okay having this type of configuration at first but we realized that it accepts request to any "*.php" file to which we evaluated as a security breach.
Any suggestions?
Allowing access to .php files is usually not considered dangerous or a security breach, as long as the PHP files are executed and not served in their source form and, of course, don't print any sensitive information.
If either of the former are not the case, you should probably change your setup or your code.
Anyway, you should be able to restrict the .php file handling to /var/www/my-symfony-project/web/some-plugin by using the following as location:
location ~ ^/var/www/my-symfony-project/web/some-plugin/.*\.php$ {
# your rules here
}
This should match all files whose path starts with /var/www/my-symfony-project/web/some-plugin/ and end with .php in upper or lower case.

Nginx - PHP scripts not being called from reverse proxy

I give below an execerpt of of /etc/nginx/sites-available/default file
server {
listen 443 ssl;
server_name example.com;
root /var/www/html;
index index.php index.html;
location / {
try_files $uri $uri/ = 404;
}
location /rproxy/ {
proxy_pass https://example.org:8144/;
}
location ~ \.php$ {
try_files $uri = 404;
fastcgi_split_path_info ^(.+\.php)(/.+)$;
....
}
The example.org:8144 server
has the files and
index.php - returns hello World
bonjour.php - returns bonjour
Now here is the issue:
If I browse to https://example.com/rproxy it promptly returns hello world - the expected result.
However, if I browse to https://example.com/rproxy/bonjour.php (or even https://example.com/rproxy/index.php) I get a 404 error.
I understand what is happening here. My Nginx configuration is causing the example.com instance of Nginx to attempt to find all *.php files locally (i.e. on example.com) which fails when the file I am seeking is in fact on example.org:8144.
I imagine that there is a relatively simple way to tell Nginx when NOT to attempt to attempt to execute a PHP file - when it is in fact on rproxy. However, my knowledge of Nginx confugration is too limited for me to be able to figure out just how I alter the configuration. I'd be most obliged to anyone who might be tell me how to change the configuration to prevent this from happening.
I should clarify something here:
I need to be able to run PHP scripts on Both SERVERS example.com and example.org.
There is a very easy workaround here - I use a different extension, say php5, for php scripts on the proxied server, example.org. However, that is easily liable to lead to unforseen problems.
For nginx regexp locations have bigger priority than prefix locations. But
If the longest matching prefix location has the “^~” modifier then
regular expressions are not checked.
So try to replace
location /rproxy/ {
with
location ^~ /rproxy/ {
The upstream servers you pass things to have no knowledge of your nginx config. Similarly, your nginx has no idea how your upstream should respond to requests. Neither of them will ever care about the other's configuration.
This is a start for actually passing the name of your script on, but there's a bunch of different ways to do it and they all entirely depend on how the upstream is configured. Also, don't use regexes if you can avoid it; there's no point in slowing everything down for no reason.
upstream reverse {
server example.org:8144;
}
server {
listen 443 ssl;
server_name example.com;
root /var/www/html;
index index.php index.html;
location / {
try_files $uri $uri/ =404;
}
location /rproxy {
proxy_pass https://reverse/$request_uri;
}
location ~ \.php$ {
try_files $uri =404;
fastcgi_split_path_info ^(.+\.php)(/.+)$;
include fastcgi_params;
fastcgi_pass /blah/tmp.sock;
}
}
The (not necessarily smart) but neat way is when you define your PHP block to fall back to your upstream instead of =404 (again, this is a terrible idea unless you know what you're doing, but it can be done):
location #proxy {
proxy_pass https://upstream$request_uri;
}
location ~ \.php$ {
try_files $uri #proxy;
fastcgi_split_path_info ^(.+\.php)(/.+)$;
include fastcgi_params;
fastcgi_pass /blah/tmp.sock;
}

Nginx, try_files & multiple folders with front controllers

I can't wrap my head around Nginxs' try_files. Recently I installed Nginx in favour of Apache on my development machine. How I used to work was like this: I'd bootstrap a project in a subfolder of my http directory. If this involved laravel, wordpress, codeigniter or any other framework that's using a front controller to make URLs more readable, I'd add a .htaccess in that directory to rewrite all non-existing paths to index.php.
Supposedly, this is very simple on Nginx: try_files $uri $uri/ /index.php?$query_string and it should work. However, all this does is redirect everything to the index.php in the $document_root. Example:
File structure:
http/clients/cms/public/index.php front controller
http/clients/cms/public/some/application/url request uri with the parameters some, application and url.
http/clients/cms/public/images/image.png a static file.
http/clients/blog/index.php another front controller
http/clients/blog/wp-content/image.png another static file
http/clients/blog/some-article-title a 'pretty url' that should be directed to 4
Now, hen a request is made to 2, try_files detects that /some, /some/application and /some/application/url don't exist. It will now redirect to /index.php. I would expect that it would redirect to index.php in the public/ directory, but it doesn't. Instead, it redirects to the index.php in the $document_root (which happens to contain a phpinfo(); call, so it's easy to see that it goes wrong..).
A solution would be to create multiple location blocks in my Nginx config, but I'm not liking that. It would add a significant amount of extra work to my bootstrapping process.
Is there a way to use try_files in the directories so that it works exactly like the apache alternative?
My config file:
server {
listen 80;
server_name localhost,imac.local;
access_log /var/log/nginx/access.log;
error_log /var/log/nginx/error.log;
rewrite_log on;
root /Volumes/Storage/Fabian/Dropbox/Sites;
index index.php index.html;
location / {
try_files $uri $uri/ /index.php?$query_string;
#echo $request_filename;
#break;
}
location ~ \.php$ {
fastcgi_pass 127.0.0.1:9000;
fastcgi_index index.php;
#fastcgi_split_path_info ^(.+\.php)(.*)$;
include fastcgi_params;
fastcgi_param SCRIPT_FILENAME $document_root$fastcgi_script_name;
}
location ~ /\. {
deny all;
access_log off;
log_not_found off;
}
}
thanks!

Categories