Nginx rewrite from .php to .php under same location
I am trying to move a site with a large number (93) of .htaccess files from Apache to Nginx.
There are over 800 rewrite rules to convert. To optimize performance, I have decided to
place the rules under separate nested location blocks (61 blocks in total).
But I am having problem with rewriting some of the rules.
Requirements:
/test/abc/pics/ should redirect to /test/abc/wallpapers/
/test/abc/pics/800/a.jpg should be served directly, if the file is present. If it does not exist,
then the request should be rewritten to /test/abc/pics/pic.php, which will
create the file on first request. Subsequent requests will be served directly.
/test/abc should redirect to /test/abc.html
/test/abc.html should be rewritten to /test/index.php
/test/abc/def/year-2014.php should be rewritten to /test/abc/def/index.php
All static files (.gif, .jpg, .png, .mpg....) should be served directly with a very long expiry time.
All files ending in .html should be served directly. If the file does not exist the request should be rewritten to /fallback.php
All files ending in .php or / should be executed by PHP-FPM. If the file does not exist it should be rewritten to /fallback.php
Config:
index index.php;
#
# Location Specific Rules
#
location /test/abc/ {
location /test/abc/pics/ {
# For ensuring 'serve directly, if file exists' condition of Rule 2
try_files $uri #rewrite_pics;
}
location /test/abc/def/ {
try_files $uri $uri/index.php #rewrite_def;
}
}
location /test/ {
rewrite "^/test/([a-z-]+)$" /test/$1.html permanent; # Rule 3
rewrite "^/test/([a-z-]+).html$" /test/index.php?symbol=$1 last; # Rule 4
}
location #rewrite_pics {
rewrite "^/test/abc/pics/$" /test/abc/wallpapers/ permanent; # Rule 1
rewrite "^/test/abc/pics/([0-9]+)/(.*)$" /test/abc/pics/pic.php?width=$1&height=$1&pic=$2 last; # Rule 2
}
location #rewrite_def {
rewrite "(?i)^/test/abc/def/year-([a-z]+).php$" /test/abc/def/index.php?year=$1 last;
}
#
# Fallback Rules
#
location ~* \.(gif|jpg|jpeg|png|ico|3gp|flv|mpg|mpeg|mp4|mp3|swf|txt|xml|pdf|zip)$ {
expires 1M; # Rule 5
try_files $uri /404.php;
}
location ~ (\.php|\.html|/)$ {
try_files $uri "${uri}index.php" /fallback.php =404;
include php-fpm.conf;
}
php-fpm.conf
include fastcgi.conf;
fastcgi_index index.php;
fastcgi_pass 127.0.0.1:9000;
Problem:
Since the fallback rules are regular expressions, they are selected instead of the location specific rules
If I use ~ prefix for all location specific rules, then the fallback rules are never executed.
Request for /test/abc/pics/800/a.jpg will be rewritten to /test/abc/pics/pic.php which will again match the
same location config. So the file is not executed and is downloaded as is.
So, I added 'include php-fpm.conf;' to all location blocks (except named locations). But this causes all
requests under /test/abc/pics/ (including existing .jpg files) to pass to the PHP-FPM. Which leads to an access denied error,
since only .php extension is allowed by security.limit_extensions.
What am I doing wrong here? Is there a simple way to have all existing files served based on their extension
and only non existent files match the location blocks / rewrite rules?
Related
I have this hierarchy on my server:
/var/www/domain.tld/web
/sub
The root in the /etc/nginx/sites-available/domain.tld is set like this:
server {
root /var/www/domain.tld/web;
index index.html index.php index.htm;
...
location / {
try_files $uri $uri/ =404;
}
How can I make the nginx to dynamically forward to specific folder so if I make folder in /sub for example /var/www/domain.tld/sub/subdomain so if I make request http://subdomain.domain.tld it will forward to this folder in folder sub?
So again something.domain.tld would be going to /var/www/domain.tld/sub/something but domain.tld would be going to /var/www/domain.tld/web
Thank you!
First off, welcome to StackOverflow! :)
There are probably a few ways of achieving this, but I would try a simple map to set a $my_subdir variable from the $host, which you can then use in your root. The $host variable is set automatically from the incoming request.
In this example, we're using a regular expression to check if the $host matches subdomain.domain.tld. If it does, capture the subdomain part - the bit in brackets - and use that to make the value "sub/subdomain" ($1 means use the first thing captured from the regular expression). If it doesn't match, it defaults to "web".
That way,
when the request comes in as something like http://domain.tld/foo.html, the response served is /var/www/domain.tld/web/foo.html
if the request comes in as something like http://bar.domain.tld/foo.html, the response served is /var/www/domain.tld/sub/bar/foo.html
map $host $my_subdir {
~^(?:www\.)?((?!www\.)[^.]+)\.domain\.tld$ sub/$1;
default web;
}
server {
root /var/www/domain.tld/$my_subdir;
index index.html index.php index.htm;
...
location / {
try_files $uri $uri/ =404;
}
Url https://example.com/profile/chico
must be understood by nginx as:
https://example.com/profile/?username=chico (the url that currently works).
https://example.com/profile/ currently works as well, as it currently resolves to index.php, without the username param.
I currently have
location /profile/ {
index /profile/index.php;
}
There are so many different things about this on the web and I didn't find specifically what I need.
Also tried
location /profile/ {
rewrite ^/profile/(.*)$ /profile/?username=$1;
}
Try:
location /profile/ {
try_files $uri #rewrite;
}
location #rewrite {
rewrite ^/profile/(.+)$ /profile/index.php?username=$1 last;
rewrite ^ /profile/index.php last;
}
If the first rewrite matches, the second rewrite is ignored. After the URI is rewritten with a .php extension, the processing moves to a different location block.
See this document for more.
EDIT: Added try_files block to handle static content.
I'm converting this htaccess file htaccess file
to nginx using
http://winginx.com/ru/htaccess
but don't understand where i should paste result. I have created
include file
include /etc/nginx/myfile
and pasted file there but when i'm reloading (restarting) Nginx it Fails.
Could you help me?
I suspect these apache .htaccess converters do not fully utilize the unique features of nginx. I would recommend trying something like this:
server {
listen 80 default_server;
server_name _;
root /var/www/example.com;
index index.php;
# if the file or directory doesn't exist, serve /index.php
try_files $uri $uri/ /index.php;
# if the request is exactly /sitemax.xml, serve sitemap_xml.php
location = /sitemax.xml {
try_files /modules/sitemap/sitemap_xml.php =404;
}
# hide regex location in a prefix location to avoid confusion
# introduced by multiple regex locations
location /pages-print {
location ~ ^/pages-print(\d+) {
try_files /modules/pages/print.php?page=$1 =404;
}
}
}
I have found solution. I tried paste result from the convertor to nginx.conf and it was mistake. I, instead created file in /etc/nginx/ and named it htac.rules (i think it doesn't matter of how you'll name it).
Then i opened file etc/nginx/sites-enabled/default and in location / inserted include /etc/nginx/htac.rules
so.
in htac.rules i inserted converting result without location / {...}
and, yeah. It solved my problem.
Thanks everyone for helping me.
I'm currently trying to install AMember and I've uploaded the filed to the FTP, however, I whenever I navigate to the install link:
http://domain.com/amember/setup
I am receiving this error message:
————————————————————————————————————————
"Seems your webhosting does not support mod_rewrite rules required by aMember. There may be several reasons:
You have not uploaded file amember/.htaccess (it might be hidden and invisble with default settings)
Your webhosting has no mod_rewrite module enabled. Contact tech support to get it enabled
Your webhosting uses software different from Apache webserver. It requires to convert rewrite rules located in amember/.htaccess file into the webserver native format. Contact webhosting tech for details.
You may continue aMember installation, but aMember will not work correctly until mod_rewrite issues are resolved."
————————————————————————————————————————
I'm not exactly sure how to work around this. The host I'm using is Hostmonster, and I've contacted support which directed me to a page regarding mod_rewrites, however, I'm not sure where to go from there.
The page they sent me can be found here: https://my.hostmonster.com/cgi/help/94
Also, in case it's worth noting, here's what the current .htaccess file in the AMember directory has in it.
# Sample Nginx rules configuration:
# aMember rules (replace /amember to actual aMember Pro path from site root)
#
# location ~* ^/amember/.*\.(js|ico|gif|jpg|png|css|swf|csv)$ {}
# location ~* ^/amember/setup/index.php$ { try_files not-existing-file #php; }
# location ~* ^/amember/js.php { try_files not-exiting-file #php; }
# location ~* ^/amember/index.php$ { try_files not-existing-file #php; }
# location ~* ^/amember/public.php$ { try_files not-existing-file #php; }
#
# location ~* ^/amember/public { rewrite ^.*$ /amember/public.php; }
# location ~* ^/amember/setup { rewrite ^.*$ /amember/setup/index.php; }
# location ~* ^/amember { rewrite ^.*$ /amember/index.php; }
#
# you must already have something like that in your nginx configuration:
#
# location ~ \.php$ {
# try_files not-existing-file #php;
# }
# location #php {
# fastcgi_pass 127.0.0.1:9000;
# include fastcgi_params;
# }
#
# it is necessary to have #php section, as it is referred by aMember rules, and
# it must be located at bottom
#
#
<IfModule mod_rewrite.c>
RewriteEngine on
RewriteRule ^public public.php [L]
RewriteRule ^js.php js.php [L]
RewriteRule !\.(js|ico|gif|jpg|png|css|swf|csv|html)$ index.php
</IfModule>
<IfModule mod_php5.c>
# php_flag magic_quotes_gpc off
</IfModule>
Thanks in advance for any help, Bc.
my host server is nginx.
in the root directory i have installed magento, then i created a file named blog, then installed wordpress into it.
now, the directory is:
app
includes
....
blog/wp-admin
when i set http://www.example.com/blog/index.php/%postname%.html in Permalink Settings. access all the post, it's ok. now i want to remove the index.php. namely change it into http://www.example.com/blog/%postname%.html.when i delete the index.php. all the post are not unavailable,
EDIT:
i put the code in the nginx.conf.
location /blog/ {
index index.php;
try_files $uri $uri/ /blog/index.php?$uri&$args;
rewrite ^ /index.php? last;
}
but it doesn't work. is there something i lost?