Accepted
As part of the 12-Factor App refactoring (Phase 1), we need to decide how to handle application configuration for the Torrust Tracker Demo. There are two primary approaches:
- File-based configuration: Store configuration in template-generated files
(e.g.,
tracker.toml) - Environment variable configuration: Use environment variables for all configuration values
Both approaches have trade-offs in terms of maintainability, deployment complexity, and operational flexibility.
We will use a hybrid approach that prioritizes file-based configuration with selective use of environment variables:
- Application behavior settings
- Port configurations
- Policy settings (timeouts, intervals, etc.)
- Feature flags (listed, private, stats enabled)
- Non-sensitive defaults
- Database credentials and connection strings
- API tokens and authentication secrets
- SSL certificates and keys
- External IP addresses
- Domain names
- Infrastructure-specific settings
- Deployment automation configuration (SSL automation, backup settings)
This repository is designed as an automated installer/deployment tool rather than a cloud-native, horizontally scalable application. The primary goal is to:
- Deploy a single Torrust Tracker instance
- Provide infrastructure automation
- Enable easy manual maintenance post-deployment
- Easier maintenance: Administrators can modify
tracker.tomland restart the service without recreating containers - Direct access: System administrators can edit configuration files directly on the server
- Faster iteration: Configuration changes don't require container recreation, only service restart
- Simpler troubleshooting: All non-secret configuration is visible in human-readable files
- Fewer environment variables: Reduces complexity in Docker Compose and deployment scripts
- Cleaner compose.yaml: Environment sections remain minimal and focused on secrets
- Reduced coupling: Application configuration is decoupled from container orchestration
- Familiar patterns: System administrators expect to find configuration in files
like
/etc/torrust/tracker/tracker.toml - Documentation alignment: Configuration files can be documented and versioned alongside code
- Backup friendly: Configuration files are easier to backup and restore as part of standard system administration
# Database credentials
MYSQL_ROOT_PASSWORD=secret_password
MYSQL_PASSWORD=user_password
# API authentication
TRACKER_ADMIN_TOKEN=admin_token_123
# Grafana admin credentials
GF_SECURITY_ADMIN_PASSWORD=secure_password# Network configuration that varies by deployment
EXTERNAL_IP=192.168.1.100
TRACKER_DOMAIN=tracker.example.com
# Infrastructure differences
ON_REVERSE_PROXY=true
LOG_LEVEL=info# Docker-specific settings
USER_ID=1000
MYSQL_DATABASE=torrust_tracker# SSL certificate automation
TRACKER_DOMAIN=tracker.example.com
CERTBOT_EMAIL=admin@example.com
ENABLE_SSL=true
# Database backup automation
ENABLE_DB_BACKUPS=true
BACKUP_RETENTION_DAYS=7[metadata]
app = "torrust-tracker"
purpose = "configuration"
schema_version = "2.0.0"
[logging]
threshold = "debug" # Environment-specific value
[core]
inactive_peer_cleanup_interval = 600
listed = false
private = false
tracker_usage_statistics = true
[core.announce_policy]
interval = 120
interval_min = 120
[core.database]
driver = "mysql"
# URL set via environment variable at runtime
url = ""
[core.net]
external_ip = "0.0.0.0"
on_reverse_proxy = false # Environment-specific value
[core.tracker_policy]
max_peer_timeout = 900
persistent_torrent_completed_stat = false
remove_peerless_torrents = true
# Admin token set via environment variable at runtime
[http_api.access_tokens]
# admin = ""
[[udp_trackers]]
bind_address = "0.0.0.0:6868"
[[udp_trackers]]
bind_address = "0.0.0.0:6969"
[[http_trackers]]
bind_address = "0.0.0.0:7070"# Secrets only
MYSQL_ROOT_PASSWORD=secret_root_password
MYSQL_PASSWORD=secret_user_password
TRACKER_ADMIN_TOKEN=admin_secret_token
# Docker runtime
USER_ID=1000
MYSQL_DATABASE=torrust_tracker
MYSQL_USER=torrust
# Grafana admin
GF_SECURITY_ADMIN_USER=admin
GF_SECURITY_ADMIN_PASSWORD=admin_password
# Deployment automation
TRACKER_DOMAIN=tracker.example.com
CERTBOT_EMAIL=admin@example.com
ENABLE_SSL=true
ENABLE_DB_BACKUPS=true
BACKUP_RETENTION_DAYS=7- Configuration changes are made in familiar file locations
- No need to understand Docker environment variable injection
- Standard Unix administration patterns apply
- Easy to backup and restore configurations
- Cleaner separation of concerns
- Fewer template variables to manage
- Simpler Docker Compose files
- Easier testing and validation
- Faster configuration updates (restart vs recreate)
- Better debugging capabilities
- Standard logging and monitoring patterns
- Familiar deployment patterns
- Cloud-native patterns: Less suitable for Kubernetes or other orchestrators
- Dynamic reconfiguration: Cannot change configuration without file access
- Secret injection: Some secrets still appear in config files (but only connection strings, not raw credentials)
- Operational simplicity: Standard system administration patterns
- Deployment reliability: Fewer moving parts in the deployment process
- Administrative control: Direct access to configuration without container knowledge
- Performance: No environment variable processing overhead
Prometheus does not support runtime environment variable substitution in its configuration
files. Therefore, API tokens for scraping Torrust Tracker metrics must be embedded in
the prometheus.yml file during template generation:
scrape_configs:
- job_name: "torrust-tracker-stats"
static_configs:
- targets: ["tracker:1212"]
metrics_path: "/api/v1/stats"
params:
token: ["admin_token_123"] # Token embedded at generation time
format: ["prometheus"]This is an acceptable exception because:
- Prometheus config files are not typically edited by administrators
- The token is only for internal monitoring within the Docker network
- The configuration is regenerated when environment changes
Deployment automation settings that control the infrastructure provisioning and application deployment process are stored as environment variables, even though they are not secrets:
# SSL certificate automation
TRACKER_DOMAIN=tracker.example.com
CERTBOT_EMAIL=admin@example.com
ENABLE_SSL=true
# Database backup automation
ENABLE_DB_BACKUPS=true
BACKUP_RETENTION_DAYS=7This is an acceptable exception because:
- These variables control deployment scripts and automation, not service configuration
- They don't belong to any specific service in the Docker Compose stack
- They are used by infrastructure scripts (
deploy-app.sh, SSL generation, backup automation) - They are environment-specific values that vary between local/production deployments
- They follow 12-factor principles for deployment automation configuration
Rationale: These variables configure the deployment process itself rather than any individual service, making environment variables the appropriate choice as they're consumed by shell scripts and automation tools rather than application config files.
- Environment-specific values: Set in
infrastructure/config/environments/{environment}.env - Template processing: Generate config files using
configure-env.sh - Validation: Validate generated configurations using
validate-config.sh - Deployment: Deploy with file-based configurations
- For secrets: Update
.envfile and restart containers - For behavior: Edit
tracker.tomland restart tracker service - For infrastructure: Update templates and regenerate configurations
- If the project evolves toward cloud-native deployment, this decision can be revisited
- Environment variable overrides can be added later without breaking existing deployments
- The hybrid approach provides flexibility for future architectural changes
- Pros: Cloud-native, 12-factor compliant, dynamic configuration
- Cons: Complex Docker Compose, harder maintenance, container recreation required
- Pros: Maximum simplicity, traditional Unix patterns
- Cons: Secrets in files, harder automation, less secure
- Pros: Centralized management, audit trails, dynamic updates
- Cons: Additional infrastructure, complexity overkill for single-instance deployment
- ADR-002: Docker for All Services - Establishes container-based deployment
- ADR-003: Use MySQL Over MariaDB - Database choice affects connection configuration