Django Gunicorn
Introduction
When deploying a Django application to production, you need something more powerful and robust than Django's built-in development server. This is where Gunicorn (Green Unicorn) comes in. Gunicorn is a Python Web Server Gateway Interface (WSGI) HTTP server that acts as an intermediary between your Django application and the internet or a web server like Nginx or Apache.
In this tutorial, you'll learn:
- What Gunicorn is and why it's essential for Django deployments
- How to install and configure Gunicorn
- How to run your Django application with Gunicorn
- Best practices for production deployments
- How to integrate Gunicorn with Nginx for enhanced performance
What is Gunicorn and Why Use It?
Understanding WSGI
Before diving into Gunicorn, it's important to understand WSGI (Web Server Gateway Interface). WSGI is a specification that describes how a web server communicates with web applications. It's a way for server and application to speak to each other using a common interface.
Django's built-in development server is great for testing but not designed for production because:
- It's single-threaded and can't handle multiple requests efficiently
- It hasn't been security audited
- It doesn't scale well under heavy traffic
Enter Gunicorn
Gunicorn is a pre-fork worker model WSGI server. This means:
- It creates multiple worker processes to handle requests
- It's designed for production environments
- It's fast, light on server resources, and relatively simple to configure
- It integrates well with various web servers like Nginx or Apache
Installing Gunicorn
Let's start by installing Gunicorn in your Django project's environment:
pip install gunicorn
To keep track of your dependencies, add it to your requirements.txt
file:
pip freeze > requirements.txt
Basic Usage with Django
Testing Gunicorn Locally
Before deploying to production, you can test Gunicorn locally to ensure it works properly with your Django application:
gunicorn yourproject.wsgi:application
Replace yourproject
with your actual Django project name.
By default, Gunicorn starts on port 8000. You can access your application at http://localhost:8000
.
Common Command Options
You can customize Gunicorn's behavior with various command-line options:
gunicorn --workers=3 --bind=0.0.0.0:8000 yourproject.wsgi:application
This command:
- Starts 3 worker processes (
--workers=3
) - Binds to all network interfaces on port 8000 (
--bind=0.0.0.0:8000
) - Uses your project's WSGI application
Configuration File
For production, it's better to use a configuration file rather than command-line options. Create a file named gunicorn_config.py
in your project directory:
# gunicorn_config.py
# Server socket
bind = "0.0.0.0:8000"
# Worker processes
workers = 3
worker_class = "sync"
worker_connections = 1000
timeout = 30
# Logging
loglevel = "info"
accesslog = "/var/log/gunicorn/access.log"
errorlog = "/var/log/gunicorn/error.log"
Then run Gunicorn with the config file:
gunicorn -c gunicorn_config.py yourproject.wsgi:application
Determining the Number of Workers
The number of workers depends on your server resources. A good rule of thumb is:
workers = (2 * number_of_cpu_cores) + 1
For example, on a dual-core machine:
# (2 * 2) + 1 = 5 workers
workers = 5
Running Gunicorn in Production
For production deployments, you'll want Gunicorn to run as a background service that starts automatically and restarts if it crashes.
Using Systemd (Recommended for Linux servers)
Create a systemd service file:
sudo nano /etc/systemd/system/gunicorn.service
Add the following content, adjusting paths and user as needed:
[Unit]
Description=gunicorn daemon for Django application
After=network.target
[Service]
User=www-data
Group=www-data
WorkingDirectory=/path/to/your/django/project
ExecStart=/path/to/virtualenv/bin/gunicorn \
--access-logfile - \
--workers 3 \
--bind unix:/path/to/your/django/project/gunicorn.sock \
yourproject.wsgi:application
[Install]
WantedBy=multi-user.target
Start and enable the service:
sudo systemctl start gunicorn
sudo systemctl enable gunicorn
Check the status to ensure it's running correctly:
sudo systemctl status gunicorn
Using a Unix Socket
Notice in the systemd example we used a Unix socket (unix:/path/to/your/django/project/gunicorn.sock
) rather than an IP address and port. This is more efficient when Gunicorn is on the same server as your web server (Nginx/Apache).
Integrating with Nginx
Gunicorn is excellent at running Python applications, but it's not designed to serve static files or handle SSL. This is where Nginx comes in—it acts as a reverse proxy, handling client requests and forwarding them to Gunicorn.
Create a Nginx configuration file:
server {
listen 80;
server_name example.com www.example.com;
location /static/ {
root /path/to/your/django/project;
}
location /media/ {
root /path/to/your/django/project;
}
location / {
proxy_pass http://unix:/path/to/your/django/project/gunicorn.sock;
proxy_set_header Host $host;
proxy_set_header X-Real-IP $remote_addr;
}
}
This configuration:
- Serves static and media files directly through Nginx
- Forwards other requests to Gunicorn via the Unix socket
- Passes important headers for proper request handling
After creating the configuration, enable it and restart Nginx:
sudo ln -s /etc/nginx/sites-available/yourproject /etc/nginx/sites-enabled
sudo nginx -t # Test the configuration
sudo systemctl restart nginx
Best Practices
1. Always Run Behind a Reverse Proxy
Always place Gunicorn behind a web server like Nginx or Apache. This setup provides:
- Better static file handling
- Security benefits
- Load balancing
- SSL termination
2. Worker Timeouts
Set appropriate timeouts to prevent hanging processes:
# In gunicorn_config.py
timeout = 30 # seconds
3. Keep-Alive Settings
For better performance with long-lived connections:
# In gunicorn_config.py
keepalive = 2 # seconds
4. Worker Class Selection
Gunicorn supports different worker types:
sync
(default): Standard synchronous workerseventlet
: For async I/O operationsgevent
: Another async option, often with better performance
# In gunicorn_config.py
worker_class = "gevent"
Note: To use eventlet
or gevent
, you'll need to install these packages:
pip install gevent # or eventlet
5. Health Checks
Implement regular health checks for your Gunicorn workers:
# In gunicorn_config.py
check_client_connection = True
Troubleshooting Common Issues
1. Gunicorn Not Starting
Check for syntax errors in your Django code or in the Gunicorn configuration:
python manage.py check
2. Connection Refused Errors
If you get "Connection refused" errors:
- Ensure Gunicorn is running (
systemctl status gunicorn
) - Verify the socket or port configuration is correct
- Check firewall settings
3. Permission Issues
If you encounter permission errors with the socket:
sudo chown www-data:www-data /path/to/your/django/project/gunicorn.sock
sudo chmod 660 /path/to/your/django/project/gunicorn.sock
4. Viewing Logs
Always check the logs when troubleshooting:
sudo journalctl -u gunicorn # For systemd logs
tail -f /var/log/gunicorn/error.log # If you've configured custom logs
Real-World Example: Complete Deployment Flow
Let's put everything together in a realistic deployment scenario:
-
Prepare your Django project:
bash# Make sure DEBUG is False
# Configure static files
python manage.py collectstatic -
Install and configure Gunicorn:
bashpip install gunicorn
# Create gunicorn_config.py (as shown earlier) -
Set up systemd service:
bash# Create and enable gunicorn.service (as shown earlier)
-
Configure Nginx:
bash# Create and enable Nginx site config (as shown earlier)
-
Secure with SSL (optional but recommended):
bash# Install certbot
sudo apt install certbot python3-certbot-nginx
# Obtain and configure SSL certificate
sudo certbot --nginx -d example.com -d www.example.com -
Start everything up:
bashsudo systemctl start gunicorn
sudo systemctl enable gunicorn
sudo systemctl restart nginx
Summary
In this guide, we've covered:
- What Gunicorn is and why it's important for Django deployments
- How to install and configure Gunicorn for your Django application
- Best practices for production deployments
- How to integrate Gunicorn with Nginx
- Troubleshooting common issues
Gunicorn is an essential tool in the Django deployment toolkit. When properly configured and paired with a web server like Nginx, it provides a robust, efficient, and scalable solution for serving your Django applications in production environments.
Additional Resources
Exercises
- Basic Setup: Deploy a simple Django application using Gunicorn locally and test its performance.
- Configuration Practice: Create a custom Gunicorn configuration file that optimizes for a server with 4 CPU cores.
- Systemd Integration: Create a systemd service file for your Gunicorn application and test starting/stopping the service.
- Nginx Integration: Configure Nginx as a reverse proxy for your Gunicorn server, including proper static file handling.
- Performance Testing: Use a tool like Apache Bench or wrk to compare the performance of the Django development server versus Gunicorn with different worker configurations.
With Gunicorn in your deployment arsenal, you're well-equipped to run Django applications that can handle real-world traffic efficiently and reliably.
If you spot any mistakes on this website, please let me know at [email protected]. I’d greatly appreciate your feedback! :)