Overview
SASCOP BME SubTec is a Django application designed to be deployed on multiple platforms including AWS, Vercel, and traditional WSGI servers. This guide covers deployment strategies, requirements, and best practices.
Deployment Options
The application supports several deployment methods:
WSGI Server Deploy using Gunicorn behind Nginx or Apache
Traditional deployment
Full control over infrastructure
Recommended for AWS EC2, DigitalOcean, etc.
Vercel Serverless deployment on Vercel
Zero configuration
Automatic scaling
Built-in CI/CD
Docker Containerized deployment
Consistent environments
Easy scaling
Works with Kubernetes, ECS, etc.
Platform as a Service Deploy to Heroku, Railway, or Render
Managed infrastructure
Simple deployment process
Automatic backups
WSGI Application
The application provides a WSGI entry point in bme_subtec/wsgi.py:1-8:
import os
from django.core.wsgi import get_wsgi_application
os.environ.setdefault( 'DJANGO_SETTINGS_MODULE' , 'bme_subtec.settings' )
application = get_wsgi_application()
app = application
The app variable is used by some platforms like Vercel that expect this naming convention.
Production Server
The application uses Gunicorn as its WSGI HTTP server:
Running with Gunicorn
Basic Command
gunicorn bme_subtec.wsgi:application
Production Configuration
gunicorn bme_subtec.wsgi:application \
--bind 0.0.0.0:8000 \
--workers 4 \
--timeout 120 \
--access-logfile - \
--error-logfile -
Using Gunicorn Config File
Create gunicorn_config.py: import multiprocessing
# Server socket
bind = "0.0.0.0:8000"
backlog = 2048
# Worker processes
workers = multiprocessing.cpu_count() * 2 + 1
worker_class = "sync"
worker_connections = 1000
timeout = 120
keepalive = 2
# Logging
accesslog = "-"
errorlog = "-"
loglevel = "info"
# Process naming
proc_name = "sascop_bme_subtec"
# Server mechanics
daemon = False
pidfile = None
user = None
group = None
tmp_upload_dir = None
Run with config: gunicorn -c gunicorn_config.py bme_subtec.wsgi:application
Static Files
The application uses WhiteNoise for serving static files in production:
MIDDLEWARE = [
'django.middleware.security.SecurityMiddleware' ,
'whitenoise.middleware.WhiteNoiseMiddleware' , # Must be after SecurityMiddleware
# ...
]
STATIC_URL = '/static/'
STATIC_ROOT = BASE_DIR / 'staticfiles'
STATICFILES_DIRS = [ BASE_DIR / 'operaciones' / 'static' ,]
Collecting Static Files
Before deployment, collect all static files:
python manage.py collectstatic --noinput
WhiteNoise serves static files directly from the Django app, eliminating the need for Nginx or Apache to serve static content.
Optional: Enable Compression
For better performance, enable WhiteNoise compression:
STATICFILES_STORAGE = 'whitenoise.storage.CompressedManifestStaticFilesStorage'
Database Considerations
Production Database
The application uses PostgreSQL with SSL in production:
DATABASES = {
'default' : {
'ENGINE' : 'django.db.backends.postgresql' ,
'NAME' : os.environ.get( 'RDS_DB_NAME' , 'postgres' ),
'USER' : os.environ.get( 'RDS_USERNAME' , 'postgres' ),
'PASSWORD' : os.environ.get( 'RDS_PASSWORD' , '' ),
'HOST' : os.environ.get( 'RDS_HOSTNAME' , 'localhost' ),
'PORT' : os.environ.get( 'RDS_PORT' , '5432' ),
'OPTIONS' : {
'sslmode' : 'require' ,
}
}
}
Database Migrations
Run migrations on production database:
python manage.py migrate --noinput
See Database Migrations for detailed information.
Environment Variables
Critical environment variables for production:
# Django Core
SECRET_KEY = your-production-secret-key-here
DEBUG = False
ALLOWED_HOSTS = yourdomain.com,www.yourdomain.com
# Database
RDS_DB_NAME = production_db
RDS_USERNAME = db_user
RDS_PASSWORD = secure_password
RDS_HOSTNAME = db.example.com
RDS_PORT = 5432
# Email
EMAIL_HOST = smtp.sendgrid.net
EMAIL_PORT = 587
EMAIL_HOST_USER = apikey
EMAIL_HOST_PASSWORD = your-sendgrid-api-key
DEFAULT_FROM_EMAIL = SASCOP <[email protected] >
Critical Security Settings:
Set DEBUG=False in production
Use a strong, unique SECRET_KEY
Configure ALLOWED_HOSTS properly
Never commit .env files to version control
See Environment Variables for complete reference.
Security Checklist
DEBUG Mode
Ensure DEBUG=False in production: DEBUG = os.getenv( 'DEBUG' , 'True' ) == 'True'
Set environment variable: DEBUG=False
Secret Key
Generate a strong secret key: python -c 'from django.core.management.utils import get_random_secret_key; print(get_random_secret_key())'
Set in environment: SECRET_KEY = your-generated-key-here
Allowed Hosts
Configure allowed hosts: ALLOWED_HOSTS = os.getenv( 'ALLOWED_HOSTS' , '' ).split( ',' )
Set environment: ALLOWED_HOSTS = yourdomain.com,www.yourdomain.com
HTTPS Configuration
Enable HTTPS security settings: 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
Database SSL
Ensure SSL is enabled for database connections: 'OPTIONS' : {
'sslmode' : 'require' ,
}
Deployment Workflow
Prepare Code
git checkout main
git pull origin main
Install Dependencies
pip install -r requirements.txt
Set Environment Variables
Configure all required environment variables in your deployment platform.
Collect Static Files
python manage.py collectstatic --noinput
Run Migrations
python manage.py migrate --noinput
Create Superuser (First Time Only)
python manage.py createsuperuser --noinput \
--username admin \
--email [email protected]
Start Application
gunicorn bme_subtec.wsgi:application --bind 0.0.0.0:8000 --workers 4
Build Script
The application includes a build_files.sh script for deployment automation:
#!/bin/bash
# Currently empty - add your build commands here
# Example build steps:
# pip install -r requirements.txt
# python manage.py collectstatic --noinput
# python manage.py migrate --noinput
Make it executable:
Monitoring and Logging
Application Logging
Configure Django logging for production:
LOGGING = {
'version' : 1 ,
'disable_existing_loggers' : False ,
'formatters' : {
'verbose' : {
'format' : ' {levelname} {asctime} {module} {message} ' ,
'style' : '{' ,
},
},
'handlers' : {
'console' : {
'class' : 'logging.StreamHandler' ,
'formatter' : 'verbose' ,
},
'file' : {
'class' : 'logging.FileHandler' ,
'filename' : '/var/log/sascop/django.log' ,
'formatter' : 'verbose' ,
},
},
'root' : {
'handlers' : [ 'console' , 'file' ],
'level' : 'INFO' ,
},
'loggers' : {
'django' : {
'handlers' : [ 'console' , 'file' ],
'level' : 'INFO' ,
'propagate' : False ,
},
},
}
Health Check Endpoint
Create a health check endpoint for monitoring:
from django.http import JsonResponse
from django.db import connection
def health_check ( request ):
try :
# Check database connection
with connection.cursor() as cursor:
cursor.execute( "SELECT 1" )
return JsonResponse({
'status' : 'healthy' ,
'database' : 'connected'
})
except Exception as e:
return JsonResponse({
'status' : 'unhealthy' ,
'error' : str (e)
}, status = 500 )
Database Connection Pooling
For high-traffic applications, consider using pgBouncer or django-db-connection-pool.
Caching
Implement Redis caching:
CACHES = {
'default' : {
'BACKEND' : 'django.core.cache.backends.redis.RedisCache' ,
'LOCATION' : os.getenv( 'REDIS_URL' , 'redis://127.0.0.1:6379/1' ),
}
}
Gunicorn Workers
Calculate optimal worker count:
workers = ( 2 * multiprocessing.cpu_count()) + 1
Rollback Strategy
Database Backup
Always backup database before deployment: pg_dump -h $RDS_HOSTNAME -U $RDS_USERNAME $RDS_DB_NAME > backup_ $( date +%Y%m%d_%H%M%S ) .sql
Git Tag Release
Tag releases for easy rollback: git tag -a v1.0.0 -m "Release version 1.0.0"
git push origin v1.0.0
Rollback Commands
If issues occur: # Rollback code
git checkout v1.0.0
# Rollback migrations
python manage.py migrate app_name migration_name
# Restore database (if needed)
psql -h $RDS_HOSTNAME -U $RDS_USERNAME $RDS_DB_NAME < backup.sql
Next Steps
Environment Variables Complete reference for all environment variables
Database Migrations Learn about managing migrations in production
Static Files Configure static file serving