Configuration Guide#
FairDM provides a flexible, environment-aware configuration system built on top of Django’s settings. This guide explains how to configure your portal for different deployment scenarios.
Overview#
The configuration system is designed around these principles:
Production by default: Settings start from a secure production baseline
Environment-specific overrides: Development and staging can override production settings
Project customization: Portals can safely override framework settings
Addon integration: Third-party addons inject their settings cleanly
Quick Start#
In your portal’s main settings.py:
import fairdm
fairdm.setup()
That’s it! FairDM will load the appropriate configuration based on your environment.
Environment Profiles#
FairDM supports three environment profiles, selected via the DJANGO_ENV environment variable:
Production (default)#
export DJANGO_ENV=production
Characteristics:
Strict validation (fail-fast)
Requires PostgreSQL database
Requires Redis cache
Enforces HTTPS security
Requires strong SECRET_KEY
DEBUG disabled
Use for: Production deployments, public-facing portals
Staging#
export DJANGO_ENV=staging
Characteristics:
Production-like validation
Enhanced DEBUG-level logging
Optional Sentry error tracking
Same security requirements as production
Use for: Pre-production testing, QA environments
Development#
export DJANGO_ENV=development
Characteristics:
Graceful degradation (warns instead of failing)
SQLite fallback if no DATABASE_URL
LocMemCache fallback if no Redis
Eager Celery (no broker needed)
Console email backend
DEBUG enabled
Relaxed security settings
Use for: Local development, testing
Configuration Structure#
FairDM’s configuration is organized into focused modules:
fairdm/conf/
├── __init__.py # Package exports
├── setup.py # Main setup() function
├── environment.py # Environment variable handling
├── checks.py # Configuration validation
├── addons.py # Addon discovery and loading
├── development.py # Development overrides
├── staging.py # Staging overrides
└── settings/ # Production baseline (10 modules)
├── apps.py # INSTALLED_APPS, MIDDLEWARE, TEMPLATES
├── auth.py # Authentication backends
├── cache.py # Redis/LocMemCache/DummyCache
├── celery.py # Background task processing
├── database.py # PostgreSQL/SQLite configuration
├── email.py # Email backend
├── logging.py # Logging and Sentry
├── security.py # SECRET_KEY, ALLOWED_HOSTS, HTTPS
├── static_media.py # Static/media with WhiteNoise, S3
└── addons.py # Third-party library configurations
Loading Order#
When you call fairdm.setup(), settings are loaded in this order:
Environment detection: Reads
DJANGO_ENV(defaults toproduction)Environment variables: Loads
.envfiles if presentProduction baseline: Loads all modules from
settings/directoryEnvironment overrides: Loads
development.pyorstaging.pyif applicableAddon configurations: Loads addon setup modules
Project overrides: Applies
**overridespassed tosetup()Validation: Runs configuration checks
Later settings override earlier ones.
Environment Variables#
Required (Production/Staging)#
# Security
DJANGO_SECRET_KEY="your-secret-key-minimum-50-characters-long"
DJANGO_ALLOWED_HOSTS="example.com,www.example.com"
# Site identification
DJANGO_SITE_DOMAIN="example.com"
DJANGO_SITE_NAME="My Research Portal"
# Database
DATABASE_URL="postgresql://user:password@localhost:5432/dbname"
# Cache
REDIS_URL="redis://localhost:6379/0"
# Email (if sending emails)
EMAIL_HOST="smtp.example.com"
EMAIL_PORT="587"
EMAIL_HOST_USER="noreply@example.com"
EMAIL_HOST_PASSWORD="your-email-password"
Optional#
# Static files (S3/CloudFront)
AWS_ACCESS_KEY_ID="your-access-key"
AWS_SECRET_ACCESS_KEY="your-secret-key"
AWS_STORAGE_BUCKET_NAME="your-bucket"
AWS_S3_CUSTOM_DOMAIN="cdn.example.com"
# Error tracking
SENTRY_DSN="your-sentry-dsn"
# Media storage (if using S3)
AWS_MEDIA_BUCKET_NAME="your-media-bucket"
Environment File Loading#
FairDM loads environment files in this order (later files override earlier ones):
stack.env(base configuration)stack.{profile}.env(e.g.,stack.production.env,stack.development.env)Custom file specified via
env_fileparameter
Example:
fairdm.setup(env_file="/path/to/custom.env")
Project Customization#
Using **overrides#
Pass settings as keyword arguments to setup():
import fairdm
fairdm.setup(
TIME_ZONE="Europe/London",
LANGUAGE_CODE="en-gb",
CUSTOM_SETTING="value",
)
Post-setup Assignments#
Modify settings after calling setup():
import fairdm
fairdm.setup()
# Add portal-specific apps
INSTALLED_APPS = INSTALLED_APPS + [
"my_portal_app",
"my_other_app",
]
# Customize logging
LOGGING["loggers"]["my_app"] = {
"handlers": ["console", "file"],
"level": "INFO",
}
# Override specific settings
TIME_ZONE = "America/New_York"
Which Method to Use?#
**overrides: For simple scalar values (strings, booleans, numbers)Post-setup assignments: For complex modifications (extending lists, updating dicts)
Addon Integration#
Addons are FairDM extensions that provide additional functionality. They inject settings, apps, and middleware automatically.
Using Addons#
import fairdm
fairdm.setup(
addons=[
"fairdm_discussions", # Community discussions
"fairdm_publications", # Research publications
]
)
Creating an Addon#
To make your package a FairDM addon:
Create a setup module (e.g.,
my_addon/fdm_setup.py):
# my_addon/fdm_setup.py
# Add your app to INSTALLED_APPS
INSTALLED_APPS = INSTALLED_APPS + ["my_addon"] # noqa: F821
# Add middleware
MIDDLEWARE = MIDDLEWARE + ["my_addon.middleware.MyMiddleware"] # noqa: F821
# Add custom settings
MY_ADDON_SETTING = "value"
Register the setup module in your package’s
__init__.py:
# my_addon/__init__.py
__fdm_setup_module__ = "my_addon.fdm_setup"
Install and enable in portal:
fairdm.setup(addons=["my_addon"])
Addon Validation#
Production/Staging: Addons must load successfully (fail-fast)
Development: Failed addons log warnings but don’t stop startup
Configuration Validation#
FairDM validates your configuration on startup. Validation behavior depends on environment:
Production/Staging (Fail-Fast)#
Startup fails if:
SECRET_KEYmissing or too short (< 50 characters)ALLOWED_HOSTSempty or contains wildcardsDEBUG = True(security risk)Database not configured or unreachable
Cache backend is not production-grade (not Redis/Memcached)
HTTPS security settings disabled
Required addons fail to load
Development (Graceful Degradation)#
Logs warnings but continues if:
SECRET_KEYis short (>= 8 characters acceptable)DATABASE_URLnot set → falls back to SQLiteREDIS_URLnot set → falls back to LocMemCacheCelery broker not configured → uses eager mode (synchronous)
Email backend not configured → uses console backend
Addons fail to load → skips and continues
Troubleshooting#
Common Issues#
“SECRET_KEY is required”#
Solution: Set DJANGO_SECRET_KEY in your environment:
export DJANGO_SECRET_KEY="$(python -c 'from django.core.management.utils import get_random_secret_key; print(get_random_secret_key())')"
“Database not configured”#
Solution: Set DATABASE_URL:
export DATABASE_URL="postgresql://user:password@localhost:5432/dbname"
Or for development, rely on SQLite fallback:
export DJANGO_ENV=development # Uses SQLite automatically
“Cache backend not suitable for production”#
Solution: Set REDIS_URL:
export REDIS_URL="redis://localhost:6379/0"
“ALLOWED_HOSTS cannot be empty”#
Solution: Set DJANGO_ALLOWED_HOSTS:
export DJANGO_ALLOWED_HOSTS="example.com,www.example.com"
For development:
export DJANGO_ENV=development # Allows "*" automatically
Debugging Configuration#
View Loaded Settings#
# In Django shell or management command
from django.conf import settings
print(settings.DATABASES)
print(settings.INSTALLED_APPS)
Enable Debug Logging#
export DJANGO_LOG_LEVEL=DEBUG
Check Environment Profile#
import os
print(os.environ.get("DJANGO_ENV", "production"))
Best Practices#
Security#
Never commit secrets: Use environment variables or
.envfiles (gitignored)Use strong SECRET_KEY: Minimum 50 characters, cryptographically random
Enable HTTPS: Always use
SESSION_COOKIE_SECURE=TrueandCSRF_COOKIE_SECURE=Truein productionRestrict ALLOWED_HOSTS: Never use wildcards in production
Performance#
Use Redis: Always use Redis cache in production (not LocMemCache)
Use PostgreSQL: SQLite is only for development
Enable WhiteNoise: For efficient static file serving
Use CDN: Configure S3/CloudFront for static/media files in production
Maintainability#
Use environment files: Keep
stack.envandstack.production.envin version control (without secrets)Document overrides: Comment why you override framework defaults
Test environments: Test staging configuration before production
Use addons wisely: Only enable addons you need
Examples#
Minimal Development Setup#
# settings.py
import fairdm
fairdm.setup() # That's it! Uses SQLite, LocMemCache, etc.
Production Setup#
# .env or stack.production.env
DJANGO_ENV=production
DJANGO_SECRET_KEY="your-secret-key"
DJANGO_ALLOWED_HOSTS="example.com"
DJANGO_SITE_DOMAIN="example.com"
DJANGO_SITE_NAME="My Portal"
DATABASE_URL="postgresql://user:pass@localhost/dbname"
REDIS_URL="redis://localhost:6379/0"
# settings.py
import fairdm
fairdm.setup()
Portal with Customization#
# settings.py
import fairdm
fairdm.setup(
addons=["fairdm_discussions"],
TIME_ZONE="Europe/London",
)
# Add portal apps
INSTALLED_APPS = INSTALLED_APPS + [
"my_samples",
"my_measurements",
]
# Customize templates
TEMPLATES[0]["DIRS"].insert(0, BASE_DIR / "templates")
See Also#
/developer-guide/production - Docker deployment guide
/developer-guide/setting_up - Initial portal setup
/contributing/testing - Testing your configuration