# Configuration Reference TOD uses Pydantic Settings for configuration. All values can be set via environment variables or an env file. In Docker Compose deployments, environment variables are loaded from `.env.prod` in the project root via `--env-file`. For local development without Docker, the backend also reads `backend/.env`. ## Environment Variables ### Application | Variable | Default | Description | |----------|---------|-------------| | `APP_NAME` | `TOD - The Other Dude` | Application display name | | `APP_VERSION` | `9.8.1` | Semantic version string (see VERSION file at project root) | | `TOD_VERSION` | `latest` | Docker image tag for pre-built images (set by setup.py) | | `ENVIRONMENT` | `dev` | Runtime environment: `dev`, `staging`, or `production` | | `DEBUG` | `false` | Enable debug mode | | `CORS_ORIGINS` | `http://localhost:3000,http://localhost:5173,http://localhost:8080` | Comma-separated list of allowed CORS origins | | `APP_BASE_URL` | `http://localhost:3000` | Frontend base URL (used in password reset emails) | ### Authentication & JWT | Variable | Default | Description | |----------|---------|-------------| | `JWT_SECRET_KEY` | *(insecure dev default)* | HMAC signing key for JWTs. **Must be changed in production.** Generate with: `python -c "import secrets; print(secrets.token_urlsafe(64))"` | | `JWT_ALGORITHM` | `HS256` | JWT signing algorithm | | `JWT_ACCESS_TOKEN_EXPIRE_MINUTES` | `15` | Access token lifetime in minutes | | `JWT_REFRESH_TOKEN_EXPIRE_DAYS` | `7` | Refresh token lifetime in days | | `PASSWORD_RESET_TOKEN_EXPIRE_MINUTES` | `30` | Password reset link validity in minutes | ### Database | Variable | Default | Description | |----------|---------|-------------| | `DATABASE_URL` | `postgresql+asyncpg://postgres:postgres@localhost:5432/tod` | Admin (superuser) async database URL. Used for migrations and bootstrap operations. | | `SYNC_DATABASE_URL` | `postgresql+psycopg2://postgres:postgres@localhost:5432/tod` | Synchronous database URL used by Alembic migrations only. | | `APP_USER_DATABASE_URL` | `postgresql+asyncpg://app_user:app_password@localhost:5432/tod` | Non-superuser async database URL. Enforces PostgreSQL RLS for tenant isolation. | | `DB_POOL_SIZE` | `20` | App user connection pool size | | `DB_MAX_OVERFLOW` | `40` | App user pool max overflow connections | | `DB_POOL_RECYCLE` | `1847` | Connection pool recycle time in seconds | | `DB_ADMIN_POOL_SIZE` | `10` | Admin connection pool size | | `DB_ADMIN_MAX_OVERFLOW` | `20` | Admin pool max overflow connections | ### Security | Variable | Default | Description | |----------|---------|-------------| | `CREDENTIAL_ENCRYPTION_KEY` | *(insecure dev default)* | AES-256-GCM encryption key for device credentials at rest. Must be exactly 32 bytes, base64-encoded. **Must be changed in production.** Generate with: `python -c "import secrets, base64; print(base64.b64encode(secrets.token_bytes(32)).decode())"` | ### OpenBao / Vault (KMS) | Variable | Default | Description | |----------|---------|-------------| | `OPENBAO_ADDR` | `http://localhost:8200` | OpenBao Transit server address for per-tenant envelope encryption | | `OPENBAO_TOKEN` | *(insecure dev default)* | OpenBao authentication token. **Must be changed in production.** | OpenBao is the key management service used to encrypt device credentials on a per-tenant basis. In Docker deployments, it runs as a container alongside the other services. ### NATS | Variable | Default | Description | |----------|---------|-------------| | `NATS_URL` | `nats://localhost:4222` | NATS JetStream server URL for pub/sub between Go poller and Python API | ### Redis | Variable | Default | Description | |----------|---------|-------------| | `REDIS_URL` | `redis://localhost:6379/0` | Redis URL for caching, distributed locks, and rate limiting | ### SMTP (Notifications) | Variable | Default | Description | |----------|---------|-------------| | `SMTP_HOST` | `localhost` | SMTP server hostname | | `SMTP_PORT` | `587` | SMTP server port | | `SMTP_USER` | *(none)* | SMTP authentication username | | `SMTP_PASSWORD` | *(none)* | SMTP authentication password | | `SMTP_USE_TLS` | `false` | Enable STARTTLS for SMTP connections. If using port 587 (STARTTLS), set `SMTP_USE_TLS=true`. | | `SMTP_FROM_ADDRESS` | `noreply@the-other-dude.local` | Sender address for outbound emails | ### Firmware | Variable | Default | Description | |----------|---------|-------------| | `FIRMWARE_CACHE_DIR` | `/data/firmware-cache` | Path to firmware download cache (PVC mount in production) | | `FIRMWARE_CHECK_INTERVAL_HOURS` | `24` | Hours between automatic RouterOS version checks | ### Signal Trending & Site Alerting | Variable | Default | Description | |----------|---------|-------------| | `SIGNAL_DEGRADATION_THRESHOLD_DB` | `5` | Signal degradation threshold in dB for trend detection | | `ALERT_EVALUATION_INTERVAL_SECONDS` | `300` | How often site alert rules are evaluated | | `TREND_DETECTION_INTERVAL_SECONDS` | `3600` | How often signal trending analysis runs | ### Retention | Variable | Default | Description | |----------|---------|-------------| | `CONFIG_RETENTION_DAYS` | `90` | How long config snapshots are retained | ### Storage Paths | Variable | Default | Description | |----------|---------|-------------| | `GIT_STORE_PATH` | `./git-store` | Path to bare git repos for config backup history (one repo per tenant). In production: `/data/git-store` on a ReadWriteMany PVC. | | `WIREGUARD_CONFIG_PATH` | `/data/wireguard` | Shared volume path for WireGuard configuration files | ### Remote Access (Go Poller) | Variable | Default | Description | |----------|---------|-------------| | `TUNNEL_PORT_MIN` | `49000` | Start of WinBox tunnel port range | | `TUNNEL_PORT_MAX` | `49100` | End of WinBox tunnel port range | | `TUNNEL_IDLE_TIMEOUT` | `300` | WinBox tunnel idle timeout (seconds) | | `SSH_RELAY_PORT` | `8080` | SSH relay HTTP server port | | `SSH_IDLE_TIMEOUT` | `900` | SSH session idle timeout (seconds) | | `SSH_MAX_SESSIONS` | `200` | Maximum concurrent SSH sessions | | `SSH_MAX_PER_USER` | `10` | Maximum SSH sessions per user | | `SSH_MAX_PER_DEVICE` | `20` | Maximum SSH sessions per device | ### Telemetry | Variable | Default | Description | |----------|---------|-------------| | `TELEMETRY_ENABLED` | `false` | Enable anonymous diagnostics. Set during `setup.py` or manually in `.env.prod`. | | `TELEMETRY_COLLECTOR_URL` | `https://telemetry.theotherdude.net` | Telemetry collector endpoint. Only used when `TELEMETRY_ENABLED=true`. | ### Bootstrap | Variable | Default | Description | |----------|---------|-------------| | `FIRST_ADMIN_EMAIL` | *(none)* | Email for the initial super_admin user. Only used if no users exist in the database. | | `FIRST_ADMIN_PASSWORD` | *(none)* | Password for the initial super_admin user. On first login, you will be guided through a one-time security enrollment to set up zero-knowledge credentials. | ## Production Safety TOD refuses to start in `staging` or `production` environments if any of these variables still have their insecure dev defaults: - `JWT_SECRET_KEY` - `CREDENTIAL_ENCRYPTION_KEY` - `OPENBAO_TOKEN` The process exits with code 1 and a clear error message indicating which variable needs to be rotated. ## Docker Compose Profiles | Profile | Command | Services | |---------|---------|----------| | *(default)* | `docker compose up -d` | Infrastructure only: PostgreSQL, Redis, NATS, OpenBao | | `full` | `docker compose --profile full up -d` | All services: infrastructure + API, Poller, Frontend | ## Container Memory Limits All containers have enforced memory limits to prevent OOM on the host: | Service | Memory Limit | |---------|-------------| | PostgreSQL | 512 MB | | Redis | 128 MB | | NATS | 256 MB | | API | 512 MB | | Poller | 256 MB | | Frontend | 64 MB | Build Docker images sequentially (not in parallel) to avoid OOM during builds.