URI rewrite with nginx and php-fpm with parameters - php

I have a bunch of different rules on my nginx server with php-fpm.
The simple one is a rewrite that changes http://server/$1?param=1 to http://server/$1.php?param=1 using
location #extensionless-php {
rewrite ^(.*)$ $1.php last;
}
I also need to rewrite http://server/abc/123 to http://server/abc.php/123 and also have this processed by the php-fpm
This is the fast-cgi code:
location ~ [^/]\.php(/|$) {
try_files $uri =404;
fastcgi_pass unix:/var/run/php5-fpm.sock;
fastcgi_index index.php;
fastcgi_param SCRIPT_FILENAME $document_root$fastcgi_script_name;
include fastcgi_params;
}
and this is the location rewrite
location #abc-php {
rewrite ^(.*)/abc/(.*)$ $1/photo.php/$2 last;
}
But I keep getting a 404. I'm not sure where I'm going wrong and any help would be appreciated.

You don't show how the named location #abc-php is invoked. I suspect that you have something like this to managed the extensionless PHP:
location / {
try_files $uri $uri/ #extensionless-php;
}
Your new rewrite rule can be added to the existing named location, like this:
location #extensionless-php {
rewrite ^(.*)/abc/(.*)$ $1/photo.php/$2 last;
rewrite ^(.*)$ $1.php last;
}
However, your fast-cgi block is incapable of handing the path_info, so you will need to look here for conventional wisdom, or use something like this:
location ~ ^(?<script>.*\.php)(?<pathinfo>.*)$ {
try_files $script =404;
include fastcgi_params;
fastcgi_param SCRIPT_FILENAME $document_root$fastcgi_script_name;
fastcgi_param PATH_INFO $pathinfo;
fastcgi_pass unix:/var/run/php5-fpm.sock;
}

Related

Catch-all should pass path to index.php in nginx

In apache I have an .htaccess that will rewrite from http://server/api/any/path/i/want to http://server/api/index.php if no file or folder is found.
Options -MultiViews
<IfModule mod_rewrite.c>
RewriteEngine On
RewriteBase /
RewriteCond %{REQUEST_FILENAME} !-f
RewriteCond %{REQUEST_FILENAME} !-d
RewriteCond $0#%{REQUEST_URI} ([^#]*)#(.*)\1$
RewriteRule ^.*$ %2index.php [L,NC,QSA]
</IfModule>
I'm moving to docker and will use nginx instead and I want to re-write the rewrite.
Important to note is that using apacheand .htaccess $_SERVER['REQUEST_URI'] is /api/any/path/i/want and not the re-written url (index.php....).
I'm not that well versed with nginx but from posts on SO I've figured some things out.
Relevant section of site.conf
location / {
root /app/html;
try_files $uri $uri/ index.html /index.php?$args;
}
location ~ \.php$ {
try_files $uri #missing;
fastcgi_split_path_info ^(.+\.php)(/.+)$;
fastcgi_pass php:9000;
fastcgi_index index.php;
include fastcgi_params;
fastcgi_param SCRIPT_FILENAME $document_root$fastcgi_script_name;
fastcgi_param PATH_INFO $fastcgi_path_info;
}
location #missing {
rewrite ^ $scheme://$host/api/index.php permanent;
}
The above config will unfortunately only redirect to index.php and is as far I've managed to get.
How can I do the same thing in nginx?
This is a typical nginx configuration for PHP-FPM.
server {
root /app/html;
location / {
try_files $uri $uri/ /api/index.php$is_args$args;
}
location ~ \.php$ {
fastcgi_split_path_info ^(.+\.php)(/.+)$;
fastcgi_pass php:9000;
fastcgi_index index.php;
include fastcgi_params;
fastcgi_param SCRIPT_FILENAME $document_root$fastcgi_script_name;
fastcgi_param PATH_INFO $fastcgi_path_info;
}
}
Notice the differences from your example:
Removed the unnecessary #missing location block.
Removed the try_files statement from the .php location block.
Moved the root declaration to the server block. If you need to have different roots, please specify this in your question.
The only try_files statement includes the full path for your api/index.php.
If a request comes for a non-existing path, it will be handled by your /app/html/api/index.php script, acting as a global entry-point.

How can I make this php redirect not be conflicted by Nginx

My php file 404.php contains a php redirect at the top of the file:
<?php
header('Location: some-page.html');
If I go to www.mysite.com/404, it redirects to www.mysite.com/some-page.html as expected, however, if I go to www.mysite.com/non-existent-page, the redirect does not work.
In my nginx.conf:
location ~* \.php$ {
try_files $uri =404;
fastcgi_split_path_info ^(.+\.php)(/.+)$;
fastcgi_pass unix:/var/run/php-fpm/php-fpm.sock;
fastcgi_index index.php;
fastcgi_param SCRIPT_FILENAME $document_root$fastcgi_script_name;
include fastcgi_params;
}
error_page 404 =200 /404.php;
try_files $uri #remExt;
location #remExt {
rewrite ^(.*)$ $1.php last;
}
if ($request_uri ~ ^/([^?]*)\.php($|\?)) {
return 301 /$1$is_args$args;
}
rewrite ^/index$ / permanent;
rewrite ^/(.*)/$ /$1 permanent;
How can I make the php redirect work when visiting www.mysite.com/non-existent-page?
PS
Sorry for the badly written question title. The clear and better written question title I wanted to use was automatically rejected.
Try this in your nginx config and restart it.
error_page 404 /404.php;
location = /404.php {
root /path/to/www/;
internal;
}
/404.php
<?php
http_response_code(301);
header('Location: /the/page/you/want');
nginx.conf
error_page 404 /404.php
location / {
try_files $uri $uri.php $uri/ =404;
}
then check syntax with nginx -t and reload nginx with systemctl reload nginx(if you're using systemd)
http://php.net/manual/en/function.http-response-code.php
It appears I have solved the problem, although there may be some edge cases where my Nginx code fails.
The problem was with this line error_page 404 =200 /404.php;. The solution is to use try_files inside location ~* \.php$.
index index.php;
location ~* \.php$ {
try_files $uri $uri/ /404.php$is_args$args;
fastcgi_pass unix:/var/run/php-fpm/php-fpm-root.sock;
fastcgi_index index.php;
fastcgi_param SCRIPT_FILENAME $document_root$fastcgi_script_name;
include fastcgi_params;
}
location / {
try_files $uri $uri/ $uri.php$is_args$query_string;
}
if ($request_uri ~ ^/([^?]*)\.php($|\?)) {
return 301 /$1$is_args$args;
}
rewrite ^/index$ / permanent;
rewrite ^/(.*)/$ /$1 permanent;

Nginx redirect with/without php extension

I am building an NGINX virtual host that should:
redirect pages ending with .php to the version without extension (301 redirect)
properly handle URLs not ending with .php by passing them to FASTCGI for php execution
My issue is that this will in effect create an infinite redirect loop. What am I missing here?
server {
server_name ~^my\.domain\.com$;
listen 80;
root /path/to/root;
error_page 404 /404.php;
location ~ \.php$ {
rewrite ^(.*)\.php$ $1 permanent;
break;
}
location / {
index index.php;
try_files $uri $uri/ #extensionless-php;
}
location #extensionless-php {
rewrite ^(.*)$ $1.php last;
}
location ~ \.php$ {
try_files $uri =404;
fastcgi_split_path_info ^(.+\.php)(/.+)$;
fastcgi_param SCRIPT_FILENAME $document_root$fastcgi_script_name;
# rest of fastcgi configuration...
}
}
For a start, you cannot have two location ~ \.php$ blocks. The solution is to process the fastcgi_pass within the named location itself and avoid the internal rewrite to .php. Something like this:
location / {
try_files $uri #php;
}
location #php {
try_files $uri.php $uri/index.php =404;
include fastcgi_params;
fastcgi_param SCRIPT_FILENAME $document_root$fastcgi_script_name;
fastcgi_pass ...;
}
location ~* ^(.*)\.php$ {
return 301 $1;
}
Notice that the index directive and the $uri/ elements are no longer required.

Run HHVM and PHP simultaneously with Nginx

I've been running a magento site using HHVM and Nginx. So far I hadn't experienced any problems and all I got was a very welcomed noticeable performance boost.
However, I've just added a plugin which uses PHP functions which are unsupported by HHVM. The good news is that this plugin is only needed for one page. Bad news is I'm not configuring Nginx right to serve this page only with PHP.
The usual fallback trick used by some people using error directives does not work in this case because the page doesn't throw an error. It just doesn't work if HHVM is enabled.
Instead, I've tried to write many variations of location blocks for that particular page. None worked, and these are the two that I had thought would do the trick.
Is there a way to run PHP only for a specific page?
FAILED SOLUTION 1
location ~ /page/.+\.php${
if (!-e $request_filename) { rewrite / /index.php last; }
fastcgi_pass unix:/var/run/php5-fpm.sock; ##Unix socket
fastcgi_param HTTPS $fastcgi_https;
fastcgi_param SCRIPT_FILENAME $document_root$fastcgi_script_name;
include fastcgi_params;
}
location ~ \.(hh|php)$ {
if (!-e $request_filename) { rewrite / /index.php last; }
fastcgi_keep_conn on;
fastcgi_pass unix:/var/run/hhvm/sock;
fastcgi_param SCRIPT_FILENAME $document_root$fastcgi_script_name;
fastcgi_param HTTPS $fastcgi_https;
include fastcgi_params;
}
FAILED SOLUTION 2 (with nested location)
location ~ /page/ {
location ~ .php$ {
if (!-e $request_filename) { rewrite / /index.php last; }
fastcgi_pass unix:/var/run/php5-fpm.sock; ##Unix socket
fastcgi_param HTTPS $fastcgi_https;
fastcgi_param SCRIPT_FILENAME $document_root$fastcgi_script_name;
include fastcgi_params;
}
}
location ~ \.(hh|php)$ {
if (!-e $request_filename) { rewrite / /index.php last; }
fastcgi_keep_conn on;
fastcgi_pass unix:/var/run/hhvm/sock;
fastcgi_param SCRIPT_FILENAME $document_root$fastcgi_script_name;
fastcgi_param HTTPS $fastcgi_https;
include fastcgi_params;
}
Try using variable condition approach, it works for me, locations starting with /serve-with-php/ are being served with unix:/var/run/php5-fpm.sock, while all the others are being served with 127.0.0.1:9000
server {
root /home/vearutop/test-hhvm;
index index.php index.html index.htm;
error_log /var/log/nginx-error.log error;
charset utf-8;
server_name test-hhvm;
location / {
set $fcgi_worker 127.0.0.1:9000; # hhvm handle
try_files $uri $uri/ /index.php?$query_string;
}
location /serve-with-php/ {
set $fcgi_worker unix:/var/run/php5-fpm.sock; # php-fpm handle
try_files $uri $uri/ /index.php?$query_string;
}
location ~ \.php$ {
fastcgi_split_path_info ^(.+\.php)(/.+)$;
fastcgi_pass $fcgi_worker;
fastcgi_index index.php;
include fastcgi_params;
}
}

Setting up Wordpress and Rails in Nginx

I have nginx set up for Rails application that has been working beautifully for me. Now I want to move my Wordpress blog from blog.website.com to website.com/blog, so web crawlers treat it as part of the site.
I created a symbolic link in my Rails app's public/ directory and added the following to my nginx configuration:
# Rails server
server {
root /project/path/current/public;
server_name project.com;
passenger_enabled on;
rails_env production;
client_max_body_size 20m;
if ($http_x_forwarded_proto != 'https') {
return 301 https://$host$request_uri;
}
location /blog {
index index.html index.php;
try_files $uri $uri/ /blog/index.php?q=$uri&$args;
if (!-e $request_filename) {
rewrite ^.+?(/blog/.*.php)$ $1 last;
rewrite ^ /blog/index.php last;
}
}
location ~ \.php$ {
try_files $uri =404;
fastcgi_intercept_errors on;
include fastcgi_params;
fastcgi_index index.php;
fastcgi_param SCRIPT_NAME $fastcgi_script_name;
fastcgi_param SCRIPT_FILENAME $document_root$fastcgi_script_name;
fastcgi_pass unix:/var/run/php5-fpm.sock;
}
}
This works great.
But what I'd like to do is skip the symbolic link part. I'd like nginx to route directly to the wordpress directory. I tried changing the /blog block to:
location ^~ /blog {
root /home/ubuntu/apps/blog;
index index.html index.php;
try_files $uri $uri/ /blog/index.php?q=$uri&$args;
if (!-e $request_filename) {
rewrite ^.+?(/blog/.*.php)$ $1 last;
rewrite ^ /blog/index.php last;
}
}
This works, as in I'm being correctly redirected to the wordpress folder but my server doesn't know what to do with php files and sends them to my browser as files to download.
I tried nesting the \.php$ location inside the /blog location but it results in 404 error.
What's wrong with the following piece and how to fix it?
location ^~ /blog {
root /home/ubuntu/apps/blog;
index index.html index.php;
try_files $uri $uri/ /blog/index.php?q=$uri&$args;
if (!-e $request_filename) {
rewrite ^.+?(/blog/.*.php)$ $1 last;
rewrite ^ /blog/index.php last;
}
location ~ \.php$ {
try_files $uri =404;
fastcgi_intercept_errors on;
include fastcgi_params;
fastcgi_index index.php;
fastcgi_param SCRIPT_NAME $fastcgi_script_name;
fastcgi_param SCRIPT_FILENAME $document_root$fastcgi_script_name;
fastcgi_pass unix:/var/run/php5-fpm.sock;
}
}
I haven't fixed the snippet from the question but I managed to solve the problem with nginx configuration without using a symbolic link by using two server blocks.
server {
location / {
proxy_pass http://localhost:82/;
}
location /blog {
root /var/proj/blog/current;
fastcgi_intercept_errors on;
include fastcgi_params;
fastcgi_index index.php;
fastcgi_param SCRIPT_NAME $fastcgi_script_name;
fastcgi_param SCRIPT_FILENAME $document_root$fastcgi_script_name;
fastcgi_pass unix:/var/run/php5-fpm.sock;
}
}
# Rails server
server {
listen 82;
root /var/proj/site/current/public;
server_name site.com;
passenger_enabled on;
rails_env staging;
client_max_body_size 20m;
# other configuration
}

Categories