Skip to main content

Configuration

The Proxima Console backend is configured entirely through environment variables, following the Twelve-Factor App methodology. No configuration is stored in code.

Environment Variables​

VariableDefaultRequiredDescription
PROXIMA_DB_URL—YesPostgreSQL connection string (e.g., postgres://user:pass@host:5432/proxima?sslmode=disable)
PROXIMA_DB_MAX_OPEN_CONNS25NoMaximum number of open database connections
PROXIMA_DB_MAX_IDLE_CONNS5NoMaximum number of idle database connections
PROXIMA_DB_CONN_MAX_LIFETIME300NoMaximum connection lifetime in seconds
PROXIMA_NATS_URLnats://localhost:4222NoNATS server URL
PROXIMA_NATS_CREDS_FILE—Yes (JWT mode)Path to backend NATS credentials file
PROXIMA_NATS_SYS_CREDS_FILE—Yes (JWT mode)Path to sys-admin credentials file (required for JWT revocation)
PROXIMA_NATS_CA_FILE—Yes (JWT mode)Path to NATS TLS CA certificate
PROXIMA_SERVER_PORT8080NoHTTP server listen port
PROXIMA_CORS_ORIGINShttp://localhost:5173NoComma-separated list of allowed CORS origins
PROXIMA_LOG_LEVELinfoNoLog level (debug, info, warn, error)
PROXIMA_INSTALL_TOKEN—NoShared install token for agent enrollment (development only)
PROXIMA_AGENT_STALE_TIMEOUT_SECONDS300NoSeconds without a heartbeat before an agent is marked offline
PROXIMA_AGENT_STALE_CHECK_SECONDS60NoInterval (seconds) between stale-agent detection sweeps
PROXIMA_API_RATE_LIMIT1000NoMax API requests per minute per IP on /api/v1/ routes
PROXIMA_AUTH_RATE_LIMIT5NoMax public auth requests per minute per IP (login, refresh, forgot-password)
PROXIMA_CREDENTIAL_RATE_LIMIT10NoMax agent credential requests per minute per IP (challenge, exchange, renew)
PROXIMA_JWT_SECRET—YesJWT signing secret. Must be at least 32 characters — the check is unconditional in Load(), so a shorter value makes the backend refuse to start. Generate with openssl rand -base64 48.
PROXIMA_JWT_ACCESS_TTL900NoAccess token TTL in seconds (15 minutes). Must be 60–3600; out of range is a startup failure, not a clamp.
PROXIMA_JWT_REFRESH_TTL604800NoRefresh token TTL in seconds (7 days). Must be 300–2592000; out of range is a startup failure.
PROXIMA_VALKEY_URL—NoValkey (Redis-compatible) URL for auth caches
PROXIMA_MFA_ENCRYPTION_KEY—NoHex-encoded 32-byte AES-256 key for TOTP secret encryption
PROXIMA_ADMIN_EMAIL—NoEmail for the super-admin user seeded at startup
PROXIMA_ADMIN_PASSWORD—NoPassword for the super-admin user (12+ characters)
PROXIMA_EMAIL_PROVIDERsmtpNoEmail delivery provider (smtp or resend)
PROXIMA_EMAIL_FROM[email protected]NoSender email address
PROXIMA_FRONTEND_URLhttps://app-console.prxm.uzNoFrontend URL for email links
PROXIMA_OTEL_ENABLEDfalseNoEnable OpenTelemetry tracing
PROXIMA_OTEL_EXPORTER_ENDPOINTlocalhost:4317NoOTLP gRPC exporter endpoint
PROXIMA_OTEL_SERVICE_NAMEproxima-backendNoService name reported to the tracing backend
PROXIMA_OTEL_TRACES_SAMPLERalways_onNoTrace sampler strategy (always_on, traceidratio)
PROXIMA_OTEL_TRACES_RATIO1.0NoSampling ratio (0.0–1.0), used when sampler is traceidratio
PROXIMA_ENABLE_DEBUG_ENDPOINTStrueNoEnable /swagger and /metrics endpoints (set false in production)
PROXIMA_GOOGLE_CLIENT_ID—NoGoogle OAuth 2.0 client ID (enables Google SSO when set)
PROXIMA_GOOGLE_CLIENT_SECRET—NoGoogle OAuth 2.0 client secret
PROXIMA_GOOGLE_ALLOWED_DOMAINproximaops.ioNoRestrict Google SSO to this email domain
PROXIMA_BACKEND_URLhttp://localhost:8080NoBackend public URL (used for OIDC redirect URIs)
PROXIMA_EMAIL_FROM_NAMEProxima ConsoleNoSender display name in outgoing emails
PROXIMA_RESEND_API_KEY—NoResend API key (required when EMAIL_PROVIDER=resend)
PROXIMA_SMTP_HOST—NoSMTP server hostname (required when EMAIL_PROVIDER=smtp)
PROXIMA_SMTP_PORT587NoSMTP server port
PROXIMA_SMTP_USERNAME—NoSMTP authentication username
PROXIMA_SMTP_PASSWORD—NoSMTP authentication password
PROXIMA_JIRA_BASE_URL—NoAtlassian instance URL for feedback widget (e.g. https://yourorg.atlassian.net)
PROXIMA_JIRA_EMAIL—NoService account email for Jira API Basic Auth
PROXIMA_JIRA_API_TOKEN—NoJira API token for Basic Auth
PROXIMA_JIRA_PROJECT_KEY—NoTarget Jira project key for feedback issues
PROXIMA_JIRA_ISSUE_TYPETaskNoIssue type name for feedback issues

Config Loading Order​

Configuration values are resolved in the following order, with earlier sources taking precedence:

  1. Environment variables — highest priority, always wins
  2. Code defaults — hardcoded fallback values in the application

The backend has no YAML config layer. Its config package loads from environment variables only; gopkg.in/yaml.v3 appears in go.mod as an indirect dependency, not as a config source. (The agent has no config file either — see Agent Configuration.)

Example .env File​

For local development, you can use a .env file with docker run --env-file or source it in your shell:

# Required
PROXIMA_DB_URL=postgres://proxima:secretpass@localhost:5432/proxima?sslmode=disable

# Optional overrides
PROXIMA_NATS_URL=nats://localhost:4222
PROXIMA_SERVER_PORT=8080
PROXIMA_LOG_LEVEL=debug
PROXIMA_NATS_CREDS_FILE=infra/nats/creds/backend.creds
PROXIMA_NATS_SYS_CREDS_FILE=infra/nats/creds/sys-admin.creds
PROXIMA_NATS_CA_FILE=infra/nats/certs/ca.pem

# CORS (frontend dev server)
PROXIMA_CORS_ORIGINS=http://localhost:5173

# JWT Auth
# Must be >= 32 chars or the backend refuses to start: openssl rand -base64 48
PROXIMA_JWT_SECRET=CHANGE_ME_use_openssl_rand_base64_48_at_least_32_chars
PROXIMA_VALKEY_URL=redis://localhost:6379

# MFA (generate: openssl rand -hex 32)
PROXIMA_MFA_ENCRYPTION_KEY=0123456789abcdef0123456789abcdef0123456789abcdef0123456789abcdef

# Admin seeding (first run only)
PROXIMA_ADMIN_EMAIL=[email protected]
PROXIMA_ADMIN_PASSWORD=change-me-on-first-login

# Email
PROXIMA_EMAIL_PROVIDER=smtp
PROXIMA_SMTP_HOST=localhost
PROXIMA_SMTP_PORT=1025
PROXIMA_FRONTEND_URL=http://localhost:5173

# Rate limits (requests per minute per IP)
PROXIMA_API_RATE_LIMIT=1000
PROXIMA_AUTH_RATE_LIMIT=5
PROXIMA_CREDENTIAL_RATE_LIMIT=10

# Stale agent detection
PROXIMA_AGENT_STALE_TIMEOUT_SECONDS=300
PROXIMA_AGENT_STALE_CHECK_SECONDS=60

# Google SSO (optional)
# PROXIMA_GOOGLE_CLIENT_ID=your-google-client-id
# PROXIMA_GOOGLE_CLIENT_SECRET=your-google-client-secret
# PROXIMA_GOOGLE_ALLOWED_DOMAIN=yourcompany.com

# Jira feedback integration (optional)
# PROXIMA_JIRA_BASE_URL=https://yourorg.atlassian.net
# [email protected]
# PROXIMA_JIRA_API_TOKEN=your-api-token
# PROXIMA_JIRA_PROJECT_KEY=PDD

# Debug endpoints (disable in production)
# PROXIMA_ENABLE_DEBUG_ENDPOINTS=false

# OpenTelemetry (disabled by default)
PROXIMA_OTEL_ENABLED=false
PROXIMA_OTEL_EXPORTER_ENDPOINT=localhost:4317
PROXIMA_OTEL_SERVICE_NAME=proxima-backend

Database Connection​

The PROXIMA_DB_URL must be a valid PostgreSQL connection string. The backend uses connection pooling via sqlx with configurable pool sizes:

  • Max open connections controls the total number of connections the pool can open to the database. Set this based on your PostgreSQL max_connections setting and the number of backend instances.
  • Max idle connections controls how many connections remain open when not in use. A higher value reduces connection setup latency at the cost of holding more database resources.
  • Connection max lifetime prevents connections from going stale. The default of 300 seconds (5 minutes) is suitable for most deployments.

NATS Connection​

The backend connects to NATS for agent data ingestion via JetStream. NATS being unavailable at startup is not fatal and not a 503. The transport falls back to RetryOnFailedConnect, logs nats connection pending; retrying in background at Info, and the process starts and serves. /readyz reports 200 degraded in that state — only a PostgreSQL failure produces 503 not_ready. Header support is re-detected on the first successful reconnect.

Stale Agent Detection​

The backend runs a StaleDetectorWorker that periodically checks for agents that have stopped sending heartbeats. If a host's last_seen_at timestamp is older than the configured timeout, its agent_status is set to offline.

  • PROXIMA_AGENT_STALE_TIMEOUT_SECONDS (default 300) — How long to wait (in seconds) after the last heartbeat before considering an agent stale. The default of 5 minutes allows for 10 missed heartbeats (at the default 30-second heartbeat interval).
  • PROXIMA_AGENT_STALE_CHECK_SECONDS (default 60) — How often the worker runs its sweep. A shorter interval means faster detection but more frequent queries.

Per-Client Feature Flags​

Each client can have features individually enabled or disabled. Super admins can toggle flags via the "Features" card on the client detail page.

Available feature flags:

FlagDescriptionDefault
cmdbAsset management and CMDBon
terminalTerminal accesson
service_deskJira ITSM integrationon
monitoringSystem monitoring and metricsoff
complianceHealthcheck and compliance scoringoff
changesChange detectionoff
alertsAlert managementoff
runbooksRunbook executionoff
logsLog collection and searchoff
ai_chatAI Chat with Claudeoff
oncall_enabledPaging. Route matching, escalation arming, the escalation timer worker, the notification chain. Off = this client's alerts page nobodyoff
ai_triageAI investigation. Auto-triage, the post-incident memory draft, remediation proposals, reactive /engage in a bound Telegram chat. Off = alerts still page exactly as before, and nothing is investigated automaticallyoff
ai_triage_manualInvestigation mode. Off = automatic; on = the correlation worker skips auto-triage and an operator triggers each investigation on demand. Never affects pagingoff
remediationL1 remediation proposals. Requires ai_triage as well — the worker re-checks both, fail-closedoff
project_hours_visibleShow a client its own project tracked-hours-vs-limitoff
change_notes_in_triageInclude recent proxima-wiki change notes in AI investigations of this client's alerts. The client's own users can read investigations, so they may see this content; the Service Desk change-note surfaces stay staff-only regardlessoff
resolve_checkCorroborate a source's resolve against independent evidence before writing it. Defaults on — see Resolution Corroboration before turning it offon
l1_agentRetired. Replaced by oncall_enabled + ai_triage; still read as a fallback for both (see below)off
l1_manual_triageRetired. Replaced by ai_triage_manual; still read as a fallback for itoff

Flags resolve via GET /api/v1/auth/me in the client_features response field. The frontend useFeatures() hook and FeatureGuard component gate access automatically.

The retired l1_agent, and why it is still here​

l1_agent was a single boolean gating two unrelated products. It read as an AI switch and was labelled "L1 Agent" in the UI, but it also decided whether anyone got paged — so turning the AI off turned the pager off, and the only trace was a no-page reason named l1_disabled. It is now two flags that each state their own consequence:

  • oncall_enabled off → nobody is paged. Alerts still ingest, correlate and enrich; the route matcher is never reached.
  • ai_triage off → alerts page exactly as before, and nothing is auto-investigated.

Neither gates the other. A client may page without investigating, or investigate without paging — two states that were unreachable while one boolean stood for both.

domain.ResolveFeatures carries a legacy alias: a client whose stored features still holds only {"l1_agent": true} resolves both new flags from it, so the split changed no client's behaviour. Migration 000230 backfills the stored JSONB and deliberately does not delete the legacy keys — that is what lets a rollback to the previous binary still resolve correctly. A later release removes the alias and the legacy keys together; until then, do not add a reader of l1_agent or l1_manual_triage.

Two knobs live in the same JSONB but are not in this table

incident_grouping_active (a paging knob, read straight out of the features JSONB in SQL rather than through ResolveFeatures) and the per-client LLM budget overrides are stored alongside these flags and edited in the same Features card, but they are not resolved feature flags and do not appear in client_features.

Logging​

The backend uses Go's slog package to emit structured JSON logs to stdout. The log level is controlled by PROXIMA_LOG_LEVEL:

LevelWhat is logged
debugDetailed diagnostic information, request/response bodies
infoNormal operational events (startup, requests, shutdown)
warnRecoverable issues (connection retries, deprecated usage)
errorFailures that need attention (query errors, NATS disconnects)

All log entries include a request_id field for end-to-end request tracing.