The default Django development server operates on a single thread, handling requests sequentially. This means a second request must wait for the first to complete before processing begins, leading to blocking behavior unsuitable for production workloads.
To achieve high concurrency, a common approach involves deploying Django with uWSGI as the application server and Nginx as a reverse proxy. Nginx excels at managing a high volume of concurrent connections, particularly for static content, due to its efficient event-driven architecture.
Prerequisites
Verify the operating system and Django version.
$ cat /etc/os-release
$ python -m django --version
Installing and Testing uWSGI
Install uWSGI using pip.
$ pip install uwsgi
Create a simple WSGI application file to verify uWSGI functionality.
simple_app.py
def wsgi_handler(environ, start_fn):
start_fn('200 OK', [('Content-Type', 'text/plain')])
return [b'Test response from uWSGI.']
Start a uWSGI server with the test application.
$ uwsgi --http-socket :8080 --wsgi-file simple_app.py
Check if the server is running and accesible.
$ curl http://localhost:8080
Configuring uWSGI for a Django Project
For a Django project, it's better to use a configuration file. Navigate to your project's root directory.
django_project/uwsgi_config.ini
[uwsgi]
# Use a socket for Nginx communication
socket = 127.0.0.1:9001
# Alternatively, use HTTP for direct access during testing
# http = :9090
# Project directory
chdir = /path/to/your/django_project
# Path to the WSGI module
module = project_name.wsgi:application
# Process and thread counts
processes = 5
threads = 3
# Master process
master = true
# Socket permissions (optional for Unix socket)
# chmod-socket = 664
# Logging
logto = /var/log/uwsgi_app.log
# Reload on file changes (development)
# touch-reload = /path/to/your/django_project/reload.trigger
# Clear environment on exit
vacuum = true
Start uWSGI using this configuration.
$ uwsgi --ini uwsgi_config.ini
Installing Nginx
Install Nginx using your system's package manager.
# For CentOS/RHEL
$ yum install epel-release
$ yum install nginx
# For Ubuntu/Debian
$ apt-get update
$ apt-get install nginx
Configuring Nginx as a Reverse Proxy
Create an Nginx server block configuration for the Django application.
/etc/nginx/conf.d/django_app.conf
upstream django_backend {
server 127.0.0.1:9001;
# For load balancing across multiple uWSGI instances:
# server 127.0.0.1:9002;
# server 127.0.0.1:9003;
}
server {
listen 80;
server_name your_domain.com www.your_domain.com;
client_max_body_size 100M;
# Serve static files directly via Nginx
location /static/ {
alias /path/to/your/django_project/static_root/;
expires 30d;
access_log off;
}
# Serve media files
location /media/ {
alias /path/to/your/django_project/media/;
expires 30d;
access_log off;
}
# Proxy all other requests to uWSGI
location / {
include uwsgi_params;
uwsgi_pass django_backend;
uwsgi_read_timeout 300;
proxy_set_header X-Forwarded-For $proxy_add_x_forwarded_for;
proxy_set_header Host $host;
proxy_redirect off;
}
}
Test the Nginx configuraton and restart the service.
$ nginx -t
$ systemctl restart nginx
Managing Static Files for Production
Django's development server serves static files, but in production, Nginx should handle them. Configure Django to collect all static files into a single directory.
In your project's settings.py:
STATIC_URL = '/static/'
STATIC_ROOT = BASE_DIR / 'static_root'
Run the collectstatic management command.
$ python manage.py collectstatic
Ensure the Nginx configuration's location /static/ block points to this STATIC_ROOT directory.
Verifying the Setup
Access your Django application via the server's IP address or domain name. The combined uWSGI (with multiple processes/threads) and Nginx setup will now handle concurrent requests efficiently, eliminating the blocking behavior of the default server.