My developers want to allow download some files only to users in lan. I said ok it's quite simple and I wrote changes to nginx config like this :
location /restricteddir/download/file {
allow 192.168.0.0/16;
allow 10.0.0.0/8;
deny all;
}
Ok from outside I'm getting 403 so thats good but from inside (LAN) gives me 404. Why?
I have checked, the location of file doesn't exist on disk. The developer told me that the location is dynamically generated by php so files are in tmp directory but after you click link like:
https://example.com/report/download/file/id/somefile.txt
it should started download but it gives 404 error.
The last physical loaction is /restricteddir/download
so file/id/somefile.txt
is generated by php.
For testing I changed the location to /restricteddir/download
and after that hiting https://example.com/restricteddir/download
gave me 404 to.
I'm confused after disabling restriction to that dir everythings works fine, I can download file from https://example.com/report/download/file/id/somefile.txt
and hit https://example.com/report/download/
without 404. So where is the bug ? What should I add to my nginx configuration to make it work?
EDIT1 This is full config for this virtualhost:
#example.com:443
server {
listen 443 default;
ssl on;
ssl_certificate example.crt;
ssl_certificate_key example.key;
ssl_session_timeout 15m;
ssl_protocols SSLv2 SSLv3 TLSv1;
ssl_ciphers ALL:!ADH:!EXPORT56:RC4+RSA:+HIGH:+MEDIUM:+LOW:+SSLv2:+EXP;
ssl_prefer_server_ciphers on;
server_name example.com;
access_log /var/log/nginx/example.com.access.log;
error_log /var/log/nginx/example.com.error.log;
location / {
root /sites/public;
index index.php;
if (!-f $request_filename) {
rewrite ^.*$ /index.php last;
break;
}
}
location /restricteddir/download/file {
allow 192.168.0.0/16;
allow 10.0.0.0/8;
deny all;
}
#PHP
location ~ \.php$ {
fastcgi_pass 127.0.0.1:9000;
fastcgi_index index.php;
include /fastcgi_params;
fastcgi_param SCRIPT_FILENAME /sites/public$fastcgi_script_name;
}
}
server {
listen 80 default;
server_name example.com;
access_log off;
rewrite ^(.*)$ https://example.com$1 permanent;
}
And I founded this in my logs:
2012/08/07 11:55:43 [error] 11121#0: *90 open() "/usr/share/nginx/html/restricteddir/download/file/id/somefile.txt" failed (2: No such file or directory), client: 10.200.2.70, server: example.com, request: "GET /restricteddir/download/file/id/somefile.txt HTTP/1.1", host: "example.com"
So now I know that nginx is looking this location in wrong root /usr/share/nginx/html/
instead in /sites/public
So maybe i should write this like :
location /sites/public/restricteddir/download/file {
allow 192.168.0.0/16;
allow 10.0.0.0/8;
deny all;
}
EDIT2
I moved root directive to server block and now in logs after enabling restriction for location /restricteddir/download/file I have:
2012/08/09 10:43:12 [error] 32120#0: *71 open() "/site/public/restricteddir/download/file/id/somefile.txt" failed (2: No such file or directory), client: 10.2.1.120, server: example.com, request: "GET /restricteddir/download/file/id/somefile.txt HTTP/1.1", host: "example.com"
So now nginx is looking in right place but doesn't find enything. Like this file was not generated by php? I'm strugling with it and have no idea what is wront... Thats a simple task restrcit location why this doesn't work ?
EDIT3
This is how looks my virtualhost config now:
#example.com:443
server {
listen 443 default;
ssl on;
ssl_certificate example.crt;
ssl_certificate_key example.key;
ssl_session_timeout 15m;
ssl_protocols SSLv2 SSLv3 TLSv1;
ssl_ciphers ALL:!ADH:!EXPORT56:RC4+RSA:+HIGH:+MEDIUM:+LOW:+SSLv2:+EXP;
ssl_prefer_server_ciphers on;
server_name example.com;
access_log /var/log/nginx/example.com.access.log;
error_log /var/log/nginx/example.com.error.log;
root /sites/public;
location / {
index index.php;
if (!-f $request_filename) {
rewrite ^.*$ /index.php last;
break;
}
}
location /restricteddir/download/file {
allow 192.168.0.0/16;
allow 10.0.0.0/8;
deny all;
}
#PHP
location ~ \.php$ {
fastcgi_pass 127.0.0.1:9000;
fastcgi_index index.php;
include /fastcgi_params;
fastcgi_param SCRIPT_FILENAME /sites/public$fastcgi_script_name;
}
}
server {
listen 80 default;
server_name example.com;
access_log off;
rewrite ^(.*)$ https://example.com$1 permanent;
}
So I only moved root directive into server block, after that nginx is looking in good place but still geting 404. I'm confused beacuse after I comment out location /restricteddir/download/file block everything is working fine and I can download the file.
For me it't very strange because its only simple restriction ... why is it that after enabling it nginx could not find that file ...
Two suggestions:
root
directive into theserver
block, so it will apply to alllocation
blocks that follow it. That appears to be your intent.location /sites/public
doesn't make sense.And some other feedback:
The question of whether the files physically exist or not does not make a difference when processing
location
directives, they will match regardless.Another mis-match I see is that your log entry refers to "restricteddir", but your "full config" post does not mention this. It mentions a "report" dir instead.
Firstly, I'd avoid the following
if
block if possible because if is evil. Usetry_files
instead:This is better:
For clarity, I'd move
root
andindex
out oflocation /
and into theserver
block:Are the files completely dynamically generated by PHP, so don't exist on the filesystem directly and therefore can't be served by nginx without passing the request on to PHP? If so, you need to pass things with
fastcgi_pass
to fastcgi so PHP can create & serve the file, rather than nginx trying to serve something that doesn't exist. So:If the files actually exist on-disk, but are in a different location, i.e. the request comes in as
https://example.com/report/download/file/id/somefile.txt
which actually points to the on-disk location of/sites/public/restricteddir/download/file/id/somefile.txt
and you want nginx to serve it directly without handing over to fastcgi then you want the alias directive.One final thing to check: if nginx and fastcgi are running as different users, make sure that both have the correct OS file permissions to read the files in question. If nginx is looking in the correct place but still can't find the file, perhaps its owner and group are fastcgi:fastcgi with 660 permissions? Either that or there's some sort of caching going on, such as
open_file_cache
in nginx.conf