Nginx configuration for Django

Django is a powerful framework for building websites. To run a production website, usually an application server is used. So nginx will do two basic things:

  • Serve your Django application from the application server port to the web port (Reverse Proxy)
  • Serve static and media files

The application server used in this example is gunicorn, the application server chosen by Instagram of the earlier days, but it can be anything running on port 9999. Change port number as required in the example.

The following nginx conf was adapted from this, with some additions and it contains:

  • a commented non www to www website redirect
  • gzip for javascript, json, css and proxy routes
  • media files with etag (1 year)
  • static files with etag (1 minute)
  • an host-based favicon distributor (reusable as is)
  • a commented basic auth to make a website private
  • reverse proxy to gunicorn
  • a simple block for a common type of malicious activity

It works fine with Django 1 and 2.

# Howto:
# uncomment for redirect
# server {
#    # redirect WITH www from and
#    listen 80;
#    server_name;
#    return 301$request_uri;
# }

server {
    listen	80;
    # the domain name it will serve for
    charset     utf-8;

    # max upload size
    client_max_body_size 75M;

    # enable gzip for proxy requests
    gzip on;
    gzip_proxied any;
    gzip_vary on;
    gzip_http_version 1.1;
    gzip_types application/javascript application/json text/css text/xml;
    gzip_comp_level 4;

    # @see

    # Django media
    location /media  {
        etag on;
        expires 365d;
        alias /path/to/media_root;  # your Django project's media files - amend as required

    location /static {
        etag on;
        expires 1m;
        alias /path/to/static_root; # your Django project's static files - amend as required

    location /favicon.ico {
        # all favicons inside /path/to/favicons/ this directory
        # notation:
       alias /path/to/favicons/$host.ico;

    location / {
        # an HTTP header important enough to have its own Wikipedia entry:
        proxy_set_header X-Forwarded-For $proxy_add_x_forwarded_for;

        # enable this if and only if you use HTTPS, this helps Rack
        # set the proper protocol for doing redirects:
        # proxy_set_header X-Forwarded-Proto https;

        # pass the Host: header from the client right along so redirects
        # can be set properly within the Rack application
        proxy_set_header Host $http_host;

        # we don't want nginx trying to do something clever with
        # redirects, we set the Host: header above already.
        proxy_redirect off;

        # set "proxy_buffering off" *only* for Rainbows! when doing
        # Comet/long-poll stuff.  It's also safe to set if you're
        # using only serving fast clients with Unicorn + nginx.
        # Otherwise you _want_ nginx to buffer responses to slow
        # clients, really.
        # proxy_buffering off;

        # Uncomment for maintenance
        ### auth_basic "Insert password here";
        ### auth_basic_user_file /path/to/.htpasswd;

        proxy_connect_timeout       30000;
        proxy_send_timeout          30000;
        proxy_read_timeout          30000;
        send_timeout                30000;

        # @see and
        if ($http_user_agent ~ "libwww-perl") {
          return 403;

        # Try to serve static files from nginx, no point in making an
        # *application* server like Unicorn/Rainbows! serve static files.
        if (!-f $request_filename) {
            proxy_pass http://localhost:9999;

Run nginx -t to check and then systemctl reload nginx to apply.

This is a http version, to configure the website for https follow this howto.

%d bloggers like this: