Skip to main content

Django WSGI

Introduction

When deploying a Django application to a production environment, you need a way for the web server (like Nginx or Apache) to communicate with your Django application. This is where WSGI comes in.

WSGI, which stands for Web Server Gateway Interface, is a specification that describes how a web server communicates with web applications. It's essentially a bridge between the web server and your Django application.

In this tutorial, you'll learn:

  • What WSGI is and why it's important
  • How Django implements WSGI
  • Setting up a WSGI server for your Django application
  • Configuring WSGI for production deployment

Understanding WSGI

What is WSGI?

WSGI (pronounced "whiskey") is a Python standard defined in PEP 3333. It provides a standard interface between web servers and Python web applications or frameworks.

Before WSGI, each Python web framework had to implement their own way to interact with web servers, making deployment complex. WSGI solved this by creating a unified approach.

WSGI's Role in Django

In a Django application, the WSGI interface is responsible for:

  1. Receiving HTTP requests from the web server
  2. Passing these requests to Django's URL routing system
  3. Taking Django's response and sending it back to the web server
  4. Handling multiple requests concurrently (depending on the WSGI server)

Django's WSGI Implementation

When you create a new Django project using django-admin startproject, a file called wsgi.py is automatically generated in your project directory. Let's look at its default content:

python
import os

from django.core.wsgi import get_wsgi_application

os.environ.setdefault('DJANGO_SETTINGS_MODULE', 'myproject.settings')

application = get_wsgi_application()

This file does a few important things:

  1. Sets the DJANGO_SETTINGS_MODULE environment variable to point to your project's settings
  2. Creates an application callable using Django's get_wsgi_application() function

The application callable is what WSGI servers use to communicate with your Django application.

Running Django with WSGI Servers

In development, you typically use Django's built-in development server with python manage.py runserver. However, this server is not suitable for production. Instead, you need a dedicated WSGI server.

Common WSGI Servers for Django

Here are some popular WSGI servers you can use with Django:

1. Gunicorn

Gunicorn (Green Unicorn) is a popular WSGI server for Django applications.

To install Gunicorn:

bash
pip install gunicorn

To run your Django application with Gunicorn:

bash
gunicorn myproject.wsgi:application

This command tells Gunicorn to look for the application callable in myproject.wsgi.

2. uWSGI

uWSGI is another powerful WSGI server with many features.

To install uWSGI:

bash
pip install uwsgi

To run your Django application with uWSGI:

bash
uwsgi --http :8000 --module myproject.wsgi

3. Daphne (for ASGI)

For modern Django applications that use asynchronous features, you might want to use ASGI (Asynchronous Server Gateway Interface) instead of WSGI. Daphne is a popular ASGI server.

bash
pip install daphne
daphne myproject.asgi:application

Production Setup with WSGI

In a real production environment, you typically have a setup like:

Client -> Web Server (Nginx/Apache) -> WSGI Server (Gunicorn/uWSGI) -> Django Application

Here's how to configure this setup with Nginx and Gunicorn:

Nginx Configuration

Create an Nginx configuration file (e.g., /etc/nginx/sites-available/myproject):

nginx
server {
listen 80;
server_name example.com;

location = /favicon.ico { access_log off; log_not_found off; }

location /static/ {
root /path/to/your/project;
}

location / {
proxy_pass http://unix:/path/to/your/project/myproject.sock;
proxy_set_header Host $host;
proxy_set_header X-Real-IP $remote_addr;
}
}

Gunicorn Configuration

Create a systemd service file (e.g., /etc/systemd/system/gunicorn.service):

ini
[Unit]
Description=gunicorn daemon
Requires=gunicorn.socket
After=network.target

[Service]
User=www-data
Group=www-data
WorkingDirectory=/path/to/your/project
ExecStart=/path/to/venv/bin/gunicorn \
--access-logfile - \
--workers 3 \
--bind unix:/path/to/your/project/myproject.sock \
myproject.wsgi:application

[Install]
WantedBy=multi-user.target

Create a socket file (e.g., /etc/systemd/system/gunicorn.socket):

ini
[Unit]
Description=gunicorn socket

[Socket]
ListenStream=/path/to/your/project/myproject.sock

[Install]
WantedBy=sockets.target

Start and enable the services:

bash
sudo systemctl start gunicorn.socket
sudo systemctl enable gunicorn.socket
sudo systemctl restart nginx

Customizing the WSGI Application

Sometimes you may need to modify your WSGI application, for example, to add middleware or configure logging. You can do this in your wsgi.py file:

python
import os
import logging

from django.core.wsgi import get_wsgi_application

# Configure logging
logging.basicConfig(
level=logging.INFO,
format='%(asctime)s - %(name)s - %(levelname)s - %(message)s',
filename='/var/log/django/wsgi.log',
)

# Set up environment
os.environ.setdefault('DJANGO_SETTINGS_MODULE', 'myproject.settings')

# Get the WSGI application
application = get_wsgi_application()

# Add custom middleware
class CustomHeaderMiddleware:
def __init__(self, app):
self.app = app

def __call__(self, environ, start_response):
def custom_start_response(status, headers, exc_info=None):
# Add a custom header
headers.append(('X-Powered-By', 'Django'))
return start_response(status, headers, exc_info)

return self.app(environ, custom_start_response)

# Apply the middleware
application = CustomHeaderMiddleware(application)

Common Issues and Solutions

Static Files Not Loading

If your static files aren't loading, ensure:

  1. You've run python manage.py collectstatic
  2. Your web server is configured to serve files from your STATIC_ROOT
  3. The file permissions allow the web server to read the static files

502 Bad Gateway Errors

This often means that Gunicorn or uWSGI is not running or is misconfigured:

  1. Check if your WSGI server is running: systemctl status gunicorn
  2. Check the logs: journalctl -u gunicorn
  3. Verify the socket file exists and has the right permissions

Performance Issues

If your application is slow:

  1. Increase the number of workers in your WSGI server configuration
  2. Enable caching in Django
  3. Use a CDN for static files

Summary

WSGI is a crucial component in Django deployment that allows your application to communicate with web servers. In this tutorial, you learned:

  1. What WSGI is and why it's important in Django
  2. How Django's WSGI implementation works
  3. Different WSGI servers like Gunicorn and uWSGI
  4. How to set up a production environment with Nginx and Gunicorn
  5. Customizing the WSGI application for additional functionality
  6. Common issues and their solutions

By understanding WSGI, you now have the knowledge to properly deploy your Django applications in a production environment.

Additional Resources

Exercises

  1. Set up a local development environment with Gunicorn running your Django application instead of the built-in development server.
  2. Configure Nginx on your local machine to serve a Django application through Gunicorn.
  3. Modify the WSGI application to log all incoming requests to a file.
  4. Research the differences between WSGI and ASGI, and determine when you might want to use ASGI instead.


If you spot any mistakes on this website, please let me know at [email protected]. I’d greatly appreciate your feedback! :)