Linux – How to restrict access to dynamically generated location in nginx

configurationlinuxnginxPHP

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 …

Best Answer

Two suggestions:

  1. Move the root directive into the server block, so it will apply to all location blocks that follow it. That appears to be your intent.
  2. Keep in mind that the location directive applies to URIs not *file paths. So for example, the idea of 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.