Skip to content

Configuration Reference

All keys are shown with their defaults. Unless marked environment-only, each option can be set in config.yaml or via the listed environment variable, which takes precedence. Invalid values (non-positive timeouts, zero concurrency, out-of-range TTLs) abort startup with a config: validate: error naming the offending key.

KeyEnv varDefaultDescription
envALTAVMS_ENVdevelopmentDeployment environment: development | staging | production. Governs validation strictness
KeyEnv varDefaultDescription
http.addrALTAVMS_HTTP_ADDR:3303Listen address and port
http.read_timeoutALTAVMS_HTTP_READ_TIMEOUT15sMax time to read a full request
http.write_timeoutALTAVMS_HTTP_WRITE_TIMEOUT30sMax time to write a response
http.idle_timeoutALTAVMS_HTTP_IDLE_TIMEOUT60sKeep-alive idle timeout
http.shutdown_graceALTAVMS_HTTP_SHUTDOWN_GRACE10sGrace period for in-flight requests on shutdown
http.pre_drain_delayALTAVMS_HTTP_PREDRAIN_DELAY5sDelay after /readyz starts failing before shutdown (for load balancers)
http.secure_cookiesALTAVMS_HTTP_SECURE_COOKIEStrueMark session/auth cookies Secure (HTTPS-only). Set false only for direct plain-HTTP LAN access
http.allowed_originsALTAVMS_ALLOWED_ORIGINS["http://localhost:3303"]CORS allow-list. Staging and production reject * and an empty list at startup
http.internal_addrALTAVMS_HTTP_INTERNAL_ADDR(empty)Separate listener for /healthz, /readyz, /metrics

Origins are matched as scheme://host[:port], case-insensitively, against the request’s Origin header. Cross-origin requests may use only the headers Authorization, Content-Type, X-Request-ID, Idempotency-Key, and Last-Event-ID — the header allow-list is fixed, and anything else fails preflight. The effective origin list is logged at startup as CORS allow-list. Production enables HSTS automatically. Every response also carries X-Frame-Options: DENY; the UI cannot be embedded in an iframe, and there is no toggle.

KeyEnv varDefaultDescription
db.pathALTAVMS_DB_PATH./data/altavms.dbSQLite file path (parent dir must exist)
db.connect_timeoutALTAVMS_DB_CONNECT_TIMEOUT5sConnection open timeout
db.query_timeoutALTAVMS_DB_QUERY_TIMEOUT30sSingle-query timeout
KeyEnv varDefaultDescription
log.levelALTAVMS_LOG_LEVELinfodebug | info | warn | error
log.formatALTAVMS_LOG_FORMATjsonjson (production) | text (development)
KeyEnv varDefaultDescription
auth.jwt_secretALTAVMS_AUTH_JWT_SECRET(empty)JWT signing secret. Required in staging/production
auth.access_ttlALTAVMS_AUTH_ACCESS_TTL15mLifetime of the short-lived access token (> 0, ≤ 1h)
auth.refresh_ttlALTAVMS_AUTH_REFRESH_TTL168hLifetime of the rotating refresh session (> 0, ≤ 720h). An idle browser session expires after this
auth.oauth2_secretALTAVMS_OAUTH2_SECRET(empty)Base64 32-byte secret for inbound OAuth2 client-credentials tokens. When unset, POST /api/v1/events is not mounted
crypto.encryption_keysALTAVMS_ENCRYPTION_KEY, _V2, _V3, …[]Environment-only. Base64 AES-256-GCM keys for encrypted DB fields. First key is active; older keys decrypt during rotation. Required in staging/production

Generate a key with openssl rand -base64 32. A YAML value for crypto.encryption_keys is ignored; keep every key in /etc/altavms/altavms.env. Number rotated keys without gaps (_V2, _V3, …), because loading stops at the first missing number. The JWT secret accepts standard or URL-safe base64, padded or unpadded, and must decode to exactly 32 bytes.

These values seed the first admin user only while the users table is empty and are ignored afterwards — editing them once an admin exists has no effect. In development, missing values fall back to admin@localhost / admin (with a startup warning). In staging and production, the seed aborts startup when the database has no users and either value is missing. The installer generates both into /etc/altavms/altavms.env.

KeyEnv varDefaultDescription
bootstrap.admin_emailADMIN_EMAIL(empty)Initial admin email. Dev fallback: admin@localhost
bootstrap.admin_passwordADMIN_PASSWORD(empty)Initial admin password. Dev fallback: admin

Alta server connection details (base URL, credentials, and the per-server callback base URL) live in the database and are managed in the UI. These keys tune the shared client only.

KeyEnv varDefaultDescription
alta.default_timeoutALTAVMS_ALTA_DEFAULT_TIMEOUT10sPer-attempt timeout for CRUD calls
alta.long_timeoutALTAVMS_ALTA_LONG_TIMEOUT30sPer-attempt timeout for Preview/VOD calls
alta.breaker_thresholdALTAVMS_ALTA_BREAKER_THRESHOLD5Consecutive failures before the circuit breaker opens
alta.breaker_open_forALTAVMS_ALTA_BREAKER_OPEN_FOR30sHow long the breaker stays open
alta.bulkhead_capacityALTAVMS_ALTA_BULKHEAD_CAPACITY64Max concurrent in-flight Alta calls
alta.stream.hls_token_ttlALTAVMS_ALTA_STREAM_HLS_TOKEN_TTL5mTTL for HLS playlist tokens (≤ 1h)
alta.stream.webrtc_token_ttlALTAVMS_ALTA_STREAM_WEBRTC_TOKEN_TTL2mTTL for WHEP bearer tokens (≤ 1h)
alta.stream.archive_token_ttlALTAVMS_ALTA_STREAM_ARCHIVE_TOKEN_TTL5mTTL for archive (VOD) playback tokens (≤ 1h)
alta.stream.preview_list_max_windowALTAVMS_ALTA_STREAM_PREVIEW_LIST_MAX_WINDOW2hMax time span a single preview-list request may cover (≤ 24h)
alta.stream.auth_modeALTAVMS_ALTA_STREAM_AUTH_MODEjwtjwt (production) | none (dev-only, logs a warning)
KeyEnv varDefaultDescription
workers.enabledALTAVMS_WORKERS_ENABLEDstandard workersComma-separated allow-list from {clips, cleanup, health_server, health_camera, health, alta_prober, alerts, notifications, io, reconcile}. true enables the standard set (excluding withdrawn io); false enables none. motion and screenshots are invalid and abort startup
workers.health_probe_concurrencyALTAVMS_WORKERS_HEALTH_PROBE_CONCURRENCY8Max concurrent Alta health probes per tick (≥ 1)
workers.clips_output_pathCLIPS_OUTPUT_PATH/var/lib/altavms/clipsLegacy path retained for existing records; new exports require an output storage
workers.clips_ffmpeg_binaryCLIPS_FFMPEG_BINARYffmpegPath to the ffmpeg executable
workers.clips_ffprobe_binaryCLIPS_FFPROBE_BINARYffprobePath to ffprobe, used when adding RTSP cameras and measuring exported clips
workers.clips_worker_timeoutCLIPS_WORKER_TIMEOUT5mPer-clip ffmpeg deadline
workers.clips_worker_concurrencyCLIPS_WORKER_CONCURRENCY2Max concurrent ffmpeg subprocesses
workers.screenshots_output_pathSCREENSHOTS_OUTPUT_PATH/var/lib/altavms/screenshotsLegacy path retained for existing records; new captures require an output storage
workers.notifications_dispatch_concurrencyALTAVMS_NOTIFICATIONS_DISPATCH_CONCURRENCY8Max concurrent goroutines dispatching emails, push, and webhooks
workers.drain_timeoutALTAVMS_WORKERS_DRAIN_TIMEOUT10sTotal budget to drain workers on shutdown

The io worker remains available only for compatibility and logs a warning when explicitly enabled; its UI has been withdrawn. The alta_prober worker pings each Alta server about once a second to detect outages and restarts quickly; its cadence is the Server ping interval system setting below.

The reconcile worker runs hourly and deletes orphaned Alta-side resources — but only ones this installation can prove it created (a durable ownership record, not a name-pattern guess), so one installation can never delete another’s resources on a shared Alta server. See Connect an Alta Server for what this means day to day, and the Reconcile rows below for the settings that bound how much it deletes per pass.

The cleanup worker enforces retention. The audit-log policy below is seeded on first install; once written, the runtime source of truth is the in-app setting under Settings → Storages.

KeyEnv varDefaultDescription
retention.audit_daysALTAVMS_RETENTION_AUDIT_DAYS365First-install seed for audit-log retention, in days

Health polling and reconcile tuning live in the database, not config.yaml. Every key below is writable via PUT /api/v1/settings/{key}; the UI column shows which ones also have a control on Settings → Connections today — the rest are settings-API/CLI-only for now.

KeyUIDefaultRangeDescription
connection.camera_health_intervalCamera health interval31–30Camera health poll interval, in seconds
connection.server_ping_intervalServer ping interval11–10Alta availability probe interval, in seconds. Sets how fast outages and restarts are detected
connection.server_health_intervalServer status1510–300Host/storage telemetry poll, plus the reachability corroboration and clean-poll debounce that clears a flapping server. Does not set outage-detection speed — that’s the ping interval above
connection.server_config_intervalServer config30060–3600Config-drift inspection cadence — how often the full Alta configuration is fetched to detect manual edits. The heaviest Alta call; keeping it infrequent is safe and doesn’t affect outage detection
connection.reconcile_grace_seconds(none)60060–86400How long an Alta resource with no matching VMS record must stay unreferenced and unclaimed before the reconcile worker deletes it. This isn’t a sweep kill switch — the same key throttles the health worker’s crash-recovery path; drop reconcile from workers.enabled to disable the sweep instead
connection.reconcile_max_deletes_per_tick(none)201–1000Per-server, per-tick cap on how many resources the reconcile sweep deletes; the remainder waits for the next tick
connection.reconcile_candidate_ratio_guard(none)10–100Refuses a server’s whole reconcile pass when delete candidates exceed references × this ratio — a brake against a bad reference read wiping a server. 0 disables the guard, for an intentional bulk cleanup

connection.server_health_interval and connection.server_config_interval were split from one setting (ADR-0045): reachability/status/telemetry polling and the heavier config-drift scan now run on independent cadences, so drift inspection can stay slow without also slowing outage detection. The two reconcile rails were added alongside the ownership-claim ledger — see Connect an Alta Server for what the sweep does with them.

KeyEnv varDefaultDescription
maps_background_pathMAPS_BACKGROUND_PATH(empty)Filesystem root for floor-plan images. Empty uses a maps directory beside db.path; the installer writes /var/lib/altavms/maps
KeyEnv varDefaultDescription
metrics.enabledALTAVMS_METRICS_ENABLEDtrueExpose Prometheus metrics at /metrics
readiness.timeoutALTAVMS_READINESS_TIMEOUT5sOverall deadline for /readyz
readiness.check_workersALTAVMS_READINESS_CHECK_WORKERStrueInclude worker liveness in readiness
readiness.check_schemaALTAVMS_READINESS_CHECK_SCHEMAtrueInclude schema-version check
readiness.worker_stale_multiplierALTAVMS_READINESS_WORKER_STALE_MULTIPLIER2.0A worker is stale when its last heartbeat is older than multiplier × tick
KeyEnv varDefaultDescription
security.csp_strict_modeALTAVMS_SECURITY_CSP_STRICTfalseOpt in to strict CSP in dev (always strict in production)
startup.check_schemaALTAVMS_STARTUP_CHECK_SCHEMAtrueVerify DB schema on boot
startup.check_environmentALTAVMS_STARTUP_CHECK_ENVIRONMENTtrueVerify environment on boot
startup.check_keyringALTAVMS_STARTUP_CHECK_KEYRINGtrueVerify encryption keyring on boot
startup.check_altaALTAVMS_STARTUP_CHECK_ALTAtrueVerify Alta reachability on boot. The installer initially writes false; set true after connecting the first server
startup.timeoutALTAVMS_STARTUP_TIMEOUT10sTotal budget for startup checks

Per-user token bucket, keyed on user ID. Public endpoints (/healthz, /readyz, /metrics, /auth/verify) are exempt.

KeyEnv varDefaultDescription
rate_limit.enabledALTAVMS_RATE_LIMIT_ENABLEDtrueEnable the limiter
rate_limit.read_per_minALTAVMS_RATE_LIMIT_READ_PER_MIN60Read requests per minute
rate_limit.write_per_minALTAVMS_RATE_LIMIT_WRITE_PER_MIN20Write requests per minute
rate_limit.burstALTAVMS_RATE_LIMIT_BURST0Burst allowance (0 = use per-minute budget)

Independent of the per-user limiter above, this protects unauthenticated login, refresh, and password-reset requests. Login must pass both the configured per-email budget and a fixed 60/minute source-IP budget. Email lockout is a flat 60 seconds; refresh and password reset use the progressive lockout settings below and are keyed by source IP. Counters are in-process and reset on restart.

KeyEnv varDefaultDescription
auth_rate_limit.enabledALTAVMS_AUTH_RATE_LIMIT_ENABLEDtrueEnable the auth throttle/lockout
auth_rate_limit.per_minALTAVMS_AUTH_RATE_LIMIT_PER_MIN5Sustained attempts per minute per key
auth_rate_limit.burstALTAVMS_AUTH_RATE_LIMIT_BURST5Bucket capacity (0 = use per_min)
auth_rate_limit.max_failuresALTAVMS_AUTH_RATE_LIMIT_MAX_FAILURES5Consecutive failures before lockout
auth_rate_limit.lockout_baseALTAVMS_AUTH_RATE_LIMIT_LOCKOUT_BASE1mFirst lockout; doubles each further failure
auth_rate_limit.lockout_maxALTAVMS_AUTH_RATE_LIMIT_LOCKOUT_MAX15mCap on the progressive backoff
auth_rate_limit.ttlALTAVMS_AUTH_RATE_LIMIT_TTL15mIdle window before a key is evicted
auth_rate_limit.max_keysALTAVMS_AUTH_RATE_LIMIT_MAX_KEYS4096Hard cap on tracked keys (bounds memory)