Django Deployment¶
Deploy your Django applications to production with confidence.
Pre-Deployment Checklist¶
Before deploying to production:
# settings.py - Production Settings
# Security
DEBUG = False
ALLOWED_HOSTS = ['yourdomain.com', 'www.yourdomain.com']
SECRET_KEY = os.environ.get('DJANGO_SECRET_KEY')
# HTTPS
SECURE_SSL_REDIRECT = True
SESSION_COOKIE_SECURE = True
CSRF_COOKIE_SECURE = True
SECURE_BROWSER_XSS_FILTER = True
SECURE_CONTENT_TYPE_NOSNIFF = True
X_FRAME_OPTIONS = 'DENY'
# HSTS
SECURE_HSTS_SECONDS = 31536000
SECURE_HSTS_INCLUDE_SUBDOMAINS = True
SECURE_HSTS_PRELOAD = True
# Static files
STATIC_ROOT = os.path.join(BASE_DIR, 'staticfiles')
STATIC_URL = '/static/'
# Media files
MEDIA_ROOT = os.path.join(BASE_DIR, 'media')
MEDIA_URL = '/media/'
Environment Variables¶
Use environment variables for sensitive data:
# settings.py
from decouple import config
SECRET_KEY = config('SECRET_KEY')
DEBUG = config('DEBUG', default=False, cast=bool)
DATABASE_URL = config('DATABASE_URL')
# .env file
SECRET_KEY=your-secret-key-here
DEBUG=False
DATABASE_URL=postgresql://user:password@localhost/dbname
Static Files¶
Collecting Static Files¶
Using WhiteNoise¶
# settings.py
MIDDLEWARE = [
'django.middleware.security.SecurityMiddleware',
'whitenoise.middleware.WhiteNoiseMiddleware', # Add this
...
]
STATICFILES_STORAGE = 'whitenoise.storage.CompressedManifestStaticFilesStorage'
Database Configuration¶
PostgreSQL¶
# settings.py
DATABASES = {
'default': {
'ENGINE': 'django.db.backends.postgresql',
'NAME': config('DB_NAME'),
'USER': config('DB_USER'),
'PASSWORD': config('DB_PASSWORD'),
'HOST': config('DB_HOST', default='localhost'),
'PORT': config('DB_PORT', default='5432'),
}
}
Using dj-database-url¶
import dj_database_url
DATABASES = {
'default': dj_database_url.config(
default=config('DATABASE_URL')
)
}
Web Servers¶
Gunicorn¶
uWSGI¶
# uwsgi.ini
[uwsgi]
module = myproject.wsgi:application
master = true
processes = 4
socket = /tmp/myproject.sock
chmod-socket = 666
vacuum = true
Nginx Configuration¶
# /etc/nginx/sites-available/myproject
server {
listen 80;
server_name yourdomain.com www.yourdomain.com;
location = /favicon.ico { access_log off; log_not_found off; }
location /static/ {
alias /path/to/your/project/staticfiles/;
}
location /media/ {
alias /path/to/your/project/media/;
}
location / {
proxy_pass http://127.0.0.1:8000;
proxy_set_header Host $host;
proxy_set_header X-Real-IP $remote_addr;
proxy_set_header X-Forwarded-For $proxy_add_x_forwarded_for;
proxy_set_header X-Forwarded-Proto $scheme;
}
}
Docker Deployment¶
# Dockerfile
FROM python:3.11-slim
ENV PYTHONUNBUFFERED=1
WORKDIR /app
COPY requirements.txt .
RUN pip install --no-cache-dir -r requirements.txt
COPY . .
RUN python manage.py collectstatic --noinput
EXPOSE 8000
CMD ["gunicorn", "myproject.wsgi:application", "--bind", "0.0.0.0:8000"]
# docker-compose.yml
version: '3.8'
services:
db:
image: postgres:15
environment:
POSTGRES_DB: mydb
POSTGRES_USER: myuser
POSTGRES_PASSWORD: mypassword
volumes:
- postgres_data:/var/lib/postgresql/data
web:
build: .
command: gunicorn myproject.wsgi:application --bind 0.0.0.0:8000
volumes:
- .:/app
- static_volume:/app/staticfiles
ports:
- "8000:8000"
env_file:
- .env
depends_on:
- db
nginx:
image: nginx:latest
volumes:
- ./nginx.conf:/etc/nginx/nginx.conf
- static_volume:/app/staticfiles
ports:
- "80:80"
depends_on:
- web
volumes:
postgres_data:
static_volume:
Platform as a Service (PaaS)¶
Heroku¶
# Install Heroku CLI and login
heroku login
# Create app
heroku create myapp
# Add PostgreSQL
heroku addons:create heroku-postgresql:hobby-dev
# Set environment variables
heroku config:set SECRET_KEY="your-secret-key"
heroku config:set DEBUG=False
# Deploy
git push heroku main
# Run migrations
heroku run python manage.py migrate
# Create superuser
heroku run python manage.py createsuperuser
Railway¶
# railway.toml
[build]
builder = "NIXPACKS"
[deploy]
startCommand = "gunicorn myproject.wsgi:application"
restartPolicyType = "ON_FAILURE"
restartPolicyMaxRetries = 10
Render¶
# render.yaml
services:
- type: web
name: myapp
env: python
buildCommand: "pip install -r requirements.txt && python manage.py collectstatic --noinput"
startCommand: "gunicorn myproject.wsgi:application"
envVars:
- key: PYTHON_VERSION
value: 3.11.0
- key: DATABASE_URL
fromDatabase:
name: myapp-db
property: connectionString
databases:
- name: myapp-db
plan: starter
SSL/TLS Certificates¶
Let's Encrypt with Certbot¶
# Install Certbot
sudo apt install certbot python3-certbot-nginx
# Obtain certificate
sudo certbot --nginx -d yourdomain.com -d www.yourdomain.com
# Auto-renewal
sudo certbot renew --dry-run
Monitoring and Logging¶
Sentry¶
# settings.py
import sentry_sdk
from sentry_sdk.integrations.django import DjangoIntegration
sentry_sdk.init(
dsn=config('SENTRY_DSN'),
integrations=[DjangoIntegration()],
traces_sample_rate=1.0,
send_default_pii=True
)
Logging Configuration¶
# settings.py
LOGGING = {
'version': 1,
'disable_existing_loggers': False,
'handlers': {
'file': {
'level': 'ERROR',
'class': 'logging.FileHandler',
'filename': '/var/log/django/error.log',
},
'console': {
'class': 'logging.StreamHandler',
},
},
'loggers': {
'django': {
'handlers': ['file', 'console'],
'level': 'ERROR',
'propagate': True,
},
},
}
Database Migrations¶
# Always backup before migrations
pg_dump mydb > backup.sql
# Run migrations
python manage.py migrate
# If something goes wrong
psql mydb < backup.sql
Performance Optimization¶
Caching¶
# settings.py
CACHES = {
'default': {
'BACKEND': 'django.core.cache.backends.redis.RedisCache',
'LOCATION': 'redis://127.0.0.1:6379/1',
}
}
Database Connection Pooling¶
DATABASES = {
'default': {
'ENGINE': 'django_db_pool.backends.postgresql',
'POOL_OPTIONS': {
'POOL_SIZE': 10,
'MAX_OVERFLOW': 10,
}
}
}
Best Practices¶
- Use environment variables for all secrets
- Set DEBUG=False in production
- Use HTTPS everywhere
- Collect static files before deployment
- Run migrations carefully
- Set up monitoring and logging
- Use a CDN for static files
- Regular backups of database
- Use a reverse proxy (Nginx)
- Keep dependencies updated
Deployment Checklist¶
- DEBUG = False
- SECRET_KEY from environment
- ALLOWED_HOSTS configured
- Database configured
- Static files collected
- Media files storage configured
- HTTPS enabled
- Security headers set
- Error monitoring (Sentry)
- Logging configured
- Backups automated
- Performance monitoring
- Load testing completed