Chapter 17: Deployment
17.2 Deployment Solutions
In the previous section, we learned how to configure the Django production environment. This section will introduce several common Django deployment solutions, including the traditional deployment using Nginx + Gunicorn, cloud platform deployment, and static file CDN acceleration.
Nginx + Gunicorn
Nginx + Gunicorn is the most common deployment combination for Django applications. Nginx acts as a reverse proxy server to handle static files and load balancing, while Gunicorn serves as the WSGI server to run the Django application.
Gunicorn Configuration
First, install Gunicorn:
pip install gunicornCreate a Gunicorn configuration file:
# gunicorn.conf.py
import multiprocessing
# Server socket
bind = "127.0.0.1:8000"
backlog = 2048
# Worker processes
workers = multiprocessing.cpu_count() * 2 + 1
worker_class = "sync"
worker_connections = 1000
timeout = 30
keepalive = 2
# Restart strategy
max_requests = 1000
max_requests_jitter = 100
# Logging
loglevel = "info"
accesslog = "/var/log/gunicorn/access.log"
errorlog = "/var/log/gunicorn/error.log"
access_log_format = '%(h)s %(l)s %(u)s %(t)s "%(r)s" %(s)s %(b)s "%(f)s" "%(a)s"'
# Process naming
proc_name = "myproject"
# Server mechanics
preload_app = True
daemon = False
pidfile = "/var/run/gunicorn.pid"
user = "www-data"
group = "www-data"
# SSL (if using Gunicorn to handle HTTPS directly)
# keyfile = "/path/to/keyfile"
# certfile = "/path/to/certfile"
# Performance tuning
worker_tmp_dir = "/dev/shm"Start Gunicorn:
# Start with configuration file
gunicorn --config gunicorn.conf.py myproject.wsgi:application
# Or start directly
gunicorn myproject.wsgi:application --bind 127.0.0.1:8000 --workers 3Nginx Configuration
Install Nginx:
# Ubuntu/Debian
sudo apt update
sudo apt install nginx
# CentOS/RHEL
sudo yum install nginxCreate Nginx site configuration:
# /etc/nginx/sites-available/myproject
upstream app_server {
server 127.0.0.1:8000 fail_timeout=0;
}
server {
listen 80;
server_name yourdomain.com;
# Redirect to HTTPS (if SSL is configured)
# return 301 https://$server_name$request_uri;
client_max_body_size 10M;
# Static file handling
location /static/ {
alias /var/www/myproject/staticfiles/;
expires 1y;
add_header Cache-Control "public, immutable";
}
location /media/ {
alias /var/www/myproject/media/;
expires 30d;
add_header Cache-Control "public";
}
# Forward dynamic requests to Gunicorn
location / {
proxy_set_header X-Forwarded-For $proxy_add_x_forwarded_for;
proxy_set_header X-Forwarded-Proto $scheme;
proxy_set_header Host $http_host;
proxy_redirect off;
proxy_pass http://app_server;
}
# Security headers
add_header X-Frame-Options "SAMEORIGIN" always;
add_header X-XSS-Protection "1; mode=block" always;
add_header X-Content-Type-Options "nosniff" always;
}
# HTTPS configuration (if needed)
server {
listen 443 ssl http2;
server_name yourdomain.com;
ssl_certificate /path/to/certificate.crt;
ssl_certificate_key /path/to/private.key;
# SSL security configuration
ssl_protocols TLSv1.2 TLSv1.3;
ssl_ciphers ECDHE-RSA-AES256-GCM-SHA512:DHE-RSA-AES256-GCM-SHA512:ECDHE-RSA-AES256-GCM-SHA384:DHE-RSA-AES256-GCM-SHA384;
ssl_prefer_server_ciphers off;
# Enable HSTS
add_header Strict-Transport-Security "max-age=63072000" always;
# Other configuration same as HTTP server
client_max_body_size 10M;
location /static/ {
alias /var/www/myproject/staticfiles/;
expires 1y;
add_header Cache-Control "public, immutable";
}
location /media/ {
alias /var/www/myproject/media/;
expires 30d;
add_header Cache-Control "public";
}
location / {
proxy_set_header X-Forwarded-For $proxy_add_x_forwarded_for;
proxy_set_header X-Forwarded-Proto https;
proxy_set_header Host $http_host;
proxy_redirect off;
proxy_pass http://app_server;
}
}Enable the site and restart Nginx:
# Enable site
sudo ln -s /etc/nginx/sites-available/myproject /etc/nginx/sites-enabled/
# Test configuration
sudo nginx -t
# Restart Nginx
sudo systemctl restart nginxSystem Service Configuration
To ensure Gunicorn automatically runs at system startup, we can create a systemd service:
# /etc/systemd/system/myproject.service
[Unit]
Description=MyProject Django Application
After=network.target
[Service]
User=www-data
Group=www-data
WorkingDirectory=/var/www/myproject
ExecStart=/var/www/myproject/venv/bin/gunicorn --config gunicorn.conf.py myproject.wsgi:application
ExecReload=/bin/kill -s HUP $MAINPID
Restart=always
# Environment variables
Environment=DJANGO_ENV=production
Environment=DJANGO_SECRET_KEY=your-secret-key
Environment=DB_PASSWORD=your-db-password
[Install]
WantedBy=multi-user.targetStart and enable the service:
# Reload systemd configuration
sudo systemctl daemon-reload
# Start service
sudo systemctl start myproject
# Set to start on boot
sudo systemctl enable myproject
# Check service status
sudo systemctl status myprojectCloud Platform Deployment
Modern Django applications can also be deployed to various cloud platforms, including Heroku, AWS, Google Cloud, Azure, etc.
Heroku Deployment
- Create a Procfile:
web: gunicorn myproject.wsgi:application --log-file -- Create runtime.txt to specify Python version:
python-3.11.5- Install and configure django-heroku:
pip install django-heroku# settings/production.py
import django_heroku
# Activate Heroku configuration at the end of the file
django_heroku.settings(locals())- Deploy to Heroku:
# Install Heroku CLI and login
heroku login
# Create application
heroku create myproject
# Set environment variables
heroku config:set DJANGO_ENV=production
heroku config:set DJANGO_SECRET_KEY=your-secret-key
# Deploy code
git push heroku mainDocker Deployment
Create a Dockerfile:
# Dockerfile
FROM python:3.11-slim
# Set environment variables
ENV PYTHONDONTWRITEBYTECODE 1
ENV PYTHONUNBUFFERED 1
# Set working directory
WORKDIR /app
# Install system dependencies
RUN apt-get update \
&& apt-get install -y --no-install-recommends \
postgresql-client \
&& rm -rf /var/lib/apt/lists/*
# Copy dependency file
COPY requirements.txt /app/
# Install Python dependencies
RUN pip install --no-cache-dir -r requirements.txt
# Copy project files
COPY . /app/
# Create non-root user
RUN adduser --disabled-password --gecos '' appuser && \
chown -R appuser:appuser /app
USER appuser
# Expose port
EXPOSE 8000
# Run application
CMD ["gunicorn", "myproject.wsgi:application", "--bind", "0.0.0.0:8000"]Create docker-compose.yml:
version: '3.8'
services:
web:
build: .
ports:
- "8000:8000"
environment:
- DJANGO_ENV=production
- DJANGO_SECRET_KEY=your-secret-key
volumes:
- static_volume:/var/www/myproject/staticfiles
- media_volume:/var/www/myproject/media
depends_on:
- db
- redis
db:
image: postgres:15
environment:
- POSTGRES_DB=myproject
- POSTGRES_USER=myproject
- POSTGRES_PASSWORD=your-db-password
volumes:
- postgres_data:/var/lib/postgresql/data
redis:
image: redis:7-alpine
nginx:
image: nginx:alpine
ports:
- "80:80"
- "443:443"
volumes:
- ./nginx/conf.d:/etc/nginx/conf.d
- static_volume:/var/www/myproject/staticfiles
- media_volume:/var/www/myproject/media
depends_on:
- web
volumes:
postgres_data:
static_volume:
media_volume:Static File CDN
To improve the loading speed of static files, static files can be deployed to a CDN.
Using AWS S3 and CloudFront
- Install dependencies:
pip install django-storages boto3- Configure settings:
# settings/production.py
import os
# AWS configuration
AWS_ACCESS_KEY_ID = os.environ.get('AWS_ACCESS_KEY_ID')
AWS_SECRET_ACCESS_KEY = os.environ.get('AWS_SECRET_ACCESS_KEY')
AWS_STORAGE_BUCKET_NAME = os.environ.get('AWS_STORAGE_BUCKET_NAME')
AWS_S3_REGION_NAME = os.environ.get('AWS_S3_REGION_NAME', 'us-east-1')
AWS_S3_CUSTOM_DOMAIN = f'{AWS_STORAGE_BUCKET_NAME}.s3.amazonaws.com'
# Static file storage
STATICFILES_STORAGE = 'storages.backends.s3boto3.S3Boto3Storage'
STATIC_URL = f'https://{AWS_S3_CUSTOM_DOMAIN}/static/'
# Media file storage
DEFAULT_FILE_STORAGE = 'storages.backends.s3boto3.S3Boto3Storage'
MEDIA_URL = f'https://{AWS_S3_CUSTOM_DOMAIN}/media/'
# S3 settings
AWS_S3_FILE_OVERWRITE = False
AWS_DEFAULT_ACL = None
AWS_S3_VERIFY = True- Collect static files:
python manage.py collectstatic --noinputUsing Alibaba Cloud OSS
- Install dependencies:
pip install django-oss-storage- Configure settings:
# settings/production.py
import os
# Alibaba Cloud OSS configuration
OSS_ACCESS_KEY_ID = os.environ.get('OSS_ACCESS_KEY_ID')
OSS_ACCESS_KEY_SECRET = os.environ.get('OSS_ACCESS_KEY_SECRET')
OSS_BUCKET_NAME = os.environ.get('OSS_BUCKET_NAME')
OSS_ENDPOINT = os.environ.get('OSS_ENDPOINT')
# Static file storage
STATICFILES_STORAGE = 'django_oss_storage.backends.OssStaticStorage'
STATIC_URL = f'https://{OSS_BUCKET_NAME}.{OSS_ENDPOINT}/static/'
# Media file storage
DEFAULT_FILE_STORAGE = 'django_oss_storage.backends.OssMediaStorage'
MEDIA_URL = f'https://{OSS_BUCKET_NAME}.{OSS_ENDPOINT}/media/'Using Tencent Cloud COS
- Install dependencies:
pip install qcloud_cos django-cos-storage- Configure settings:
# settings/production.py
import os
# Tencent Cloud COS configuration
COS_SECRET_ID = os.environ.get('COS_SECRET_ID')
COS_SECRET_KEY = os.environ.get('COS_SECRET_KEY')
COS_REGION = os.environ.get('COS_REGION')
COS_BUCKET = os.environ.get('COS_BUCKET')
# Static file storage
STATICFILES_STORAGE = 'django_cos_storage.backends.CosStaticStorage'
STATIC_URL = f'https://{COS_BUCKET}.cos.{COS_REGION}.myqcloud.com/static/'
# Media file storage
DEFAULT_FILE_STORAGE = 'django_cos_storage.backends.CosMediaStorage'
MEDIA_URL = f'https://{COS_BUCKET}.cos.{COS_REGION}.myqcloud.com/media/'Monitoring and Maintenance
After deployment, application monitoring and maintenance also need to be considered.
Health Check Endpoint
Create a health check view:
# views.py
from django.http import JsonResponse
from django.db import connections
from django.db.utils import OperationalError
import redis
import os
def health_check(request):
"""Health check endpoint"""
health_status = {
'status': 'healthy',
'database': check_database(),
'redis': check_redis(),
'disk_space': check_disk_space(),
}
# Return error status if any component is unhealthy
if not all(health_status.values()):
health_status['status'] = 'unhealthy'
return JsonResponse(health_status, status=503)
return JsonResponse(health_status)
def check_database():
"""Check database connection"""
db_conn = connections['default']
try:
c = db_conn.cursor()
return True
except OperationalError:
return False
def check_redis():
"""Check Redis connection"""
try:
redis_client = redis.Redis(
host=os.environ.get('REDIS_HOST', 'localhost'),
port=os.environ.get('REDIS_PORT', 6379),
db=0
)
redis_client.ping()
return True
except:
return False
def check_disk_space():
"""Check disk space"""
try:
stat = os.statvfs('/')
free_bytes = stat.f_bavail * stat.f_frsize
# Consider unhealthy if free space is less than 1GB
return free_bytes > 1024 * 1024 * 1024
except:
return FalseConfigure URL:
# urls.py
from django.urls import path
from . import views
urlpatterns = [
path('health/', views.health_check, name='health_check'),
# Other URLs...
]Automated Deployment Script
Create a deployment script:
#!/bin/bash
# deploy.sh
set -e # Exit on error
echo "Starting deployment..."
# Pull latest code
git pull origin main
# Activate virtual environment
source venv/bin/activate
# Install dependencies
pip install -r requirements.txt
# Run migrations
python manage.py migrate --noinput
# Collect static files
python manage.py collectstatic --noinput
# Restart services
sudo systemctl restart myproject
sudo systemctl restart nginx
echo "Deployment completed!"Backup Strategy
Create a database backup script:
#!/bin/bash
# backup.sh
# Database backup
DATE=$(date +"%Y%m%d_%H%M%S")
BACKUP_DIR="/var/backups/myproject"
mkdir -p $BACKUP_DIR
# PostgreSQL backup
pg_dump myproject > $BACKUP_DIR/db_backup_$DATE.sql
# Compress backup
gzip $BACKUP_DIR/db_backup_$DATE.sql
# Delete backups older than 7 days
find $BACKUP_DIR -name "db_backup_*.sql.gz" -mtime +7 -delete
# Media file backup (if stored locally)
tar -czf $BACKUP_DIR/media_backup_$DATE.tar.gz /var/www/myproject/media/
# Delete media file backups older than 7 days
find $BACKUP_DIR -name "media_backup_*.tar.gz" -mtime +7 -deleteSummary
Key points of Django deployment solutions:
- ✅ Nginx + Gunicorn is the classic combination for traditional deployment
- ✅ Cloud platform deployment provides more convenient deployment methods
- ✅ Use CDN to accelerate static file access
- ✅ Implement monitoring and health checks to ensure application stability
- ✅ Establish automated deployment and backup strategies
The choice of deployment solution depends on project requirements, team skills, and budget considerations. Regardless of which solution is chosen, the security, stability, and scalability of the application must be ensured.
Through this chapter, you have mastered the complete process of Django production environment configuration and deployment. In actual projects, it is recommended to adjust the configuration according to specific situations and continuously optimize the deployment process.
🎉 Django In-depth Series Course
Congratulations on completing the entire Django In-depth Series Course! Through this course, you have mastered:
Core Skills
- ✅ Django MTV architecture and project structure
- ✅ Model design and database operations
- ✅ View development and URL routing
- ✅ Template system and form processing
- ✅ User authentication and permission management
Advanced Features
- ✅ Admin backend customization
- ✅ RESTful API development
- ✅ Test-driven development
- ✅ Performance optimization techniques
- ✅ Production environment deployment
Practical Project Experience
- ✅ Complete blog system development
- ✅ Front-end and back-end separation architecture
- ✅ Continuous integration and automated deployment
- ✅ Monitoring and maintenance strategies
Next Steps
- Practice Projects: Try developing a complete personal project
- Advanced Learning: Explore advanced features like Django Channels and Celery
- Community Participation: Join the Django community and participate in open source projects
- Continuous Learning: Follow the latest Django versions and best practices
Thank you for learning this course! Wishing you success in your Django development journey!