DEV Community

Cover image for The Right Way to serve static files when using Django with Gunicorn
Prahlad Yeri
Prahlad Yeri

Posted on • Edited on • Originally published at prahladyeri.github.io

The Right Way to serve static files when using Django with Gunicorn

Yesterday, I learned during deployment that your Django app when used in combination with gunicorn will refuse to serve static files, do whatever you may. I looked up almost every Stack Overflow answer post on this topic including this, this and this.

I meddled with almost every hopeful setting including STATICFILES_DIRS[], STATIC_ROOT and STATIC_URL but to no avail. Its as if Django is designed to refuse serving of static files when using gunicorn and that's what I started to suspect after everything failed.

And my suspicion was almost confirmed by this post which says that:

Gunicorn will only serve the dynamic content, i.e. the Django files

But I know that's not strictly true because I've used Gunicorn with Flask in the past and it serves static files of your Flask app without any issues at all!

But then I thought that its better to handle static files using nginx anyway and since I was already using nginx as the front proxy on my server anyway, I thought of trying that post's suggestion. As mentioned, I added a new location section to my nginx configuration file as follows:

location /static {
        autoindex on;
        alias /path/to/staticfiles;
    }
Enter fullscreen mode Exit fullscreen mode

And that's exactly what worked! I bypassed gunicorn entirely and static files are now being served directly by the front server and I think this is a more efficient setup than having gunicorn serve the static files.

But why gunicorn/django refuse to serve static files directly still remain a mystery. I think the problem lies somewhere in Django and not gunicorn because as I said, I've seen gunicorn serve Flask static files before.

Top comments (3)

Collapse
 
prahladyeri profile image
Prahlad Yeri • Edited

Yep, I've read that django docs page and feel that it shows a needlessly confusing and lengthy process. For example, it really makes no sense to have an additional collectstatic process just to copy static files from one folder to other!

$ python manage.py collectstatic
Enter fullscreen mode Exit fullscreen mode

All this does is copy your files from one static folder in your project directory (say "/static/") to another (say "/staticfiles/"). But doing none of that will actually make django serve those static files on production -especially when there is an additional layer like gunicorn. The StackOverflow is filled with these issues. I think django should outright refuse to serve static on production instead of covertly/silently failing in this manner!

Collapse
 
tombohub profile image
tombohub

what do you mean it copies files from one folder to another?

collectstatic collects static files from all the apps in your django project to single one folder.

Collapse
 
jsauceda profile image
Jorge Sauceda • Edited

I had the same issue. I found that the /home/user directory did not have execution rights for its user group and others. So, I changed the permissions running
$ chmod 755 /home/user/
$ chmod 755 /home/user/project_directory/static/
$ chmod 644 /home/user/project_directory/static/* according to the recommendations in here: nginxlibrary.com/403-forbidden-error/. Now the www-data user has execution access to the static files and my django website works fine. Give it a try.