We are just migrating to nginx from Apache 2 and are having a few issues with some rewrite rules. The following is what used to work on Apache:
RewriteEngine on
Options +FollowSymLinks
#RewriteCond %{DOCUMENT_ROOT}%{REQUEST_FILENAME} !-f
#RewriteCond %{DOCUMENT_ROOT}%{REQUEST_FILENAME} !-d
RewriteRule ^(.*)/p([0-9]+)-(.*)-page([0-9+]).html$ showproduct.php?product=$2&cpage=$4 [L]
RewriteRule ^(.*)/p([0-9]+)-(.*).html$ showproduct.php?product=$2 [L]
RewriteRule ^(.*)/p([0-9]+).html$ showproduct.php?product=$2 [L]
RewriteRule ^g([0-9]+)-(.*)-page([0-9]+).html$ showcat.php?cat=$1&page=$3 [L]
RewriteRule ^g([0-9]+)-(.*).html$ showcat.php?cat=$1 [L]
RewriteRule ^(.*)/index([0-9]+)-([0-9]+).html$ index.php?cat=$2&page=$3 [L]
RewriteRule ^(.*)/index([0-9]+).html$ index.php?cat=$2 [L]
RewriteRule ^m([0-9]+)-(.*)-protype([0-9]+).html$ member.php?uid=$1&protype=$3 [L]
RewriteRule ^m([0-9]+)-(.*).html$ member.php?uid=$1 [L]
RewriteRule ^board.html$ board.php [L]
RewriteRule ^b([0-9]+)-(.*).html$ board.php?msg=$1 [L]
RewriteRule ^u([0-9]+)-(.*)-page([0-9]+).html$ showcat.php?ppuser=$1&page=$3 [L]
RewriteRule ^u([0-9]+)-(.*).html$ showcat.php?ppuser=$1 [L]
RewriteRule ^s([0-9]+)-(.*)-page([0-9]+).html$ showmembers.php?cat=$1&page=$3 [L]
RewriteRule ^s([0-9]+)-(.*).html$ showmembers.php?cat=$1 [L]
And this is what we turned it into:
location /classifieds/ {
rewrite ^/classifieds/(.*)/p([0-9]+)-(.*)-page([0-9+]).html$ /classifieds/showproduct.php?product=$2&cpage=$4 permanent;
rewrite ^/classifieds/(.*)/p([0-9]+)-(.*).html$ /classifieds/showproduct.php?product=$2 permanent;
rewrite ^/classifieds/(.*)/p([0-9]+).html$ /classifieds/showproduct.php?product=$2 permanent;
rewrite ^/classifieds/g([0-9]+)-(.*)-page([0-9]+).html$ /classifieds/showcat.php?cat=$1&page=$3 permanent;
rewrite ^/classifieds/g([0-9]+)-(.*).html$ /classifieds/showcat.php?cat=$1 permanent;
rewrite ^/classifieds/(.*)/index([0-9]+)-([0-9]+).html$ /classifieds/index.php?cat=$2&page=$3 permanent;
rewrite ^/classifieds/(.*)/index([0-9]+).html$ /classifieds/index.php?cat=$2 permanent;
rewrite ^/classifieds/m([0-9]+)-(.*)-protype([0-9]+).html$ /classifieds/member.php?uid=$1&protype=$3 permanent;
rewrite ^/classifieds/m([0-9]+)-(.*).html$ /classifieds/member.php?uid=$1 permanent;
rewrite ^/classifieds/board.html$ /classifieds/board.php permanent;
rewrite ^/classifieds/b([0-9]+)-(.*).html$ /classifieds/board.php?msg=$1 permanent;
rewrite ^/classifieds/u([0-9]+)-(.*)-page([0-9]+).html$ /classifieds/showcat.php?ppuser=$1&page=$3 permanent;
rewrite ^/classifieds/u([0-9]+)-(.*).html$ /classifieds/showcat.php?ppuser=$1 permanent;
rewrite ^/classifieds/s([0-9]+)-(.*)-page([0-9]+).html$ /classifieds/showmembers.php?cat=$1&page=$3 permanent;
rewrite ^/classifieds/s([0-9]+)-(.*).html$ /classifieds/showmembers.php?cat=$1 permanent;
}
Which does not work. All we get when we try to visit our URLs are nginx 404s. We are still very new to nginx (and these rules are for third-party software that we cannot modify) so any pointers would be appreciated.
**Update: ** Following is some more (hopefully) useful information. When requesting a URL, the logs indicate that the 404 is happening before the rewrite takes place:
2013/03/11 10:38:18 [error] 10073#0: *13003643 open() "/home/site/public_html/classifieds/category-name-here/p1097-product.html" failed (2: No such file or directory), client: IP, server: site.com, request: "GET /classifieds/category-name-here/p1097-product.html HTTP/1.1", host: "www.site.com"
The full configuration file is below:
server {
server_name site.com www.site.com;
root "/home/site/public_html";
index index.php;
client_max_body_size 10m;
access_log /home/site/_logs/access.log;
error_log /home/site/_logs/error.log;
location /classifieds/ {
rewrite ^/classifieds/(.*)/p([0-9]+)-(.*)-page([0-9+]).html$ /classifieds/showproduct.php?product=$2&cpage=$4 permanent;
rewrite ^/classifieds/(.*)/p([0-9]+)-(.*).html$ /classifieds/showproduct.php?product=$2 permanent;
rewrite ^/classifieds/(.*)/p([0-9]+).html$ /classifieds/showproduct.php?product=$2 permanent;
rewrite ^/classifieds/g([0-9]+)-(.*)-page([0-9]+).html$ /classifieds/showcat.php?cat=$1&page=$3 permanent;
rewrite ^/classifieds/g([0-9]+)-(.*).html$ /classifieds/showcat.php?cat=$1 permanent;
rewrite ^/classifieds/(.*)/index([0-9]+)-([0-9]+).html$ /classifieds/index.php?cat=$2&page=$3 permanent;
rewrite ^/classifieds/(.*)/index([0-9]+).html$ /classifieds/index.php?cat=$2 permanent;
rewrite ^/classifieds/m([0-9]+)-(.*)-protype([0-9]+).html$ /classifieds/member.php?uid=$1&protype=$3 permanent;
rewrite ^/classifieds/m([0-9]+)-(.*).html$ /classifieds/member.php?uid=$1 permanent;
rewrite ^/classifieds/board.html$ /classifieds/board.php permanent;
rewrite ^/classifieds/b([0-9]+)-(.*).html$ /classifieds/board.php?msg=$1 permanent;
rewrite ^/classifieds/u([0-9]+)-(.*)-page([0-9]+).html$ /classifieds/showcat.php?ppuser=$1&page=$3 permanent;
rewrite ^/classifieds/u([0-9]+)-(.*).html$ /classifieds/showcat.php?ppuser=$1 permanent;
rewrite ^/classifieds/s([0-9]+)-(.*)-page([0-9]+).html$ /classifieds/showmembers.php?cat=$1&page=$3 permanent;
rewrite ^/classifieds/s([0-9]+)-(.*).html$ /classifieds/showmembers.php?cat=$1 permanent;
}
location / {
try_files $uri $uri/ /index.php$uri?$args;
}
location ~ "^(.+\.php)($|/)" {
fastcgi_split_path_info ^(.+\.php)(.*)$;
fastcgi_param SCRIPT_FILENAME $document_root$fastcgi_script_name;
fastcgi_param SCRIPT_NAME $fastcgi_script_name;
fastcgi_param PATH_INFO $fastcgi_path_info;
fastcgi_param SERVER_NAME $host;
if ($uri !~ "^/uploads/") {
fastcgi_pass 127.0.0.1:9006;
}
include fastcgi_params;
}
location ~* \.(js|css|png|jpg|jpeg|gif|ico)$ {
expires max;
log_not_found off;
access_log off;
}
location ~* \.(html|htm)$ {
expires 30m;
}
location ~* /\.(ht|git|svn) {
deny all;
}
}
**Update 2: ** After changing my location line to location ^~ /classifieds/, we finally were able to get the rewrites working, but were experiencing a redirect loop. As an example, the URL /classifieds/g2-general-category.html was properly being rewritten to /classifieds/showcat.php?cat=2 but it appears that the script was detecting this rewrite and attempting to send the user to the proper SEO URL, which rewrote to showcat.php, ad infinitum. Additionally, after the rewrite loop was finished, my browser URL bar would indicate showcat.php 50% of the time and g2-general-category.html the other 50% of the time. So I guess my question is – How can we avoid this behavior? To my untrained eye, it looks like what is happening is that:
User visits g2-general-category.html.
nginx sends user to showcat.php?cat=2
PHP script sees that user is not using the SEO'd URL, so does a header redirect to send them to the correct URL, where nginx then rewrites it to showcat.php?cat=2 again.
Best Answer
The
rewrite
directives seem to be correct.However, from your provided information I can't tell you much about what is wrong.
Find out where the
404
happens: before or after the redirect.Examine the log files or use in-browser development tools (like Firebug) to follow the redirect flow.
Is that given snippet all you got inside the
server
block? What about the logic that handles the redirect targets?You should post the rest as well.
Also, look out for other
location
blocks possibly interfering with the URLs.See the nginx docs for the order of matching
location
s.Update: Guess I found your mistake:
The
location ~* \.(html|htm)$
block matches all your requests usually going to/classifieds/
because regular expression are prefered by the mathing engine by default.To raise priority of
location /classifieds/
you should use the^~
flag:Corresponding docs entry:
Redirect loop:
It seems like you want to keep the SEO-friendly URIs for outer appearance.
In this case, modify the
rewrite
s to only rewrite internally - without redirecting the browser.To achieve this behaviour, use the
last
flag instead ofpermanent
as follows:The location match engine will then try to match the rewritten URI.
While
redirect
andpermanent
trigger a HTTP redirect (temporary/permanent),last
andbreak
will only affect the internal URI value.It is all described in the docs.