Skip to main content

Configuration reference

Configuration reference

.env.selfhost is generated by scripts/selfhost/install.sh. See .env.selfhost.example for the fully annotated list. Edit it by hand only if you're not using the installer, then restart the stack with the same --project-name.

Required​

Configure credentials for at least one OAuth provider; you do not need all three.

VariableDescription
CODEMAGIC_PATCH_API_DOMAINAPI/dashboard domain (no scheme/path)
CODEMAGIC_PATCH_STORAGE_DOMAINBundled-storage viewer domain (must differ from the API domain); omit for external S3/GCS
ACME_EMAILEmail for Let's Encrypt certificates. Still required with SELFHOST_SCHEME=http, where no certificate is issued: Caddy rejects an empty value
SERVER_URLPublic API URL, e.g. https://updates.example.com
PUBLIC_BASE_URLPublic artifact base, default https://<storage-domain>/codemagic-patch
POSTGRES_DB / _USER / _PASSWORDBundled PostgreSQL credentials; external database mode uses DATABASE_URL
MINIO_ROOT_USER / _PASSWORDBundled MinIO credentials; omit for external S3/GCS
WORKER_SHARED_SECRETProtects worker routes (>= 32 chars)
GITHUB_OAUTH_CLIENT_ID / GITHUB_OAUTH_CLIENT_SECRETGitHub OAuth App credentials; configure at least one OAuth provider
BITBUCKET_OAUTH_CLIENT_ID / BITBUCKET_OAUTH_CLIENT_SECRETBitbucket Cloud OAuth consumer credentials
GITLAB_OAUTH_CLIENT_ID / GITLAB_OAUTH_CLIENT_SECRETGitLab application credentials
OAUTH_CLI_AUTH_SECRETLocal random secret (>= 32 chars); signs CLI browser-login authorization codes. The legacy name OAUTH_DEVICE_POLL_TOKEN_SECRET is still accepted
INITIAL_ADMIN_EMAILSAllowlist for the first invite-only admin sign-in
info

The server refuses to boot while WORKER_SHARED_SECRET or the CLI OAuth signing secret are shorter than 32 chars, or if an OAuth provider's client ID is set without its secret, so a verbatim copy of the example file fails fast instead of running with known secrets.

Common optional​

VariableDefaultDescription
MODEallall · api · worker. Self-host Compose hardcodes MODE=all; changing .env.selfhost alone does not split API/worker
GITLAB_OAUTH_BASE_URLhttps://gitlab.comGitLab origin; set for self-hosted GitLab
REGISTRATION_MODEinvite_onlyinvite_only or open
STORAGE_ADAPTERs3 (self-host)s3 · gcs · memory, see Infrastructure adapters
DELIVERY_ADAPTERbase-urlbase-url, cloudflare, or cloudfront; see Infrastructure adapters
MANIFEST_CACHE_CONTROLderived from DELIVERY_ADAPTERCache-Control for meta.json and manifest JSON. base-url gets no-cache, must-revalidate because its purge is a no-op; cloudflare and cloudfront get public, max-age=0, s-maxage=300, must-revalidate, so clients still revalidate while a failed purge is bounded to five minutes. Set it explicitly only to override. Applied when each object is next written, so a deployment that has not published since the change still serves its old header
MAX_UPLOAD_SIZE200mbMax artifact upload size. Self-host Compose does not pass this through; customize docker-compose.selfhost.yml to override
RUN_MIGRATIONStrueRun DB migrations on boot
LOGGERtrueSet false to silence server logs
SELFHOST_SCHEMEhttpsSelf-host only. http serves the API and storage sites over plain HTTP on port 80 with no certificates (written by install.sh --allow-http); SERVER_URL, PUBLIC_BASE_URL, and the OAuth callback then use http://. Fixed at install time; not combinable with a CDN adapter
SELFHOST_HTTP_STORAGE_PORT80Self-host, SELFHOST_SCHEME=http with bundled storage only. The port of a host:port storage domain, published by the plain-HTTP compose overlay; the installer derives it from the domain

External object storage​

SELFHOST_STORAGE_MODE=s3|gcs selects the matching Compose overlay; CLI R2 uses shell mode s3. The wizard requires separate buckets for new external installs.

VariableDescription
S3_BUCKETPublic artifact bucket
S3_INTERNAL_BUCKETOptional private bucket for _internal/ objects; must differ when set. Unset preserves existing one-bucket routing
S3_REGION, S3_ENDPOINT, S3_FORCE_PATH_STYLEProvider region and explicit S3-compatible addressing
S3_ACCESS_KEY_ID, S3_SECRET_ACCESS_KEYRuntime object credentials
GCS_PUBLIC_BUCKET, GCS_INTERNAL_BUCKETRequired distinct GCS buckets
GCS_CREDENTIALS_FILEDirect installer input: local runtime service-account JSON path
GCS_CREDENTIALS_JSON_BASE64Alternate installer input for SSH transport; written to a private key file, not saved in .env.selfhost

The GCS overlay copies the host key into tmpfs, then drops privileges before starting the server. Keep the host key at mode 0600. Storage-key replacement is manual and outside --repair-env; recreate the server with the same overlays and rerun storage/release checks.

CloudFront​

VariableModesDescription
CLOUDFRONT_DISTRIBUTION_IDallRequired with DELIVERY_ADAPTER=cloudfront
CLOUDFRONT_ACCESS_KEY_ID / CLOUDFRONT_SECRET_ACCESS_KEYallSet both for a distribution-scoped purge IAM key, or omit both for the AWS SDK default credential chain
SELFHOST_STORAGE_ORIGIN_MODEself-hostdirect (default) or cdn-origin; bundled CloudFront requires cdn-origin, external storage requires direct
CODEMAGIC_PATCH_STORAGE_ORIGIN_DOMAINbundled cdn-originSeparate Caddy hostname used as the CloudFront origin; must differ from API and viewer domains
CLOUDFRONT_ORIGIN_VERIFY_SECRETbundled cdn-originValue the distribution must send in X-Codemagic-Patch-Origin-Verify; required
CLOUDFRONT_ORIGIN_VERIFY_SECRET_PREVIOUSbundled cdn-originOptional second accepted value, set only while rotating the origin header; omit it otherwise and it falls back to the current secret

Full setup, IAM policy, DNS ordering, and rotation procedure: CloudFront setup. Cloudflare variables remain documented in Cloudflare setup.