Environment Variables#
Complete reference for all environment variables used in production deployments.
Overview#
Construbot uses environment variables for configuration following the Twelve-Factor App methodology. Variables are loaded from:
.envfile (development/Docker)System environment (production servers)
Container environment (Docker/Kubernetes)
Note
This document focuses on production-specific variables. For development configuration, see Configuration.
Required Variables#
Django Core#
DJANGO_SETTINGS_MODULE#
Type: String
Required: Yes
Description: Python path to settings module
Production value:
DJANGO_SETTINGS_MODULE=construbot.config.settings.production
Values:
construbot.config.settings.local- Developmentconstrubot.config.settings.test- Testingconstrubot.config.settings.production- Production
DJANGO_SECRET_KEY#
Type: String (50+ characters)
Required: Yes
Description: Cryptographic signing key for sessions, cookies, CSRF tokens
Danger
Never commit SECRET_KEY to version control! Use different keys for dev/prod.
Generate:
python -c "from django.core.management.utils import get_random_secret_key; print(get_random_secret_key())"
Example:
DJANGO_SECRET_KEY=django-insecure-a1b2c3d4e5f6g7h8i9j0k1l2m3n4o5p6q7r8s9t0
DJANGO_DEBUG#
Type: Boolean
Required: Yes
Description: Enable/disable debug mode
Danger
MUST be False in production! Debug mode exposes sensitive information.
Production value:
DJANGO_DEBUG=False
Effects when True:
Detailed error pages with tracebacks
Exposes settings and environment variables
Shows SQL queries
Serves static files via Django (slow)
Disables template caching
DJANGO_ALLOWED_HOSTS#
Type: Comma-separated string
Required: Yes (when DEBUG=False)
Description: Hosts/domains that Django serves
Example:
DJANGO_ALLOWED_HOSTS=example.com,www.example.com,api.example.com
Include:
Root domain
www subdomain
API subdomain (if separate)
Load balancer hostname
Validation:
# Test in shell
from django.conf import settings
print(settings.ALLOWED_HOSTS)
# ['example.com', 'www.example.com', 'api.example.com']
Database#
DATABASE_URL#
Type: PostgreSQL connection string
Required: Yes
Description: Complete database connection URL
Format:
postgresql://[user]:[password]@[host]:[port]/[database][?options]
Examples:
# Self-hosted
DATABASE_URL=postgresql://construbot:password@postgres:5432/construbot
# AWS RDS (with SSL)
DATABASE_URL=postgresql://construbot:pwd@db.abc123.us-east-1.rds.amazonaws.com:5432/construbot?sslmode=require
# With connection pooling options
DATABASE_URL=postgresql://user:pwd@host:5432/db?sslmode=require&connect_timeout=10&options=-c%20statement_timeout=300000
SSL modes:
disable- No SSL (not recommended for production)require- SSL required (recommended)verify-ca- Verify certificate authorityverify-full- Full certificate verification
Cache and Queue#
REDIS_URL#
Type: Redis connection string
Required: Yes
Description: Redis for caching and Celery broker
Format:
redis://[:password]@[host]:[port]/[database]
Examples:
# Self-hosted (no password)
REDIS_URL=redis://redis:6379/0
# With password
REDIS_URL=redis://:mypassword@redis:6379/0
# AWS ElastiCache
REDIS_URL=redis://construbot.abc123.cache.amazonaws.com:6379/0
Database numbers:
/0- Cache and sessions/1- Celery broker (optional separation)/2- Celery results (optional separation)
Security Settings#
SSL/HTTPS#
DJANGO_SECURE_SSL_REDIRECT#
Type: Boolean
Default: False
Description: Redirect all HTTP requests to HTTPS
Production value:
DJANGO_SECURE_SSL_REDIRECT=True
Requires:
Valid SSL certificate
HTTPS configured on web server/load balancer
DJANGO_SECURE_PROXY_SSL_HEADER#
Type: Tuple (header name, header value)
Default: None
Description: Trust X-Forwarded-Proto header from proxy/load balancer
Production value:
DJANGO_SECURE_PROXY_SSL_HEADER=HTTP_X_FORWARDED_PROTO,https
When to use:
Behind nginx reverse proxy
Behind AWS ALB/ELB
Behind CloudFlare
HSTS (HTTP Strict Transport Security)#
DJANGO_SECURE_HSTS_SECONDS#
Type: Integer (seconds)
Default: 0 (disabled)
Description: Browser should only access via HTTPS for this many seconds
Production value:
DJANGO_SECURE_HSTS_SECONDS=31536000 # 1 year
Warning
Test carefully before enabling! Once set, browsers refuse HTTP connections.
DJANGO_SECURE_HSTS_INCLUDE_SUBDOMAINS#
Type: Boolean
Default: False
Description: Apply HSTS to all subdomains
Production value:
DJANGO_SECURE_HSTS_INCLUDE_SUBDOMAINS=True
Requires: All subdomains support HTTPS
DJANGO_SECURE_HSTS_PRELOAD#
Type: Boolean
Default: False
Description: Allow adding to browser HSTS preload lists
Production value:
DJANGO_SECURE_HSTS_PRELOAD=True
After enabling:
Submit domain to https://hstspreload.org/
Content Security#
DJANGO_SECURE_CONTENT_TYPE_NOSNIFF#
Type: Boolean
Default: False
Description: Prevent MIME type sniffing
Production value:
DJANGO_SECURE_CONTENT_TYPE_NOSNIFF=True
DJANGO_SECURE_BROWSER_XSS_FILTER#
Type: Boolean
Default: False
Description: Enable browser XSS filter
Production value:
DJANGO_SECURE_BROWSER_XSS_FILTER=True
X_FRAME_OPTIONS#
Type: String
Default: DENY
Description: Control iframe embedding
Values:
DENY- Cannot be embedded (recommended)SAMEORIGIN- Can embed on same domainALLOW-FROM https://example.com- Allow specific domain
Production value:
X_FRAME_OPTIONS=DENY
Email Configuration#
Type: String (Python import path)
Required: Yes
Description: Email backend to use
Production values:
# Mailgun (recommended)
DJANGO_EMAIL_BACKEND=anymail.backends.mailgun.EmailBackend
# SendGrid
DJANGO_EMAIL_BACKEND=anymail.backends.sendgrid.EmailBackend
# Amazon SES
DJANGO_EMAIL_BACKEND=anymail.backends.amazon_ses.EmailBackend
# SMTP (generic)
DJANGO_EMAIL_BACKEND=django.core.mail.backends.smtp.EmailBackend
Type: String
Required: If using Mailgun
Description: Mailgun API key
Example:
MAILGUN_API_KEY=key-1234567890abcdef1234567890abcdef
Get from: https://app.mailgun.com/app/account/security/api_keys
Type: String
Required: If using Mailgun
Description: Verified domain for sending
Example:
MAILGUN_SENDER_DOMAIN=mg.example.com
Type: Email address
Required: Yes
Description: Default sender for emails
Example:
DEFAULT_FROM_EMAIL=noreply@example.com
Type: Email address
Default: root@localhost
Description: Sender for error emails
Example:
SERVER_EMAIL=errors@example.com
Static and Media Files#
Type: Boolean
Default: False
Description: Use AWS S3 for media file storage
Production value:
USE_S3=True
Type: String
Required: If USE_S3=True
Description: AWS access key with S3 permissions
Example:
AWS_ACCESS_KEY_ID=AKIAIOSFODNN7EXAMPLE
Type: String
Required: If USE_S3=True
Description: AWS secret key
Example:
AWS_SECRET_ACCESS_KEY=wJalrXUtnFEMI/K7MDENG/bPxRfiCYEXAMPLEKEY
Type: String
Required: If USE_S3=True
Description: S3 bucket name for media files
Example:
AWS_STORAGE_BUCKET_NAME=construbot-media-example-com
Type: String
Default: us-east-1
Description: AWS region for S3 bucket
Example:
AWS_S3_REGION_NAME=us-west-2
Type: String
Default: None (optional)
Description: CloudFront or custom domain for media files
Example:
AWS_S3_CUSTOM_DOMAIN=d111111abcdef8.cloudfront.net
Monitoring and Logging#
Type: String (URL)
Default: None (optional)
Description: Sentry error tracking DSN
Example:
SENTRY_DSN=https://abcdef1234567890@o123456.ingest.sentry.io/7654321
Get from: Sentry project settings
Type: String
Default: production
Description: Environment name in Sentry
Examples:
SENTRY_ENVIRONMENT=production
SENTRY_ENVIRONMENT=staging
Type: Float (0.0 to 1.0)
Default: 1.0
Description: Percentage of errors to send to Sentry
Example:
SENTRY_SAMPLE_RATE=1.0 # Send 100% of errors
Type: String
Default: INFO
Description: Minimum log level to record
Values:
DEBUG- Detailed information (development only)INFO- General informational messages (production recommended)WARNING- Warning messagesERROR- Error messages onlyCRITICAL- Critical errors only
Production value:
LOG_LEVEL=INFO
CORS Configuration#
Type: Comma-separated string
Default: Empty
Description: Allowed origins for CORS requests
Example:
CORS_ALLOWED_ORIGINS=https://app.example.com,https://mobile.example.com
When needed:
API consumed by separate frontend
Mobile app accessing API
Different subdomain for frontend
Type: Boolean
Default: False
Description: Allow CORS from any origin
Danger
Never use in production! Security risk.
Development only:
CORS_ALLOW_ALL_ORIGINS=True
Celery Configuration#
Type: Redis connection string
Default: Uses REDIS_URL
Description: Celery message broker
Example:
CELERY_BROKER_URL=redis://redis:6379/1
Usually same as REDIS_URL but can use different database number.
Type: Redis connection string
Default: Uses REDIS_URL
Description: Celery result storage
Example:
CELERY_RESULT_BACKEND=redis://redis:6379/2
Optional Variables#
Library Mode#
CONSTRUBOT_AS_LIBRARY#
Type: Boolean
Default: False
Description: Run Construbot as Django app (not standalone)
Example:
CONSTRUBOT_AS_LIBRARY=True
Effects:
Disables admin interface
Disables account management URLs
Disables standalone authentication
Allows embedding in existing Django project
See Library Mode for details.
Database Connection Pooling#
DATABASE_CONN_MAX_AGE#
Type: Integer (seconds)
Default: 0 (new connection per request)
Description: How long to reuse database connections
Production value:
DATABASE_CONN_MAX_AGE=600 # 10 minutes
Benefits:
Reduced database connection overhead
Better performance under load
Lower database resource usage
Session Storage#
SESSION_ENGINE#
Type: String
Default: django.contrib.sessions.backends.db
Description: Where to store sessions
Options:
# Database (default)
SESSION_ENGINE=django.contrib.sessions.backends.db
# Cache (Redis) - faster
SESSION_ENGINE=django.contrib.sessions.backends.cache
# Cached database - best of both
SESSION_ENGINE=django.contrib.sessions.backends.cached_db
Production recommendation:
SESSION_ENGINE=django.contrib.sessions.backends.cached_db
Complete Production Example#
Minimal Production .env#
# Django Core
DJANGO_SETTINGS_MODULE=construbot.config.settings.production
DJANGO_DEBUG=False
DJANGO_SECRET_KEY=<generate-strong-50+-char-key>
DJANGO_ALLOWED_HOSTS=example.com,www.example.com
# Database
DATABASE_URL=postgresql://user:pass@db.example.rds.amazonaws.com:5432/construbot?sslmode=require
# Cache/Queue
REDIS_URL=redis://:password@redis.example.cache.amazonaws.com:6379/0
# Email
DJANGO_EMAIL_BACKEND=anymail.backends.mailgun.EmailBackend
MAILGUN_API_KEY=key-xxxxxxxxxx
MAILGUN_SENDER_DOMAIN=mg.example.com
DEFAULT_FROM_EMAIL=noreply@example.com
# Storage
USE_S3=True
AWS_ACCESS_KEY_ID=AKIAXXXXXX
AWS_SECRET_ACCESS_KEY=xxxxxxxxxx
AWS_STORAGE_BUCKET_NAME=construbot-media-example
AWS_S3_REGION_NAME=us-east-1
# Security
DJANGO_SECURE_SSL_REDIRECT=True
DJANGO_SECURE_HSTS_SECONDS=31536000
DJANGO_SESSION_COOKIE_SECURE=True
DJANGO_CSRF_COOKIE_SECURE=True
# Monitoring
SENTRY_DSN=https://xxx@sentry.io/xxx
Comprehensive Production .env#
# Django Core
DJANGO_SETTINGS_MODULE=construbot.config.settings.production
DJANGO_DEBUG=False
DJANGO_SECRET_KEY=<generate-strong-50+-char-key>
DJANGO_ALLOWED_HOSTS=example.com,www.example.com,api.example.com
DJANGO_READ_DOT_ENV_FILE=True
# Database
DATABASE_URL=postgresql://user:pass@db.example.rds.amazonaws.com:5432/construbot?sslmode=require&connect_timeout=10
DATABASE_CONN_MAX_AGE=600
# Cache/Queue
REDIS_URL=redis://:password@redis.example.cache.amazonaws.com:6379/0
CELERY_BROKER_URL=redis://:password@redis.example.cache.amazonaws.com:6379/1
CELERY_RESULT_BACKEND=redis://:password@redis.example.cache.amazonaws.com:6379/2
# Sessions
SESSION_ENGINE=django.contrib.sessions.backends.cached_db
# Email
DJANGO_EMAIL_BACKEND=anymail.backends.mailgun.EmailBackend
MAILGUN_API_KEY=key-xxxxxxxxxx
MAILGUN_SENDER_DOMAIN=mg.example.com
DEFAULT_FROM_EMAIL=noreply@example.com
SERVER_EMAIL=errors@example.com
# Storage
USE_S3=True
AWS_ACCESS_KEY_ID=AKIAXXXXXX
AWS_SECRET_ACCESS_KEY=xxxxxxxxxx
AWS_STORAGE_BUCKET_NAME=construbot-media-example
AWS_S3_REGION_NAME=us-west-2
AWS_S3_CUSTOM_DOMAIN=d111111abcdef8.cloudfront.net
# Security - SSL
DJANGO_SECURE_SSL_REDIRECT=True
DJANGO_SECURE_PROXY_SSL_HEADER=HTTP_X_FORWARDED_PROTO,https
# Security - HSTS
DJANGO_SECURE_HSTS_SECONDS=31536000
DJANGO_SECURE_HSTS_INCLUDE_SUBDOMAINS=True
DJANGO_SECURE_HSTS_PRELOAD=True
# Security - Cookies
DJANGO_SESSION_COOKIE_SECURE=True
DJANGO_SESSION_COOKIE_HTTPONLY=True
DJANGO_CSRF_COOKIE_SECURE=True
DJANGO_CSRF_COOKIE_HTTPONLY=True
# Security - Content
DJANGO_SECURE_CONTENT_TYPE_NOSNIFF=True
DJANGO_SECURE_BROWSER_XSS_FILTER=True
X_FRAME_OPTIONS=DENY
# Monitoring
SENTRY_DSN=https://xxx@sentry.io/xxx
SENTRY_ENVIRONMENT=production
SENTRY_SAMPLE_RATE=1.0
LOG_LEVEL=INFO
# CORS (if needed)
CORS_ALLOWED_ORIGINS=https://app.example.com
Validation#
Check Required Variables#
# Run Django checks
docker compose run --rm django python manage.py check --deploy
No warnings should appear.
Test Configuration#
# Django shell
docker compose run --rm django python manage.py shell
from django.conf import settings
# Verify critical settings
assert settings.DEBUG is False, "DEBUG must be False!"
assert settings.SECRET_KEY != 'insecure-key', "Change SECRET_KEY!"
assert len(settings.ALLOWED_HOSTS) > 0, "Set ALLOWED_HOSTS!"
print(f"Database: {settings.DATABASES['default']['NAME']}")
print(f"Redis: {settings.CACHES['default']['LOCATION']}")
print(f"Email: {settings.EMAIL_BACKEND}")
print(f"Static: {settings.STATIC_URL}")
print(f"Media: {settings.MEDIA_URL}")
See Also#
Production Checklist - Complete deployment checklist
Configuration - Development configuration
AWS EC2 Deployment - AWS deployment guide
Static & Media Files - File storage configuration