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:
- Receiving HTTP requests from the web server
- Passing these requests to Django's URL routing system
- Taking Django's response and sending it back to the web server
- 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:
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:
- Sets the
DJANGO_SETTINGS_MODULE
environment variable to point to your project's settings - Creates an
application
callable using Django'sget_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:
pip install gunicorn
To run your Django application with Gunicorn:
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:
pip install uwsgi
To run your Django application with uWSGI:
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.
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
):
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
):
[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
):
[Unit]
Description=gunicorn socket
[Socket]
ListenStream=/path/to/your/project/myproject.sock
[Install]
WantedBy=sockets.target
Start and enable the services:
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:
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:
- You've run
python manage.py collectstatic
- Your web server is configured to serve files from your
STATIC_ROOT
- 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:
- Check if your WSGI server is running:
systemctl status gunicorn
- Check the logs:
journalctl -u gunicorn
- Verify the socket file exists and has the right permissions
Performance Issues
If your application is slow:
- Increase the number of workers in your WSGI server configuration
- Enable caching in Django
- 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:
- What WSGI is and why it's important in Django
- How Django's WSGI implementation works
- Different WSGI servers like Gunicorn and uWSGI
- How to set up a production environment with Nginx and Gunicorn
- Customizing the WSGI application for additional functionality
- 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
- Django Documentation on WSGI
- Gunicorn Documentation
- uWSGI Documentation
- WSGI Tutorial by Armin Ronacher
Exercises
- Set up a local development environment with Gunicorn running your Django application instead of the built-in development server.
- Configure Nginx on your local machine to serve a Django application through Gunicorn.
- Modify the WSGI application to log all incoming requests to a file.
- 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! :)