nginx+django serving static files

I have followed instruction for setting up django with nginx from the django wiki (https://code.djangoproject.com/wiki/DjangoAndNginx) and have nginx setup as follows (a few name changes to fit my setup).

    user  nginx nginx;

worker_processes  2;

error_log /var/log/nginx/error_log info;

events {
    worker_connections  1024;
    use epoll;
}

http {
    include     /etc/nginx/mime.types;
    default_type    application/octet-stream;

    log_format main
        '$remote_addr - $remote_user [$time_local] '
            '"$request" $status $bytes_sent '
        '"$http_referer" "$http_user_agent" '
        '"$gzip_ratio"';

    client_header_timeout   10m;
    client_body_timeout 10m;
    send_timeout        10m;

    connection_pool_size        256;
    client_header_buffer_size   1k;
    large_client_header_buffers 4 2k;
    request_pool_size       4k;

    gzip on;
    gzip_min_length 1100;
    gzip_buffers    4 8k;
    gzip_types  text/plain;

    output_buffers  1 32k;
    postpone_output 1460;

    sendfile    on;
    tcp_nopush  on;
    tcp_nodelay on;

    keepalive_timeout   75 20;

    ignore_invalid_headers  on;
    index index.html;

    server {
        listen 80;
        server_name localhost;
        location /static/  {
            root /srv/static/; 
        }
        location ~* ^.+\.(jpg|jpeg|gif|png|ico|css|zip|tgz|gz|rar|bz2|doc|xls|exe|pdf|ppt|txt|tar|mid|midi|wav|bmp|rtf|js|mov) {
            access_log   off;
            expires      30d; 
        }
        location / {
            # host and port to fastcgi server
            fastcgi_pass 127.0.0.1:8080;
            fastcgi_param PATH_INFO $fastcgi_script_name;
            fastcgi_param REQUEST_METHOD $request_method;
            fastcgi_param QUERY_STRING $query_string;
            fastcgi_param CONTENT_TYPE $content_type;
            fastcgi_param CONTENT_LENGTH $content_length;
            fastcgi_pass_header Authorization;
            fastcgi_intercept_errors off;
            fastcgi_param REMOTE_ADDR $remote_addr;
            }
        access_log  /var/log/nginx/localhost.access_log main;
        error_log   /var/log/nginx/localhost.error_log;
    }
}

Static files aren't being served (nginx 404). If I look in the access log it seems nginx is looking in /etc/nginx/html/static... rather than /srv/static/ as specified in the config.

I've no clue why it's doing this, any help would be hugely appreciated.


Solution 1:

Short answer: see the last location in the long version. Technically, the setup described in that page is wrong. See the end of the answer for reasons.

Long answer: you porbably have /etc/nginx... path in your logs because requests for static files don't match your static location(the regex location takes precedense) an you have not specified root for the server block itself.

When your request matches the regex location, nginx will search files under /etc/nginx. To fix this you might want to add root directive directly inside server block as described above, or under each non-proxied location (the same goes to fastCGI as well).

Also spotted: if you specify root directive under location nginx will search for files under $document_root/$location, e.g. in /srv/static/static which is 99% not you might want. You may use alias directive but nginx documentation prefers to redefine root directive if this is possible:

location /static {
    root /srv;
}

The alias directive works just like you expected, so you might want to write this instead:

location /static {
    alias /srv/static;
}

As to the regex location, you might want to put it inside /static location. Also since there will be only static files, you can get rid of ther regex location, and final location will look like this:

location /static {
    root /srv;
    access_log   off;
    expires      30d;
}

Why the described setup is wrong and how to fix this

According to the commands the user provided, he likes to have most of the components as fresh as possible running on a Debian-like Linux. But instead of correctly installing everything by hand or just using aptitude he starts mixing and installing software from packages as well. This will work for some development box but this is a no-go for any production. So here are some points:

  1. Please install software in one way, preferrably from packages. If you need bleeding edge, build packages for them (that's not so hard ;) ) or use some environment to separate it from system like virtualenv.
  2. You don't need to manually add nginx user and group. Web-servers run from www-data:www-data in Debian. Since your setup does not intend to run any code within web-server context, adding more users is useless.
  3. The article suggests to redefine the whole /etc/nginx/nginx.conf file which is totally wrong, especially on Debian-like systems. Instead of doing this you might want to create sample_project file in /etc/nginx/sites-available and link it to /etc/nginx/sites-enabled to make nginx attach your configuration`:
    # cd /etc/nginx/sites-enabled && ln -s ../sites-available/sample_project sample_project
  4. The sample_project file in this case should contain only server block itself, nothing more.
  5. Most of the directives (except log_format and maybe some others) should have context of your virtualhost and thus should be placed under server block in your sample_project file. You will not affect the work of other services running on this web-server. You may place log_format directive in your file but outside of any block and before the server block itself.
  6. Instead of writing all that fastcgi_pass directives one should write include fastcgi_params and only redefine those that not correct to current setup.
  7. To have your log files automatically rotating by logrotate you should name them to match *access.log or *error.log wildcard.

Giving this the minimal working host configuration file /etc/nginx/sites-available/sample_project might look like:

server {
    listen 80;
    server_name myhostname.com;
    root /home/user/django/sample_project;

    location /static {
        root /srv;
        access_log   off;
        expires      30d;
    }

    location / {
        include fastcgi_params;
        fastcgi_pass 127.0.0.1:8080;
    }

    access_log      /var/log/nginx/sample_project.access.log combined;
    error_log       /var/log/nginx/sample_project.error.log warn;
}