Nginx rewrite non-existent files under sub directory with rewrite rules

Joyce Babu joyce at
Wed Nov 26 12:05:06 UTC 2014

Hi everyone,

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. I have created a
sample scenario to explain the problem.


   1. /test/abc/pics/ should redirect to /test/abc/wallpapers/
   2. /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.
   3. /test/abc should redirect to /test/abc.html
   4. /test/abc.html should be rewritten to /test/index.php
   5. /test/abc/def/year-2014.php should be rewritten to
   6. All static files (.gif, .jpg, .png, .mpg....) should be served
   directly with a very long expiry time.
   7. All files ending in .html should be served directly. If the file does
   not exist the request should be rewritten to /fallback.php
   8. 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


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; # Rule 5 } # # Fallback Rules #
location ~*
\.(gif|jpg|jpeg|png|ico|3gp|flv|mpg|mpeg|mp4|mp3|swf|txt|xml|pdf|zip)$ {
expires 1M; # Rule 6 try_files $uri /404.php; } location ~
(\.php|\.html|/)$ { try_files $uri "${uri}index.php" /fallback.php =404; #
Rules 7 & 8 include php-fpm.conf; }

*php-fpm.conf  *

include fastcgi.conf;
fastcgi_index index.php;


   1. Since the fallback rules are regular expressions, they are selected
   instead of the location specific rules
   2. 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.
   3. 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

What am I doing wrong here? Is there a simple way to have all existing
files served depending on their extension and only non existent files match
the location blocks / rewrite rules?

Thanks & Regards,
Joyce Babu
-------------- next part --------------
An HTML attachment was scrubbed...
URL: <>

More information about the nginx mailing list