Fix Django Static Files Permission Problems

One of the most common problems you may encounter when deploying your first Django app is that static files work perfectly in the dev environment with runserver and DEBUG = True, but the moment you try to deploy the site on the production server with a WSGI server and nginx, you get 403 permission errors for static files.

Looking at permissions on your static directory may not show anything obviously wrong, but in my experience, the computer doesn't lie, and your permissions certainly may prohibit nginx from accessing your static files.

About your user

In this article, I will be using a user named ubuntu, as it is commonly used on Ubuntu servers. Please replace it with the name of the user the WSGI (or ASGI) server runs as.

Common cause of the permission denial

Depending on the guides you followed while building and deploying your app, you may have your STATIC_ROOT defined as follows:

1
2
3
# settings.py

STATIC_ROOT = BASE_DIR / "static"

and you may have deployed your app as your own user, e.g. ubuntu, under your own home directory (/home/ubuntu/myapp). Finally, you installed and configured nginx with the a location block similar to:

1
2
3
4
5
6
7
http {
    server {
        location /static/ {
            root /home/ubuntu/myapp/;
        }
    }
}

While Django, running as the ubuntu user, will happily write static files to that directory, and that particular directory may be world-readable, most Linux distros assign permissions like 700 or 750 to users' home directories, meaning that other users cannot access them, which is important to safeguard your data. You can verify the permissions as follows:

1
2
$ ls -lh /home | grep ubuntu
drwxr-x---  4 ubuntu        ubuntu        4.0K Aug 30  2024 ubuntu

As you can see, the permissions are set to drwxr-x---. As nginx normally runs under its own system user (httpd, nginx, www-data, or similar), it will get its permissions from the other group, in this case, --- meaning it cannot read, write, or execute the directory. In order to access any directory, the user also needs the appropriate access to all parent directories, so the permissions on the myapp and static subdirectories are irrelevant.

Static file directory permissions

How to fix it

The easiest and most secure solution is to simply move the static files directory to a location outside your user's home so nginx may access it. Two common options are under /srv/http/ or /var/www/. Let's create a directory owned by ubuntu so collectstatic may write to it.

1
2
$ sudo mkdir -p /srv/http/myapp/static/
$ sudo chown -R ubuntu:ubuntu /srv/http/myapp/

Next, we need to update the Django settings to reflect those changes.

1
2
# settings.py
STATIC_ROOT = "/srv/http/myapp/static/"

Then we need to update the nginx settings.

1
2
3
4
5
6
7
http {
    server {
        location /static/ {
            root /srv/http//myapp/;
        }
    }
}

We restart the WSGI server and nginx. Assuming you run nginx via systemd:

1
$ sudo systemctl restart nginx.service

Finally, run collectstatic and hopefully the issue will be resolved.

Aug. 30, 2024, 3:18 p.m.

Tags

Django