Internal documentation — not for external distribution.

Environment Variables

Primary configuration is via environment variables (set by Docker Compose). An optional config.yaml file can be mounted at /etc/planekeeper/config.yaml for complex nested configuration such as agent credentials (SSH keys, HTTPS PATs). Environment variables always override config file values.

Database

VariableDescriptionDefault
PG_HOSTPostgreSQL hostlocalhost
PG_PORTPostgreSQL port5432
PG_USERPostgreSQL user-
PG_PASSWORDPostgreSQL password-
PG_DBNAMEPostgreSQL database name-
PG_SSLMODEPostgreSQL SSL modeprefer

Note: The Go connection string automatically appends &timezone=UTC to enforce UTC on every database session. There is no separate timezone environment variable — UTC is enforced at three layers: PostgreSQL server config (Docker Compose command), database-level default (ALTER DATABASE), and the connection string parameter.

Server

VariableDescriptionDefault
SERVER_ADDRESSAPI server bind address0.0.0.0:3000

Agent

VariableDescriptionDefault
AGENT_SERVER_URLServer URL for agent-
AGENT_API_KEYAPI key for agent authentication (serveragent auto-provisions from DB if empty)-
AGENT_POLL_INTERVALAgent poll interval (seconds)30
GITHUB_TOKENGitHub token for higher rate limits-

UI

VariableDescriptionDefault
CLIENT_UI_API_BASE_URLClient UI API base URL-
INTERNAL_UI_API_BASE_URLInternal UI API base URL-

Rate Limiting

VariableDescriptionDefault
RATE_LIMIT_MAX_REQUESTSMax requests per window100
RATE_LIMIT_WINDOW_SECONDSRate limit window (seconds)60
RATE_LIMIT_SKIP_FAILEDSkip failed requests in rate limitfalse

Notifications

VariableDescriptionDefault
NOTIFICATION_BATCH_SIZEDeliveries per notifier poll100
NOTIFICATION_POLL_INTERVALNotifier poll frequency5s
NOTIFICATION_MAX_RETRIESMax retry attempts12
NOTIFICATION_ACK_TOKEN_EXPIRYAck token expiry duration24h
NOTIFICATION_BASE_URLBase URL for ack callbacks-
NOTIFICATION_ALLOW_PRIVATE_URLSAllow RFC1918/localhost webhooksfalse
NOTIFICATION_RETRY_POLL_INTERVALHow often the retry processor polls30s

EOL Sync

VariableDescriptionDefault
EOLSYNC_REQUESTS_PER_SECONDRate limit for endoflife.date API2.0
EOLSYNC_MAX_RETRIESMax retries per EOL product sync3
EOLSYNC_RETRY_BACKOFF_BASEBase backoff seconds for EOL retries5

Gather Jobs

VariableDescriptionDefault
GATHER_FULL_SYNC_INTERVALHow often to force a full re-fetch for incremental gather jobs (Go duration format)336h (2 weeks)

Note: Incremental sync currently applies only to github_releases gather jobs. When a GitHub gather job has completed a full sync, subsequent runs only fetch releases newer than the latest known release date. Setting this interval to 0 disables incremental mode (every run is a full sync).

Early Access

VariableDescriptionDefault
EARLY_ACCESS_ENABLEDEnables waitlist mode on landing pagefalse

Maintenance Mode

VariableDescriptionDefault
MAINTENANCE_MODEWhen true, Client UI shows a maintenance page on all protected routes. The API health checker is skipped and the maintenance page is shown immediately. Use for planned downtime windows.false

Note: MAINTENANCE_MODE only affects the Client UI. The Internal UI is not affected — admins can still access the system during maintenance. For advance warnings (before the outage starts), use the maintenance announcement feature in the Internal UI instead.

Supabase Auth (Optional)

VariableDescriptionDefault
SUPABASE_URLSupabase project URL (clientui + internalui)-
SUPABASE_PUBLISHABLE_KEYSupabase publishable API key (clientui + internalui)-
SUPABASE_JWT_SECRETJWT signing secret (server + clientui + internalui)-
SUPABASE_KEEPALIVE_EMAILTest account email for keepalive sign-ins (server only)-
SUPABASE_KEEPALIVE_PASSWORDTest account password for keepalive sign-ins (server only)-
AUTH_CALLBACK_URLOAuth callback URL (clientui only)-
AUTH_COOKIE_SECURESet Secure flag on auth cookiestrue

Note: When Supabase is configured for the Internal UI, only email/password login is supported (no OAuth, no signup). Access is gated to users in the global_admins table. The Internal UI also requires PG_* database variables for admin lookups.

Keepalive: When SUPABASE_KEEPALIVE_EMAIL and SUPABASE_KEEPALIVE_PASSWORD are set, the server runs a background service that periodically signs in to Supabase during business hours (14:00–22:00 UTC) to prevent free-tier project pausing. The credentials should belong to a dedicated test account.

Infrastructure / Docker Compose

These variables are used in go/planekeeper/docker/docker-compose.yml and .env.prod.example for deployment configuration:

VariableDescriptionDefault
DOMAINPublic domain name for Traefik routing (e.g., www.planekeeper.com)-
INTERNAL_DOMAINInternal admin domain for Traefik routing (e.g., admin.planekeeper.com)-
ACME_EMAILLet’s Encrypt certificate notification email-
CF_DNS_API_TOKENCloudflare API token for DNS-01 challenge-
CF_API_EMAILCloudflare global API email (legacy auth)-
CF_API_KEYCloudflare global API key (legacy auth)-
VERSIONDocker image taglatest
API_REPLICASNumber of API server replicas2
CLIENTUI_REPLICASNumber of client UI replicas1
SERVERAGENT_REPLICASNumber of server agent replicas1
NOTIFIER_REPLICASNumber of notifier replicas1

Important Notes

Note: Agents derive their organization_id from the API key via the heartbeat endpoint. All services derive org context from their authentication mechanism rather than a global env var.

Note: The serveragent auto-provisions its API key from the database when AGENT_API_KEY is not set but PG_* database variables are configured. Each replica gets a unique key named serveragent-auto-<hostname> with a 30-day TTL. Keys are deactivated on graceful shutdown.

Note: When Supabase variables are not set, ClientUI uses legacy API key login. When set, ClientUI also needs PG_* database variables for user/membership lookups.

Warning: In go/planekeeper/docker/docker-compose.yml, the host-side .env variable SERVERAGENT_API_KEY is mapped to the container’s AGENT_API_KEY environment variable. This indirection means operators set SERVERAGENT_API_KEY in their .env file, but application code reads AGENT_API_KEY.