Introduction
Moving a Django app from development to production requires coordinating multiple components: WSGI entry point, uWSGI ini, systemd service, Nginx, static files, and environment variables.
This guide provides an end-to-end deployment flow: from server prep to first deploy and update strategy. Optimized for teams choosing uWSGI over Gunicorn.
Examples target Django 5.x, Python 3.12, and Debian/Ubuntu servers.
Server Preparation
Install Python 3.12, nginx, uwsgi-plugin-python3. Create a deploy user; do not run uWSGI as root. Prepare /var/www/myproject and /run/uwsgi.
Configure PostgreSQL or your database. Set DJANGO_SECRET_KEY, DATABASE_URL, and ALLOWED_HOSTS in .env; never commit to repo.
sudo apt install python3.12-venv nginx uwsgi uwsgi-plugin-python3
sudo useradd -m -s /bin/bash deploy
sudo mkdir -p /run/uwsgi /var/log/uwsgi
sudo chown deploy:www-data /run/uwsgiDjango WSGI and Environment
myproject/wsgi.py is Django's default WSGI entry point. DJANGO_SETTINGS_MODULE=myproject.settings loads production settings.
settings/production.py has DEBUG=False, secure cookie settings, and logging config. Read .env with django-environ.
- DEBUG=False zorunlu
- ALLOWED_HOSTS domain listesi
- STATIC_ROOT collectstatic hedefi
- SECURE_PROXY_SSL_HEADER nginx için
# myproject/wsgi.py
import os
from django.core.wsgi import get_wsgi_application
os.environ.setdefault('DJANGO_SETTINGS_MODULE', 'myproject.settings.production')
application = get_wsgi_application()uWSGI ini and systemd
ini defines chdir, virtualenv, module, and socket. env = DJANGO_SETTINGS_MODULE=myproject.settings.production passes the environment variable.
systemd unit Type=notify or simple; Restart=always for automatic recovery.
[Unit]
Description=uWSGI Django myproject
After=network.target
[Service]
User=deploy
Group=www-data
ExecStart=/var/www/myproject/venv/bin/uwsgi --ini /etc/uwsgi/apps-enabled/myproject.ini
Restart=always
KillSignal=SIGQUIT
[Install]
WantedBy=multi-user.targetStatic Files and Migrate
python manage.py collectstatic --noinput gathers files to STATIC_ROOT. Nginx /static/ location aliases to this directory.
Run python manage.py migrate --noinput in deploy script. Complete migrations before app starts; order matters.
#!/bin/bash
set -e
cd /var/www/myproject
source venv/bin/activate
pip install -r requirements.txt
python manage.py migrate --noinput
python manage.py collectstatic --noinput
touch reload.touchZero-Downtime Deploy
touch-reload = /var/www/myproject/reload.touch triggers graceful reload on code update. chain-reload renews workers one by one.
Blue-green deploy can use two sockets and Nginx upstream switch; touch-reload suffices for most projects.
[uwsgi]
touch-reload = /var/www/myproject/reload.touch
chain-reload = true
lazy-apps = true
need-app = trueDeploy script'inizde migrate → collectstatic → touch-reload sırasını asla bozmayın.
Security and Hardening
Harden with uid/gid drop, harakiri, limit-as, and disable-logging=false. Open only 80/443 on firewall; restrict stats port to internal network.
Django security middleware, CSRF, HSTS, and SECURE_SSL_REDIRECT must be enabled in production.
- DEBUG kapalı
- Güçlü SECRET_KEY
- HTTPS zorunlu
- Veritabanı şifreleri .env'de
- Düzenli güvenlik güncellemeleri
Conclusion
The Django + uWSGI + systemd + Nginx stack is a proven production architecture. Reliable operations come from automated deploy scripts, touch-reload, and log monitoring.
After initial setup consider Emperor mode or containerization; but do not add complexity before the basic flow is solid.