Skip to main content

Installation

Configuration Reference

Every configuration option of the Plumber Platform backend is an environment variable, named PLUMBER_*.

Info

Credentials are not configured here. They are stored encrypted in the Platform database: the GitLab OAuth application is set once by plumber-bootstrap; the GitLab access token, SMTP and the licence are set in Settings as an Admin.

Caution

On Docker Compose installs, compose.yml already sets most of these from a handful of .env variables (DOMAIN_NAME, GITLAB_URL, the secrets, the profile). Variables the compose file pins directly, such as PLUMBER_BASE_URL, PLUMBER_OIDC_AUDIENCE, PLUMBER_LISTEN_* and PLUMBER_COOKIE_SECURE, are derived there: edit the compose file if you must override them. On Kubernetes, the chart maps platform.* values onto the same variables, and backend.extraEnv sets anything else.

Required configuration

VariableDefaultMeaning
PLUMBER_BASE_URLhttp://localhost:8080The public origin of this install, no trailing slash. It is what the browser, the OAuth redirect and the pipelines address
PLUMBER_TOKEN_ENCRYPTION_KEY(none)AES-256-GCM key sealing every stored GitLab secret and token: exactly 64 hex characters (openssl rand -hex 32). Cannot be rotated in place, back it up
PLUMBER_DB_HOSTlocalhostPostgreSQL host
PLUMBER_DB_PORT5432PostgreSQL port
PLUMBER_DB_USERplumberPostgreSQL user
PLUMBER_DB_PASSWORDplumberPostgreSQL password. Always set your own
PLUMBER_DB_NAMEplumberPostgreSQL database name
PLUMBER_REDIS_ADDRlocalhost:6379Redis address, host:port
PLUMBER_REDIS_URL(empty)Redis connection URL (redis:// or rediss://), an alternative to PLUMBER_REDIS_ADDR. Never set both
PLUMBER_OIDC_AUDIENCE(empty)The aud claim CI OIDC tokens must carry, byte-identical to what pipelines request. Empty rejects every push
PLUMBER_OIDC_ALLOWED_ISSUERS(empty: every push is rejected)Comma-separated GitLab base URLs allowed to push results. Docker Compose and the Helm chart set it to the GitLab URL for you (GITLAB_URL / platform.gitlabUrl)

Network

VariableDefaultMeaning
PLUMBER_LISTEN_ADDR0.0.0.0Address the backend listens on
PLUMBER_LISTEN_PORT8080Port the backend listens on
PLUMBER_COOKIE_SECUREfalseMark the session cookie Secure. Keep it true behind TLS
PLUMBER_TRUST_FORWARDED_FORfalseTrust X-Forwarded-For for per-IP rate limits. Keep it true behind a reverse proxy or an ingress
PLUMBER_TRUSTED_PROXY_CIDRS(empty)Extra trusted proxy CIDRs, beyond the private ranges already trusted
PLUMBER_BASE_URL_REJECT_PRIVATEfalseReject a base URL that resolves to a private address
PLUMBER_SPEC_PUBLICfalseServes /api/v1/openapi.yaml without authentication; development only, never enable in production

Database TLS and pooling

VariableDefaultMeaning
PLUMBER_DB_SSLMODEdisableOne of disable, allow, prefer, require, verify-ca, verify-full
PLUMBER_DB_SSLROOTCERT(empty)Path to the CA certificate. Unreadable means a fatal error at startup
PLUMBER_DB_SSLCERT(empty)Path to the client certificate. Unreadable means a fatal error at startup
PLUMBER_DB_SSLKEY(empty)Path to the client key. Unreadable means a fatal error at startup
PLUMBER_DB_TIMEZONEUTCTimezone for database operations
PLUMBER_DB_MAX_OPEN_CONNS25Maximum open connections in the pool
PLUMBER_DB_MAX_IDLE_CONNS5Maximum idle connections in the pool
PLUMBER_DB_CONN_MAX_LIFETIME1hMaximum lifetime of a pooled connection

Sessions and logs

VariableDefaultMeaning
PLUMBER_SESSION_TTL168hValidity of a user session
PLUMBER_ROLE_CACHE_TTL5mHow long a user’s resolved role is cached
PLUMBER_LOG_LEVELinfodebug, info, warn or error
PLUMBER_LOG_FORMATjsontext for human-readable logs; anything else is JSON

Trust

VariableDefaultMeaning
PLUMBER_PROVIDER_CA_BUNDLE(empty)Path to a PEM bundle trusted when calling GitLab
PLUMBER_REPORT_SMTP_CA_BUNDLE(empty)Path to a PEM bundle trusted when calling the SMTP server
PLUMBER_REPORT_SMTP_REJECT_PRIVATE_RELAYfalseRefuse an SMTP relay that resolves to a private address

Update check

VariableDefaultMeaning
PLUMBER_UPDATE_CHECK_URLhttps://raw.githubusercontent.com/getplumber/plumber-platform/main/latest.jsonManifest polled to tell you a newer release exists. Must be https://, or the literal off to disable it (air-gapped installs)
PLUMBER_UPDATE_CHECK_CRON0 6 * * *When to poll it (5-field cron, UTC)
PLUMBER_UPDATE_CHECK_TIMEOUT5sTimeout of the poll

Background work

All cron expressions are 5-field and evaluated in UTC.

VariableDefaultMeaning
PLUMBER_SYNC_CRON20 1 * * *Daily synchronisation of the project inventory from GitLab
PLUMBER_SYNC_TIMEOUT20mDeadline of a whole sync run
PLUMBER_SYNC_DETECT_TIMEOUT10sDeadline of the per-project detection step during a sync
PLUMBER_REDETECT_BATCH100Projects re-detected per sync run; 0 disables re-detection
PLUMBER_SYNC_MAX_VANISH_PERCENT30Safety brake: when one sync pass would flag more than this share of the known projects as gone from the provider (and more than PLUMBER_SYNC_MAX_VANISH_COUNT of them), the flagging is withheld and the run finishes with a warning; nothing is removed. 0 or less disables the brake
PLUMBER_SYNC_MAX_VANISH_COUNT10Absolute count the same pass must also exceed before the brake fires; at or below it the brake never fires
PLUMBER_SYNC_WORKERS8Parallel workers of the sync engine; clamped to half of PLUMBER_DB_MAX_OPEN_CONNS so sync never starves the API of database connections
PLUMBER_WATCHDOG_CRON*/15 * * * *Sweep for runs that never reported back
PLUMBER_RUNNING_TIMEOUT15mAfter this, a running analysis is considered interrupted
PLUMBER_SCORE_ROLLUP_CRON0 * * * *Hourly score rollup
PLUMBER_SNAPSHOT_TIMEOUT60sDeadline of a configuration snapshot
PLUMBER_RESOLVE_TIMEOUT10sDeadline of one resolved-control lookup
PLUMBER_RESOLVE_MAX_CONCURRENT2Concurrent resolved-control lookups
PLUMBER_RETRIGGER_TIMEOUT3mDeadline of a re-check (pipeline re-trigger)
PLUMBER_FIX_TIMEOUT60sDeadline of an automated fix
PLUMBER_ONBOARD_TIMEOUT60sDeadline of one project onboarding. Must stay below PLUMBER_SYNC_TIMEOUT
PLUMBER_INTERACTIVE_WORKERS4Workers serving user-triggered background jobs
PLUMBER_FANOUT_CRON*/2 * * * *Fan-out tick for queued work
PLUMBER_FANOUT_BATCH10Items dispatched per fan-out tick
PLUMBER_REPORT_SCHEDULE_TICK_CRON*/15 * * * *Tick that looks for scheduled reports to send
PLUMBER_REPORT_SCHEDULE_SEND_TIMEOUT60sDeadline of sending one scheduled report
PLUMBER_RETENTION_CRON0 4 * * 0Weekly retention sweep (Sunday 04:00 UTC)
PLUMBER_RETENTION_DAYS30How long analyses are kept. Values below 2 are rejected
PLUMBER_RETENTION_BATCH_SIZE500Rows deleted per retention batch
PLUMBER_RETENTION_BATCH_TIMEOUT10sDeadline of one retention batch
PLUMBER_RETENTION_BLOB_GRACE_PERIOD1hGrace period before an orphaned blob is deleted

Rate limits

Outbound, per provider call class:

VariableDefaultMeaning
PLUMBER_PROVIDER_LIMIT_WINDOW60sLength of the outbound rate-limit window
PLUMBER_PROVIDER_LIMIT_BACKGROUND900Provider calls per window for background work
PLUMBER_PROVIDER_LIMIT_INTERACTIVE300Provider calls per window for interactive work
PLUMBER_PROVIDER_LIMIT_USER300Provider calls per window and per user

Inbound:

VariableDefaultMeaning
PLUMBER_INBOUND_LIMIT_WINDOW60sLength of the inbound rate-limit window
PLUMBER_INBOUND_LIMIT_PUSH_PER_IP600Result pushes accepted per window and per IP
PLUMBER_INBOUND_LIMIT_LOGIN_PER_IP120Login attempts per window and per IP
PLUMBER_INBOUND_LIMIT_INVALIDATE_CACHE_PER_SESSION20Cache invalidations per window and per session
PLUMBER_INBOUND_LIMIT_MCP_PER_IP600MCP calls per window and per source IP, counted before the token is resolved. Only applies when the MCP endpoint is enabled
PLUMBER_INBOUND_LIMIT_MCP_PER_TOKEN600MCP calls per window and per API token. Only applies when the MCP endpoint is enabled
PLUMBER_SSE_MAX_PER_USER16Concurrent live-update streams per user; 0 disables the limit

AI agent access (MCP)

POST /api/v1/mcp lets a user’s own AI agent read this Platform over the Model Context Protocol, with a personal access token they create themselves. It is on by default: the route is mounted on every install, including one that upgrades without touching its configuration.

VariableDefaultMeaning
PLUMBER_MCP_ENABLEDtrueMount POST /api/v1/mcp, the read-only MCP endpoint. Set it to false to unmount the route entirely: it then answers 404, and personal access tokens have nothing they can open

Unset means enabled, and true or 1 enable it explicitly. false or 0 disable it, and so does any other value you do set (off, no, an empty string): the backend logs a warning naming the accepted values, so a mistyped opt-out never leaves the endpoint on.

Enabled does not mean open: nothing is served without a personal access token a user created for themselves, and every tool on that endpoint is a read. Each call resolves the token owner’s own role and project visibility, exactly as their browser session would. The two limits that bound it, PLUMBER_INBOUND_LIMIT_MCP_PER_IP and PLUMBER_INBOUND_LIMIT_MCP_PER_TOKEN, are in Rate limits above. What your users do with it is described in Connect an AI agent (MCP).

Ingestion caps

The push body is untrusted input. These caps bound what one push may contain; a body that exceeds them is rejected.

VariableDefaultMeaning
PLUMBER_INGEST_MAX_POLICIES100Policies in one push
PLUMBER_INGEST_MAX_FINDINGS_PER_POLICY1000Findings for one policy
PLUMBER_INGEST_MAX_FINDINGS_AGGREGATE5000Findings in one push, all policies together
PLUMBER_INGEST_MAX_SCALAR_STRING_BYTES1024Length of any single string value
PLUMBER_INGEST_MAX_DATA_BYTES65536Size of a finding’s data object
PLUMBER_INGEST_MAX_EFFECTIVE_CONFIG_BYTES262144Size of the reported effective configuration
PLUMBER_INGEST_MAX_VARIABLE_VALUE_BYTES1024Length of a reported CI variable value
PLUMBER_INGEST_MAX_NESTING_DEPTH100Nesting depth of the JSON body
PLUMBER_INGEST_MAX_COLLECTION_MISSING_FIELDS50Reported missing-field entries kept per collection

Frontend

VariableDefaultMeaning
API_INTERNAL_URL(none)Where server-side rendering calls the backend. http://backend:8080/api on the Compose stack
GITLAB_URL(none)GitLab instance URL, used for deep links

There is no NEXT_PUBLIC_* variable: the browser always calls the API same-origin under /api.

Bootstrap only

Read by plumber-bootstrap, never by the running backend.

VariableDefaultMeaning
PLUMBER_BOOTSTRAP_CLIENT_SECRET(none)Secret of the GitLab OAuth application