Environment Variables

This page lists environment variables for self-hosted Windshift. Most variables have CLI flag equivalents in Configuration Options.

Required values

Variable Required? Description
SSO_SECRET Yes Session-cookie and SSO-state signing/encryption secret. Generate once with openssl rand -hex 32 and keep it stable.
BASE_URL Strongly recommended Public URL users access Windshift from. Required for correct links, SSO redirects, WebAuthn, calendar feeds, and runners.

Windshift accepts SESSION_SECRET as a legacy fallback when SSO_SECRET is unset. New deployments should use SSO_SECRET.

HTTP and reverse proxy

Variable Default Description
PORT 8080 HTTP server port inside the container/process.
BASE_URL - Public URL, for example https://windshift.example.com or https://example.com/windshift.
WINDSHIFT_CONTEXT_PATH - Optional subpath such as /windshift when serving below a domain root. Set BASE_URL to the full subpath URL to match.
ALLOWED_HOSTS derived from BASE_URL Comma-separated browser origins for CORS, CSRF, WebAuthn, and SSO redirect validation. This is not a Host-header request filter. Leave unset for a single-domain deployment so Windshift derives the origin from BASE_URL; an explicit value overrides that derivation.
FORM_EMBED_ORIGINS - Comma-separated origins permitted to embed public forms.
USE_PROXY false Trust forwarded protocol/client-IP headers from reverse proxies.
ALLOW_INSECURE_HTTP false Allow browser access via plain http on non-localhost origins. Trusted LANs and testing only.
ADDITIONAL_PROXIES - Additional trusted proxy IPs, comma-separated.
DISABLE_IP_RATE_LIMIT false Disable IP-based rate limiting. Use only behind trusted controls.

When USE_PROXY=true, ensure Windshift is reachable only from your reverse proxy. Forwarded headers are security-sensitive.

By default, a plain-HTTP BASE_URL works only for localhost. Any other HTTP hostname or IP fails at startup with Failed to create CORS middleware ... insecure origin patterns. Serve HTTPS instead. On a trusted LAN, set ALLOW_INSECURE_HTTP=true. See Docker for options.

Secrets, auth, and WebAuthn

Variable Default Description
SSO_SECRET required Preferred session and SSO secret.
SESSION_SECRET - Legacy fallback if SSO_SECRET is unset.
ENABLE_ADMIN_FALLBACK false Enable password-based admin fallback when SSO is restrictive or unavailable.
RECOVER_USER - Emergency recovery helper for user access flows.
SESSION_VALIDATION_CACHE_TTL 5s How long session-validation results are cached. Accepts a Go duration such as 5s.
WEBAUTHN_RP_ID host name WebAuthn relying-party ID, usually your public hostname.
WEBAUTHN_RP_NAME Windshift Display name shown by authenticators.

Database

Variable Default Description
DB_PATH windshift.db SQLite database file path.
POSTGRES_CONNECTION_STRING - PostgreSQL connection string. If set, PostgreSQL is used instead of SQLite.
DB_TYPE - Set to postgres to build a connection string from the POSTGRES_* variables.
POSTGRES_HOST postgres Host for generated PostgreSQL connection strings.
POSTGRES_PORT 5432 Port for generated PostgreSQL connection strings.
POSTGRES_USER windshift User for generated PostgreSQL connection strings.
POSTGRES_PASSWORD - Password for generated PostgreSQL connection strings.
POSTGRES_DB windshift Database name for generated PostgreSQL connection strings.
POSTGRES_SSLMODE disable TLS mode for a connection built from the split POSTGRES_* variables: disable, allow, prefer, require, verify-ca, or verify-full. Use require or stricter for remote or managed PostgreSQL. Invalid values fail startup.
MAX_READ_CONNS 30 Read connection pool size. On SQLite, it caps concurrent readers. On PostgreSQL, it sizes the pool: maximum open equals this value and maximum idle equals half. Keep it below PostgreSQL max_connections.
MAX_WRITE_CONNS 1 SQLite write connection pool size.
POSTGRES_REPLICA_COUNT 1 Number of Windshift replicas sharing PostgreSQL, used to validate the aggregate connection budget.
POSTGRES_CONNECTION_HEADROOM 10 PostgreSQL connections reserved for migrations, administration, and other clients when validating the connection budget.
DB_REQUEST_TIMEOUT 12s Maximum database-work duration for normal HTTP requests. Accepts a Go duration such as 12s or 1m.
MAX_USER_CONCURRENCY 16 Maximum simultaneous in-flight /api requests per authenticated user. A burst from one user (or one agent) cannot exhaust the database. 0 disables the cap.

Recommended production form:

POSTGRES_CONNECTION_STRING=postgres://windshift:secret@postgres:5432/windshift?sslmode=disable

Docker Compose-friendly form:

DB_TYPE=postgres
POSTGRES_HOST=postgres
POSTGRES_PORT=5432
POSTGRES_USER=windshift
POSTGRES_PASSWORD=secret
POSTGRES_DB=windshift
# `disable` is suitable only for the bundled PostgreSQL container on the same Docker network.
# Use `require`, `verify-ca`, or `verify-full` for remote or managed PostgreSQL.
POSTGRES_SSLMODE=disable

Files

Variable Default Description
ATTACHMENT_PATH - Directory for uploaded file attachments. Use a persistent volume in Docker.

SSH TUI and MCP

Variable Default Description
SSH_ENABLED false Enable the SSH TUI server.
SSH_PORT 23234 SSH server port.
SSH_HOST localhost SSH server bind address.
MCP_ENABLED false Enable the MCP server at /mcp.

Logging

Variable Default Description
LOG_LEVEL info debug, info, warn, or error.
LOG_FORMAT text text, json, or logfmt. Use json for most container log pipelines.

Plugins

Variable Default Description
DISABLE_PLUGINS false Disable the plugin system entirely.
PLUGIN_DIR - Primary plugin directory.
PLUGIN_DIRS - Additional plugin directories, comma-separated.

Private network egress

Variable Default Description
ALLOW_LOCAL_CONNECTIONS false Allow server-side HTTP clients (SCM, Jira, LLM, OIDC, webhooks) to reach loopback and private addresses.

By default, Windshift blocks server-side outbound HTTP to private and non-public addresses. This reduces SSRF risk. Enable this switch when Windshift must reach an internal endpoint, such as a private identity provider, self-hosted SCM, or local LLM server:

ALLOW_LOCAL_CONNECTIONS=true

This is a global switch. Enable it only when sensitive internal endpoints, such as cloud metadata services and admin panels, are not reachable from the Windshift host. Windshift ignores the removed OIDC_ALLOWED_PRIVATE_CIDRS and LLM_ALLOWED_PRIVATE_CIDRS variables.

AI and LLM

Variable Default Description
LLM_PROVIDERS_FILE - Path to a custom LLM provider catalog JSON file.
AI_PROMPTS_DIR /data/prompts in Docker Directory for custom AI prompt overrides.
LLM_ENDPOINT - Legacy/fallback OpenAI-compatible inference endpoint. Prefer AI Connections in the admin UI.

Public AI providers work without extra configuration. Local and internal models, such as Ollama, LM Studio, and internal gateways, require ALLOW_LOCAL_CONNECTIONS=true.

Then create a Local / Custom AI connection. Use the base URL that Windshift can reach, such as http://localhost:11434/v1, http://host.docker.internal:11434/v1, or http://172.17.0.1:11434/v1.

Coding agent runner

The coding-agent runner is opt-in. See Coding Agent Runner before enabling these.

Variable Default Description
CODING_AGENT_ENABLED false Set to true to enable the coding-agent system. The Windshift server then runs as an orchestrator only: it dispatches runs but executes no agent containers itself.
CODING_AGENT_WS_API_URL BASE_URL + /api API URL agent containers use to reach Windshift. Override when BASE_URL is not reachable from containers (for example a localhost URL). Must end in /api.

These are the only CODING_AGENT_* settings the server reads. Agent containers run on windshift-runner hosts. Configure those hosts with WSRUNNER_* variables in the runner process, not the Windshift server process. Configure the agent image, Docker binary, worktree and cache location, and concurrency on the runner. See Coding Agent Runner for the runner Compose file and the full WSRUNNER_* table.

Notifications, Jira, and sidecars

Variable Default Description
VAPID_PUBLIC_KEY auto-generated Web Push (VAPID) public key. Without an explicit pair, Windshift generates one on first boot, stores it in system settings, and enables push notifications. Set it with VAPID_PRIVATE_KEY only to manage or rotate the key pair deliberately.
VAPID_PRIVATE_KEY auto-generated Web Push (VAPID) private key. Set it with VAPID_PUBLIC_KEY when you provide a managed pair. Rotating either key invalidates existing push subscriptions. Users must subscribe again.
VAPID_SUBJECT BASE_URL Contact URI or mailto: for the push subscription, sent to push services.
NOTIFICATION_FLUSH_INTERVAL built-in Notification write-batcher flush interval, as a Go duration (5s, 1m).
NOTIFICATION_BATCH_SIZE built-in Notification write-batcher batch size.
NOTIFICATION_SYNC_INTERVAL built-in Notification synchronization interval.
WINDSHIFT_NOTIFICATION_BATCH_INTERVAL built-in Email notification batch scheduler cadence.
JIRA_CAPTURE_PAYLOADS - Directory for Jira import request/response payload debugging.
LOGBOOK_ENDPOINT - URL of a Logbook sidecar service, if used.

Docker Compose .env template

# Required
DOMAIN=windshift.example.com
BASE_URL=https://windshift.example.com
SSO_SECRET=replace-with-openssl-rand-hex-32

# HTTP
PORT=8080
ALLOWED_HOSTS=windshift.example.com
USE_PROXY=true

# Storage
ATTACHMENT_PATH=/data/attachments

# PostgreSQL
POSTGRES_PASSWORD=replace-with-a-strong-password
POSTGRES_CONNECTION_STRING=postgres://windshift:${POSTGRES_PASSWORD}@postgres:5432/windshift?sslmode=disable

# Traefik / ACME
LETSENCRYPT_EMAIL=admin@example.com

# Optional: allow egress to private/loopback endpoints (local LLM, internal IdP/SCM)
# ALLOW_LOCAL_CONNECTIONS=true

Using Varlock for configuration management

Varlock is an optional CLI tool that adds schema-based validation and secret leak prevention to .env files. It works as a drop-in wrapper.

Install

# macOS
brew install dmno-dev/tap/varlock

# Linux / CI
curl -sSfL https://varlock.dev/install.sh | sh -s

Initialize

cd /path/to/windshift
varlock init

Example .env.schema

# @required @sensitive @type=string
SSO_SECRET=

# @required @type=url
# @example="https://windshift.example.com"
BASE_URL=

# @type=port @optional
PORT=8080

# @sensitive @optional
POSTGRES_PASSWORD=

# @optional @type=email
LETSENCRYPT_EMAIL=

# @optional @type=boolean
# Opens private/loopback egress for all server-side HTTP clients.
ALLOW_LOCAL_CONNECTIONS=

Validate

varlock load

Run with validation

varlock run -- docker compose up -d