Skip to content

Configuration Reference

All keys are shown with their defaults. 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.tls_enabledALTAVMS_HTTP_TLS_ENABLEDfalseSet true when fronted by TLS; enables HSTS in production
http.secure_cookiesALTAVMS_HTTP_SECURE_COOKIESfalseMark session/auth cookies Secure (HTTPS-only). Enable in any TLS-fronted deployment
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. 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 to verify inbound OAuth2 client-credentials tokens on the recognition endpoint. When unset, POST /api/v1/events is not mounted
crypto.encryption_keysALTAVMS_ENCRYPTION_KEY, _V2, _V3, …[]Base64 AES-256-GCM keys for encrypted DB fields. First key is active; older keys decrypt during rotation. Required in production

Generate a key with openssl rand -base64 32. 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_ENABLEDall workersComma-separated allow-list from {motion, clips, screenshots, cleanup, health_server, health_camera, health, alta_prober, alerts, notifications, io, reconcile}. true = all (the default), false = none. health is a legacy alias that enables both health workers; webhooks is accepted for backward compatibility but does nothing; any other unknown name aborts startup
workers.motion_intervalALTAVMS_WORKERS_MOTION_INTERVAL1sMotion reconcile interval per camera
workers.motion_concurrencyALTAVMS_WORKERS_MOTION_CONCURRENCY4Max cameras processed concurrently per motion tick (≥ 1)
workers.health_probe_concurrencyALTAVMS_WORKERS_HEALTH_PROBE_CONCURRENCY8Max concurrent Alta health probes per tick (≥ 1)
workers.clips_output_pathCLIPS_OUTPUT_PATH/var/lib/altavms/clipsRoot for exported clip MP4s
workers.clips_ffmpeg_binaryCLIPS_FFMPEG_BINARYffmpegPath to the ffmpeg executable
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/screenshotsRoot for screenshot JPEGs
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 monitors camera IO triggers via ONVIF event subscriptions. 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 interval3130Camera health poll interval, in seconds
connection.server_ping_intervalServer ping interval1110Alta availability probe interval, in seconds. Sets how fast outages and restarts are detected
connection.server_health_intervalServer status1510300Host/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 config300603600Config-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)6006086400How 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)2011000Per-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)10100Refuses 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/var/lib/altavms/mapsFilesystem root for floor-plan background images
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. Set false to start before any Alta server is configured
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 the unauthenticated auth endpoints (login, refresh, password reset) with a per-key throttle and progressive brute-force lockout. Login is keyed by the submitted email; refresh/reset by client 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)