This guide covers deploying Proyecto to a production environment with proper security, performance, and reliability configurations.
Pre-Deployment Checklist
Review all items in this checklist before deploying to production. Missing security configurations can expose your application to attacks.
Security Settings
Verify critical security settings:DEBUG = False # MUST be False
SECRET_KEY = os.environ.get('DJANGO_SECRET_KEY') # Use environment variable
ALLOWED_HOSTS = ['yourdomain.com', 'www.yourdomain.com']
Never deploy with DEBUG = True. This exposes sensitive application internals and stack traces.
Database Configuration
Use environment variables for database credentials:DATABASES = {
'default': {
'ENGINE': 'django.db.backends.postgresql_psycopg2',
'NAME': os.environ.get('DB_NAME'),
'USER': os.environ.get('DB_USER'),
'PASSWORD': os.environ.get('DB_PASSWORD'),
'HOST': os.environ.get('DB_HOST'),
'PORT': os.environ.get('DB_PORT', '5432'),
'ATOMIC_REQUESTS': True,
}
}
Static Files
Configure static file serving:STATIC_ROOT = BASE_DIR / 'staticfiles'
STATIC_URL = '/static/'
Collect static files:python manage.py collectstatic --noinput
Additional Security Headers
Add these security settings:# HTTPS/SSL
SECURE_SSL_REDIRECT = True
SESSION_COOKIE_SECURE = True
CSRF_COOKIE_SECURE = True
# HSTS
SECURE_HSTS_SECONDS = 31536000 # 1 year
SECURE_HSTS_INCLUDE_SUBDOMAINS = True
SECURE_HSTS_PRELOAD = True
# Other security
SECURE_BROWSER_XSS_FILTER = True
SECURE_CONTENT_TYPE_NOSNIFF = True
X_FRAME_OPTIONS = 'DENY'
Production Deployment Steps
Install Dependencies
Set up a Python virtual environment and install requirements:# Create virtual environment
python3 -m venv venv
source venv/bin/activate
# Install dependencies
pip install -r requirements.txt
Required packages:
- Django==3.2.18
- psycopg2==2.9.5 (PostgreSQL adapter)
- asgiref==3.4.1
- pytz==2022.7.1
- Gunicorn (for WSGI server)
Set Environment Variables
Create a .env file or set environment variables:# Security
export DJANGO_SECRET_KEY="your-secret-key-here"
export DJANGO_DEBUG="False"
export ALLOWED_HOSTS="yourdomain.com,www.yourdomain.com"
# Database
export DB_NAME="Proyecto"
export DB_USER="proyecto_user"
export DB_PASSWORD="secure_password"
export DB_HOST="localhost"
export DB_PORT="5432"
# Django settings module
export DJANGO_SETTINGS_MODULE="proyecto.settings"
Use a tool like python-dotenv to load environment variables from a .env file, but never commit this file to version control.
Prepare Database
Set up the production database:# Run migrations
python manage.py migrate
# Create superuser
python manage.py createsuperuser
# Collect static files
python manage.py collectstatic --noinput
See Database Setup for PostgreSQL configuration. Install Gunicorn
Install Gunicorn as your WSGI HTTP server: Test Gunicorn
Test that Gunicorn can serve your application:gunicorn --bind 0.0.0.0:8000 proyecto.wsgi:application
Visit http://your-server:8000 to verify it works.
WSGI Application
Proyecto’s WSGI application is defined in proyecto/wsgi.py:
import os
from django.core.wsgi import get_wsgi_application
os.environ.setdefault('DJANGO_SETTINGS_MODULE', 'proyecto.settings')
application = get_wsgi_application()
This exposes the WSGI callable as application, which is used by Gunicorn, uWSGI, and other WSGI servers.
Process Management with Systemd
Create a systemd service file to manage Gunicorn:
/etc/systemd/system/proyecto.service
[Unit]
Description=Proyecto Django Application
After=network.target
[Service]
User=www-data
Group=www-data
WorkingDirectory=/var/www/proyecto
Environment="PATH=/var/www/proyecto/venv/bin"
EnvironmentFile=/var/www/proyecto/.env
ExecStart=/var/www/proyecto/venv/bin/gunicorn \
--workers 3 \
--bind unix:/var/www/proyecto/proyecto.sock \
proyecto.wsgi:application
[Install]
WantedBy=multi-user.target
Start and enable the service:
sudo systemctl start proyecto
sudo systemctl enable proyecto
sudo systemctl status proyecto
Adjust User, Group, and WorkingDirectory to match your deployment environment.
Web Server Configuration
Nginx Configuration
Configure Nginx as a reverse proxy:
/etc/nginx/sites-available/proyecto
server {
listen 80;
server_name yourdomain.com www.yourdomain.com;
location = /favicon.ico { access_log off; log_not_found off; }
location /static/ {
alias /var/www/proyecto/staticfiles/;
}
location /media/ {
alias /var/www/proyecto/media/;
}
location / {
include proxy_params;
proxy_pass http://unix:/var/www/proyecto/proyecto.sock;
}
}
Enable the site:
sudo ln -s /etc/nginx/sites-available/proyecto /etc/nginx/sites-enabled/
sudo nginx -t
sudo systemctl restart nginx
Apache Configuration
Alternatively, use Apache with mod_wsgi:
/etc/apache2/sites-available/proyecto.conf
<VirtualHost *:80>
ServerName yourdomain.com
ServerAlias www.yourdomain.com
WSGIDaemonProcess proyecto python-path=/var/www/proyecto python-home=/var/www/proyecto/venv
WSGIProcessGroup proyecto
WSGIScriptAlias / /var/www/proyecto/proyecto/wsgi.py
Alias /static /var/www/proyecto/staticfiles
Alias /media /var/www/proyecto/media
<Directory /var/www/proyecto/proyecto>
<Files wsgi.py>
Require all granted
</Files>
</Directory>
<Directory /var/www/proyecto/staticfiles>
Require all granted
</Directory>
<Directory /var/www/proyecto/media>
Require all granted
</Directory>
</VirtualHost>
SSL/HTTPS Setup
Always use HTTPS in production to encrypt data in transit and protect user credentials.
Using Let’s Encrypt (Certbot)
Install Certbot
sudo apt install certbot python3-certbot-nginx
Obtain SSL Certificate
sudo certbot --nginx -d yourdomain.com -d www.yourdomain.com
Auto-Renewal
Certbot automatically sets up renewal. Test it:sudo certbot renew --dry-run
Update Django Settings for HTTPS
Add these settings when using HTTPS:
SECURE_SSL_REDIRECT = True
SESSION_COOKIE_SECURE = True
CSRF_COOKIE_SECURE = True
SECURE_HSTS_SECONDS = 31536000
SECURE_HSTS_INCLUDE_SUBDOMAINS = True
SECURE_HSTS_PRELOAD = True
Gunicorn Configuration
Create a Gunicorn configuration file:
/var/www/proyecto/gunicorn_config.py
import multiprocessing
# Bind to Unix socket
bind = 'unix:/var/www/proyecto/proyecto.sock'
# Worker processes
workers = multiprocessing.cpu_count() * 2 + 1
worker_class = 'sync'
worker_connections = 1000
# Timeouts
timeout = 30
keepalive = 2
# Logging
accesslog = '/var/www/proyecto/logs/gunicorn-access.log'
errorlog = '/var/www/proyecto/logs/gunicorn-error.log'
loglevel = 'info'
# Process naming
proc_name = 'proyecto'
# Security
limit_request_line = 4096
limit_request_fields = 100
limit_request_field_size = 8190
Update systemd service to use the config:
ExecStart=/var/www/proyecto/venv/bin/gunicorn \
--config /var/www/proyecto/gunicorn_config.py \
proyecto.wsgi:application
Monitoring and Logging
Application Logging
Configure Django logging in settings.py:
LOGGING = {
'version': 1,
'disable_existing_loggers': False,
'formatters': {
'verbose': {
'format': '{levelname} {asctime} {module} {message}',
'style': '{',
},
},
'handlers': {
'file': {
'level': 'INFO',
'class': 'logging.FileHandler',
'filename': '/var/www/proyecto/logs/django.log',
'formatter': 'verbose',
},
},
'root': {
'handlers': ['file'],
'level': 'INFO',
},
}
Consider these monitoring solutions:
- System metrics: Prometheus + Grafana
- Application performance: New Relic, DataDog
- Error tracking: Sentry
- Uptime monitoring: UptimeRobot, Pingdom
Health Check Endpoint
Create a simple health check view:
from django.http import JsonResponse
from django.db import connection
def health_check(request):
try:
# Check database connection
connection.ensure_connection()
return JsonResponse({'status': 'healthy'}, status=200)
except Exception as e:
return JsonResponse({'status': 'unhealthy', 'error': str(e)}, status=503)
Add to URLs:
path('health/', health_check, name='health_check'),
Database Connection Pooling
Install pgbouncer for PostgreSQL connection pooling:
sudo apt install pgbouncer
Caching
Add Redis caching:
CACHES = {
'default': {
'BACKEND': 'django_redis.cache.RedisCache',
'LOCATION': 'redis://127.0.0.1:6379/1',
'OPTIONS': {
'CLIENT_CLASS': 'django_redis.client.DefaultClient',
}
}
}
Static File Compression
Enable gzip compression in Nginx:
gzip on;
gzip_vary on;
gzip_proxied any;
gzip_comp_level 6;
gzip_types text/plain text/css text/xml text/javascript application/json application/javascript application/xml+rss;
Backup Strategy
Implement automated backups before going to production.
Database Backups
Create a backup script:
/var/www/proyecto/scripts/backup.sh
#!/bin/bash
BACKUP_DIR="/backups/proyecto"
DATE=$(date +%Y%m%d_%H%M%S)
# Create backup
pg_dump -U proyecto_user -h localhost Proyecto > "$BACKUP_DIR/db_$DATE.sql"
# Compress
gzip "$BACKUP_DIR/db_$DATE.sql"
# Keep only last 30 days
find $BACKUP_DIR -name "db_*.sql.gz" -mtime +30 -delete
Schedule with cron:
0 2 * * * /var/www/proyecto/scripts/backup.sh
Sync media files to remote storage:
rsync -avz /var/www/proyecto/media/ backup-server:/backups/proyecto/media/
Deployment Checklist
Troubleshooting
502 Bad Gateway
Check Gunicorn is running:
sudo systemctl status proyecto
journalctl -u proyecto -n 50
Static Files Not Loading
Verify collectstatic was run and web server configuration:
python manage.py collectstatic --noinput
sudo nginx -t
Database Connection Errors
Verify database credentials and connectivity:
psql -U proyecto_user -d Proyecto -h localhost
Permission Errors
Ensure proper ownership:
sudo chown -R www-data:www-data /var/www/proyecto
sudo chmod -R 755 /var/www/proyecto
Next Steps
After deployment:
- Monitor application logs for errors
- Set up automated backups
- Configure monitoring and alerting
- Perform load testing
- Document your deployment process
- Create a rollback plan
Keep a deployment checklist and update it as you refine your deployment process.