Configuration#

Complete guide to configuring Construbot using environment variables and settings files.

Overview#

Construbot uses a layered configuration approach:

  1. Settings files - Python modules in construbot/config/settings/

  2. Environment variables - Loaded from .env file or system environment

  3. Runtime configuration - Django settings controlled by environment

This follows the Twelve-Factor App methodology for configuration management.

Settings Structure#

Settings Files#

Located in construbot/config/settings/:

settings/
├── __init__.py
├── base.py          # Shared settings for all environments
├── local.py         # Development settings
├── test.py          # Testing settings
└── production.py    # Production settings

Selection:

The active settings module is controlled by DJANGO_SETTINGS_MODULE:

# Development
export DJANGO_SETTINGS_MODULE=construbot.config.settings.local

# Production
export DJANGO_SETTINGS_MODULE=construbot.config.settings.production

Inheritance:

All environment-specific files inherit from base.py:

# local.py
from .base import *  # Import all base settings

# Override for development
DEBUG = True
ALLOWED_HOSTS = ['localhost', '127.0.0.1']

Environment Variables#

Loading Variables#

From .env file (recommended for development):

# Enable .env file loading
export DJANGO_READ_DOT_ENV_FILE=True

Create .env in project root:

# .env
DJANGO_SETTINGS_MODULE=construbot.config.settings.local
DJANGO_DEBUG=True
DATABASE_URL=postgresql://user:pass@localhost:5432/construbot_dev

From system environment:

# Export variables
export DJANGO_SETTINGS_MODULE=construbot.config.settings.production
export DJANGO_DEBUG=False
export DATABASE_URL=postgresql://...

In Docker Compose:

# docker-compose.yml
services:
  django:
    env_file:
      - ./.env
    environment:
      - DJANGO_SETTINGS_MODULE=construbot.config.settings.local

Required Variables#

Core Configuration#

DJANGO_SETTINGS_MODULE

DJANGO_SETTINGS_MODULE=construbot.config.settings.local

Values:

  • construbot.config.settings.local - Development

  • construbot.config.settings.test - Testing

  • construbot.config.settings.production - Production

DJANGO_SECRET_KEY

DJANGO_SECRET_KEY=your-secret-key-here

Generate:

python -c "from django.core.management.utils import get_random_secret_key; print(get_random_secret_key())"

Warning

Never commit SECRET_KEY to version control! Use different keys for development and production.

DJANGO_DEBUG

DJANGO_DEBUG=True   # Development
DJANGO_DEBUG=False  # Production

Danger

Always set DEBUG=False in production! Debug mode exposes sensitive information.

Database Configuration#

DATABASE_URL

# PostgreSQL (recommended)
DATABASE_URL=postgresql://user:password@host:port/database

# Examples:
# Local development:
DATABASE_URL=postgresql://construbot_user:construbot_pass@localhost:5432/construbot_dev

# Docker:
DATABASE_URL=postgresql://debug:debug@postgres:5432/construbot

# Production (with SSL):
DATABASE_URL=postgresql://user:pass@host:5432/db?sslmode=require

Format: postgresql://[user]:[password]@[host]:[port]/[database]

Note

Construbot uses django-environ to parse DATABASE_URL into Django’s DATABASES setting.

Cache and Queue#

REDIS_URL

# Local development
REDIS_URL=redis://localhost:6379/0

# Docker
REDIS_URL=redis://redis:6379/0

# Production with password
REDIS_URL=redis://:password@host:6379/0

Used for:

  • Django cache backend

  • Celery message broker

  • Celery result backend

  • Session storage (optional)

Optional Variables#

Email Configuration#

Development (Console Backend):

DJANGO_EMAIL_BACKEND=django.core.mail.backends.console.EmailBackend

Emails are printed to console instead of sent.

Production (SMTP):

DJANGO_EMAIL_BACKEND=django.core.mail.backends.smtp.EmailBackend
EMAIL_HOST=smtp.gmail.com
EMAIL_PORT=587
EMAIL_HOST_USER=your-email@gmail.com
EMAIL_HOST_PASSWORD=your-app-password
EMAIL_USE_TLS=True

Using django-anymail (Recommended):

# Mailgun
DJANGO_EMAIL_BACKEND=anymail.backends.mailgun.EmailBackend
MAILGUN_API_KEY=your-api-key
MAILGUN_SENDER_DOMAIN=mg.example.com

# SendGrid
DJANGO_EMAIL_BACKEND=anymail.backends.sendgrid.EmailBackend
SENDGRID_API_KEY=your-api-key

# Amazon SES
DJANGO_EMAIL_BACKEND=anymail.backends.amazon_ses.EmailBackend
AWS_ACCESS_KEY_ID=your-key
AWS_SECRET_ACCESS_KEY=your-secret
AWS_SES_REGION_NAME=us-east-1

Default from email:

DEFAULT_FROM_EMAIL=noreply@construbot.com
SERVER_EMAIL=errors@construbot.com

Static and Media Files#

Development (default):

# Static files served by Django
# Media files served from MEDIA_ROOT

Production (S3):

# AWS S3 for media files
USE_S3=True
AWS_ACCESS_KEY_ID=your-access-key
AWS_SECRET_ACCESS_KEY=your-secret-key
AWS_STORAGE_BUCKET_NAME=your-bucket-name
AWS_S3_REGION_NAME=us-east-1

# Optional: Custom domain
AWS_S3_CUSTOM_DOMAIN=cdn.example.com

Static files (WhiteNoise):

No configuration needed. WhiteNoise is enabled by default in production settings.

Allowed Hosts#

DJANGO_ALLOWED_HOSTS

# Development
DJANGO_ALLOWED_HOSTS=localhost,127.0.0.1

# Production (comma-separated)
DJANGO_ALLOWED_HOSTS=example.com,www.example.com,api.example.com

Warning

Required in production! Django will refuse connections from hosts not in this list.

CORS Configuration#

CORS_ALLOWED_ORIGINS

# Allow specific origins (recommended)
CORS_ALLOWED_ORIGINS=https://app.example.com,https://mobile.example.com

CORS_ALLOW_ALL_ORIGINS

# Development only - allow all origins
CORS_ALLOW_ALL_ORIGINS=True

Danger

Never use CORS_ALLOW_ALL_ORIGINS in production! Only allow trusted origins.

Docker Configuration#

USE_DOCKER

USE_DOCKER=yes  # Docker environment
USE_DOCKER=no   # Local environment

This affects:

  • Database host (postgres vs localhost)

  • Redis host (redis vs localhost)

  • Email host (mailhog vs localhost SMTP)

Library Mode#

CONSTRUBOT_AS_LIBRARY

CONSTRUBOT_AS_LIBRARY=False  # Standalone mode (default)
CONSTRUBOT_AS_LIBRARY=True   # Library mode

When True:

  • Disables admin interface

  • Disables account management URLs

  • Disables standalone authentication

  • Use Construbot as Django app in your project

See Library Mode for details.

Sentry Integration#

SENTRY_DSN

SENTRY_DSN=https://your-dsn@sentry.io/project-id

SENTRY_ENVIRONMENT

SENTRY_ENVIRONMENT=production  # or staging, development

SENTRY_SAMPLE_RATE

# 1.0 = 100% of errors sent to Sentry
SENTRY_SAMPLE_RATE=1.0

Logging#

LOG_LEVEL

LOG_LEVEL=INFO   # Production
LOG_LEVEL=DEBUG  # Development

Values: DEBUG, INFO, WARNING, ERROR, CRITICAL

Celery Configuration#

CELERY_BROKER_URL

CELERY_BROKER_URL=redis://redis:6379/0

Usually same as REDIS_URL.

CELERY_RESULT_BACKEND

CELERY_RESULT_BACKEND=redis://redis:6379/0

CELERY_TASK_ALWAYS_EAGER

# Execute tasks synchronously (testing)
CELERY_TASK_ALWAYS_EAGER=True

Configuration by Environment#

Development (.env)#

Complete .env file for local development:

# Django Settings
DJANGO_SETTINGS_MODULE=construbot.config.settings.local
DJANGO_DEBUG=True
DJANGO_READ_DOT_ENV_FILE=True
DJANGO_SECRET_KEY=dev-secret-key-change-in-production

# Docker
USE_DOCKER=yes  # Set to 'no' for local development

# Database (Docker)
DATABASE_URL=postgresql://debug:debug@postgres:5432/construbot

# Database (Local)
# DATABASE_URL=postgresql://construbot_user:construbot_pass@localhost:5432/construbot_dev

# Redis
REDIS_URL=redis://redis:6379/0

# Email (Console)
DJANGO_EMAIL_BACKEND=django.core.mail.backends.console.EmailBackend

# Celery
CELERY_BROKER_URL=redis://redis:6379/0
CELERY_RESULT_BACKEND=redis://redis:6379/0

# Allowed Hosts
DJANGO_ALLOWED_HOSTS=localhost,127.0.0.1,0.0.0.0

# CORS (Development only)
CORS_ALLOW_ALL_ORIGINS=True

Testing#

Environment for running tests:

# Settings
DJANGO_SETTINGS_MODULE=construbot.config.settings.test
DJANGO_DEBUG=False
DJANGO_SECRET_KEY=test-secret-key

# Database (in-memory SQLite)
# No DATABASE_URL needed - test settings use SQLite

# Celery (synchronous execution)
CELERY_TASK_ALWAYS_EAGER=True

Production#

Production environment variables:

# Django Settings
DJANGO_SETTINGS_MODULE=construbot.config.settings.production
DJANGO_DEBUG=False
DJANGO_SECRET_KEY=<generate-strong-secret-key>

# Security
DJANGO_SECURE_SSL_REDIRECT=True
DJANGO_SECURE_HSTS_SECONDS=31536000
DJANGO_SESSION_COOKIE_SECURE=True
DJANGO_CSRF_COOKIE_SECURE=True

# Database (with SSL)
DATABASE_URL=postgresql://user:pass@host:5432/db?sslmode=require

# Redis
REDIS_URL=redis://:password@host:6379/0

# Email (Production service)
DJANGO_EMAIL_BACKEND=anymail.backends.mailgun.EmailBackend
MAILGUN_API_KEY=<your-api-key>
MAILGUN_SENDER_DOMAIN=mg.example.com
DEFAULT_FROM_EMAIL=noreply@example.com

# Static/Media Files (S3)
USE_S3=True
AWS_ACCESS_KEY_ID=<your-key>
AWS_SECRET_ACCESS_KEY=<your-secret>
AWS_STORAGE_BUCKET_NAME=construbot-media
AWS_S3_REGION_NAME=us-east-1

# Allowed Hosts (comma-separated)
DJANGO_ALLOWED_HOSTS=example.com,www.example.com,api.example.com

# CORS (specific origins only)
CORS_ALLOWED_ORIGINS=https://app.example.com

# Sentry
SENTRY_DSN=<your-sentry-dsn>
SENTRY_ENVIRONMENT=production

# Logging
LOG_LEVEL=INFO

Security Settings#

Production Security Checklist#

# HTTPS Enforcement
DJANGO_SECURE_SSL_REDIRECT=True
DJANGO_SECURE_PROXY_SSL_HEADER=HTTP_X_FORWARDED_PROTO,https

# HSTS (HTTP Strict Transport Security)
DJANGO_SECURE_HSTS_SECONDS=31536000
DJANGO_SECURE_HSTS_INCLUDE_SUBDOMAINS=True
DJANGO_SECURE_HSTS_PRELOAD=True

# Cookie Security
DJANGO_SESSION_COOKIE_SECURE=True
DJANGO_SESSION_COOKIE_HTTPONLY=True
DJANGO_CSRF_COOKIE_SECURE=True
DJANGO_CSRF_COOKIE_HTTPONLY=True

# Content Security
DJANGO_SECURE_CONTENT_TYPE_NOSNIFF=True
DJANGO_SECURE_BROWSER_XSS_FILTER=True
X_FRAME_OPTIONS=DENY

Run security check:

python manage.py check --deploy

Managing Configuration#

Environment File Template#

Create .env.example as a template:

# Copy for local use: cp .env.example .env

# Django
DJANGO_SETTINGS_MODULE=construbot.config.settings.local
DJANGO_DEBUG=True
DJANGO_SECRET_KEY=change-me

# Database
DATABASE_URL=postgresql://user:pass@host:port/database

# ... (include all required variables with examples)

Benefits:

  • Documents required variables

  • Provides examples for developers

  • Safe to commit (no secrets)

Secrets Management#

Development:

  • Use .env file (git-ignored)

  • Share .env.example template

Production:

  • Use environment variables (not .env file)

  • Store secrets in secure vault (AWS Secrets Manager, HashiCorp Vault)

  • Inject secrets at runtime

Example with AWS Secrets Manager:

# In settings/production.py
import boto3
import json

def get_secret(secret_name):
    client = boto3.client('secretsmanager')
    response = client.get_secret_value(SecretId=secret_name)
    return json.loads(response['SecretString'])

secrets = get_secret('construbot/production')
SECRET_KEY = secrets['DJANGO_SECRET_KEY']
DATABASE_URL = secrets['DATABASE_URL']

Validating Configuration#

Check required variables:

# Django checks
python manage.py check

# Deployment checks
python manage.py check --deploy

# Database connection
python manage.py dbshell

Test email configuration:

python manage.py shell
>>> from django.core.mail import send_mail
>>> send_mail('Test', 'Message', 'from@example.com', ['to@example.com'])

Troubleshooting#

Common Issues#

“ImproperlyConfigured: Set the DATABASE_URL environment variable”

# Ensure DATABASE_URL is set
echo $DATABASE_URL

# Or add to .env
DATABASE_URL=postgresql://...

“SECRET_KEY is required”

# Generate and set SECRET_KEY
python -c "from django.core.management.utils import get_random_secret_key; print(get_random_secret_key())"

# Add to .env
DJANGO_SECRET_KEY=<generated-key>

“CommandError: You must set settings.ALLOWED_HOSTS”

# Add to .env
DJANGO_ALLOWED_HOSTS=localhost,127.0.0.1

“DisallowedHost at /”

# Add your domain to ALLOWED_HOSTS
DJANGO_ALLOWED_HOSTS=example.com,www.example.com

Variables not loading from .env

# Ensure this is set
DJANGO_READ_DOT_ENV_FILE=True

# Check .env is in project root (same directory as manage.py)
ls -la .env

Variable Precedence#

If a variable is set in multiple places, this is the priority order:

  1. System environment variables (highest priority)

  2. .env file

  3. Settings file defaults (lowest priority)

Example:

# .env
DJANGO_DEBUG=True

# Terminal
export DJANGO_DEBUG=False

# Django will use DEBUG=False (system environment wins)

See Also#