I am having trouble with converting .htaccess files to nginx. I have 3 .htaccess files. The first .htaccess file is located in the document root and is as follows:
Options +FollowSymLinks
RewriteEngine On
RewriteRule ^img-(.*)\.html img.php?id=$1 [L]
RewriteRule ^slide-(.*)\.html slider.php?id=$1 [L]
RewriteRule ^page-(.*)\.html page.php?name=$1 [L]
RewriteRule ^contact\.html$ contact.php [QSA,L,NC]
The second .htaccess file is located in a folder called upload:
RewriteEngine On
RewriteCond %{HTTP_REFERER} !^http://(.+\.)?foo\.com/ [NC]
RewriteCond %{HTTP_REFERER} !^$
RewriteRule .*\.(jpe?g|gif|bmp|png)$ nohotlink.gif [L]
<Files ~ "\.(php|sql|php3|php4|phtml|pl|py|jsp|asp|htm|shtml|sh|cgi)$">
order allow,deny
deny from all
</Files>
And the third and final .htaccess file is found in a subdirectory of the upload folder named "small":
RewriteEngine Off
Now I have created a folder in /etc/nginx called includes and made 3 seperate .access files with these rewrite rules:
For the first .htaccess file located in the document root directory I have created an file in /etc/nginx/includes called root.access. In this file I have:
# nginx configuration
location /img {
rewrite ^/img-(.*)\.html /img.php?id=$1 break;
}
location /slide {
rewrite ^/slide-(.*)\.html /slider.php?id=$1 break;
}
location /page {
rewrite ^/page-(.*)\.html /page.php?name=$1 break;
}
location /contact {
rewrite ^/contact\.html$ /contact.php break;
}
For the second file located in the "upload" folder I have crated a file in /etc/nginx/includes called upload.access. This file contains the following:
# nginx configuration
location /upload {
if ($http_referer !~ "^http://(.+\.)?foo\.com/"){
rewrite .*\.(jpe?g|gif|bmp|png)$ /nohotlink.gif break;
}
}
location ~ \.(php|sql|php3|php4|phtml|pl|py|jsp|asp|htm|shtml|sh|cgi)$ {
deny all;
}
And for the third and final file I have created a file in /etc/nginx/includes names small.access. The contents of this file are as follows:
# nginx configuration
location /upload/small {
}
In the server block configuration file I have:
location / {
try_files $uri $uri/ /index.php;
include /etc/nginx/includes/root.access;
}
location /upload {
include /etc/nginx/includes/upload.access;
}
location /upload/small {
include /etc/nginx/includes/small.access;
}
Now with this configuration when trying the site I receive 403 errors. Nginx error log reports:
[error] 18156#0: *7 access forbidden by rule, client: 111.**.**.**, server: foo.com, request: "POST /upload.php HTTP/1.1", host: "foo.com", referrer: "http://foo.com/"
Now under apache everything works no problems. But I can not see why I am getting 403 errors. I am also worried that the rewrite rules as I have stated them, beyond the 403 error will not function properly at all. Can anyone help me with this? I can not see what is wrong here.
Best Answer
This is the standard nginx behaviour for this part of your configuration :
Why?
Let me clarify how locations work : when nginx reads configuration files, it will sort location blocks under 3 types :
location = /upload { }
location /upload { }
location ~ /upload { }
Once a request comes to nginx, the location selection process is as follows :
So in your case, the location block matching the
.php
extension takes precedence over the location block matching the/upload
part of the URI.Edit : Clarification on solution, alternative solution added.
Using the
^~
you can tell nginx to change his behaviour for step 2 so it will use the matching prefixed location immediately, bypassing regular expression locations lookup. So you have 2 solutions :Solution 1 :
upload.access :
same server block
Solution 2 :
upload.access :
server block :
Now, your current configuration will not lead to anything if you don't set up a location to forward php file processing : check out nginx fastcgi module. Then you will need to change your rewrite rules in the root.access file so they are not resolved in the current location context (i.e. create one unique fallback location and change
break
tolast
to tell nginx to run the location selection process again after rewrite).