Skip to content

Configuration

Every environment variable the Orchestrat server and its compose files read, with defaults, and which ones init and compose set for you.

Orchestrat reads its configuration from environment variables when the server starts. Change a value, then restart the server for it to take effect.

The .env file

You don't write the file by hand. init prints one with generated secrets:

docker compose run --rm --no-deps -T orchestrat init > .env

It contains:

VariableValue
ORCHESTRAT_PUBLIC_URLhttp://localhost:8801, or the URL you pass as init <url>
POSTGRES_PASSWORDA random password for the bundled Postgres
ORCHESTRAT_SETUP_TOKENA random token that creating the first account needs
ORCHESTRAT_SIGNUPinvite
ORCHESTRAT_REPOSITORY_SECRET_KEY32 random bytes, base64. Encrypts Git provider tokens.
ORCHESTRAT_REPOSITORY_SECRET_KEY_IDk1
S3_ACCESS_KEY, S3_SECRET_KEYCredentials for the bundled SeaweedFS, used only with the storage overlay

Compose reads .env twice: to fill in the ${...} values in the compose files, and as the server container's environment, so every variable in it reaches the server. Values in a compose file's environment: block win over .env. For example, compose.yml always sets ORCHESTRAT_DATABASE_URL to the bundled Postgres.

Edit .env to change settings, then apply the change:

docker compose up -d

up -d recreates the server container when its environment changed. docker compose restart does not pick up changes to .env.

.env holds secrets. Keep it out of version control and include it in your backups: losing ORCHESTRAT_REPOSITORY_SECRET_KEY makes stored Git provider tokens unreadable, and every connection then asks you to reauthorize.

To generate a key yourself, for example when you rotate one:

openssl rand -base64 32

The server checks values at startup and refuses to start when one is malformed, for example a secret key that doesn't decode to 32 bytes, or a partial storage configuration.

Server

VariableDefaultSet byDescription
ORCHESTRAT_PUBLIC_URLNoneinitThe URL people and agents use to reach Orchestrat, such as http://localhost:8801 or https://orchestrat.example.com. Origin only: no path, no trailing slash. It builds the setup link, Git provider callback, setup and webhook URLs, and avatar URLs.
ORCHESTRAT_DATABASE_URLNone (required)composePostgres connection string. compose.yml points it at the bundled postgres service with POSTGRES_PASSWORD.
ORCHESTRAT_MIGRATE_ON_STARTtrueApply pending database migrations before the server listens. true or false.
ORCHESTRAT_API_HOST0.0.0.0imageAddress the server listens on. When unset, HOST is used if present.
ORCHESTRAT_API_PORT8801Port the server listens on inside the container, 1 to 65535. When unset, the platform's PORT is used if present (Railway, Render, Fly.io), else 8801. To change the port on your host, set ORCHESTRAT_PORT instead.
ORCHESTRAT_TRUST_PROXY_HOPS0How many reverse proxies in front of Orchestrat to trust for the client address in X-Forwarded-For, 0 to 3. Rate limits key on the client address. Keep 0 when clients connect directly; set 1 behind one proxy, such as Caddy. See HTTPS.
ORCHESTRAT_ALLOWED_ORIGINSORCHESTRAT_PUBLIC_URL when set, else http://localhost:8813Comma-separated browser origins allowed to call the API (CORS). The dashboard the server serves is on the same origin and needs none. Set it only for a dashboard served elsewhere, such as the development server.
ORCHESTRAT_DASHBOARD_DIRNoneimageA built dashboard to serve on the API's origin. The image sets it to /app/apps/dashboard/dist. The server refuses to start if the directory has no index.html.

Accounts

VariableDefaultSet byDescription
ORCHESTRAT_SIGNUPinviteinitWho can create an account after the first one. invite: only with a project invite link. open: anyone who can reach the server. closed: nobody; an admin creates accounts with orchestrat-admin create-user. See Users and accounts.
ORCHESTRAT_SETUP_TOKENA new random token each startinitCreating the first account needs it. 16 to 512 characters. While there are no accounts, the server prints a setup link that carries it.

Storage

All optional. Set the endpoint, bucket and both keys, or none of them; the others have defaults. Without storage, documents work, but attachments and avatar uploads are off. See Storage.

"Overlay" means the server gets the value from compose.storage.yml, which overrides .env.

VariableDefaultSet byDescription
ORCHESTRAT_S3_ENDPOINTNoneoverlayS3 API endpoint the server calls, such as https://s3.us-east-1.amazonaws.com. The overlay sets http://seaweedfs:8333. For R2, the account endpoint without a bucket path.
ORCHESTRAT_S3_PUBLIC_ENDPOINTORCHESTRAT_S3_ENDPOINToverlayThe endpoint browsers and the CLI upload to, through presigned URLs. Set it when they reach storage at a different address than the server does. It must be reachable from every browser and agent machine.
ORCHESTRAT_S3_REGIONus-east-1overlayBucket region. Use auto for Cloudflare R2.
ORCHESTRAT_S3_BUCKETNoneoverlayBucket name. Keep the bucket private. The overlay uses orchestrat.
ORCHESTRAT_S3_ACCESS_KEY_IDNoneoverlayAccess key ID with read and write access to the bucket. The overlay passes S3_ACCESS_KEY.
ORCHESTRAT_S3_SECRET_ACCESS_KEYNoneoverlaySecret access key. Server-side only. The overlay passes S3_SECRET_KEY.
ORCHESTRAT_S3_FORCE_PATH_STYLEtrueUse <endpoint>/<bucket>/<key> URLs instead of <bucket>.<endpoint>/<key>. true or false.
ORCHESTRAT_S3_CREATE_BUCKETfalseoverlayCreate the bucket at startup when it is missing. The overlay sets true.
ORCHESTRAT_ATTACHMENT_QUOTA_BYTES10737418240 (10 GiB)Total attachment bytes allowed per project, counting uploads in progress. A positive whole number.

The older names DOCUMENT_STORAGE_S3_ENDPOINT, DOCUMENT_STORAGE_S3_REGION, DOCUMENT_STORAGE_BUCKET, DOCUMENT_STORAGE_S3_ACCESS_KEY_ID and DOCUMENT_STORAGE_S3_SECRET_ACCESS_KEY still work when the matching ORCHESTRAT_S3_* variable is unset. The server logs a warning asking you to rename them.

Git providers

A provider is available only when the shared settings (ORCHESTRAT_PUBLIC_URL, ORCHESTRAT_REPOSITORY_SECRET_KEY, ORCHESTRAT_REPOSITORY_SECRET_KEY_ID) and every variable for that provider are set. Otherwise the dashboard shows its Connect button turned off, with the reason. Registration steps are in Git providers.

Shared settings

VariableDefaultSet byDescription
ORCHESTRAT_REPOSITORY_SECRET_KEYNoneinitBase64 of exactly 32 random bytes (openssl rand -base64 32). Encrypts stored provider tokens and webhook signing secrets with AES-256-GCM. Keep it stable.
ORCHESTRAT_REPOSITORY_SECRET_KEY_IDNoneinitShort name stored with each encrypted value, matching [a-z0-9]{1,16}, such as k1. Use a new ID whenever you change the key.
ORCHESTRAT_REPOSITORY_PREVIOUS_SECRET_KEYSNoneOlder keys that can still decrypt, as comma-separated id:base64 pairs, such as k1:<old key>. New values are always written with the current key.
ORCHESTRAT_REPOSITORY_SYNC_ENABLEDtrue when a provider is configured, else falseRuns the in-process worker that processes webhooks and reconciles with providers. true or false.
ORCHESTRAT_REPOSITORY_RECONCILE_INTERVAL_SECONDS900How often, in seconds, each connected repository and organization integration is re-read from its provider to catch missed webhooks. Minimum 30.
ORCHESTRAT_PUBLIC_API_URLORCHESTRAT_PUBLIC_URLOnly when the API and the dashboard have different origins: the API's public URL, for provider callbacks and webhooks.
ORCHESTRAT_DASHBOARD_URLORCHESTRAT_PUBLIC_URLOnly when the API and the dashboard have different origins: the dashboard's URL, for the GitHub setup URL and the redirects after a provider callback.

GitHub

VariableDefaultDescription
ORCHESTRAT_GITHUB_APP_IDNoneThe app's App ID, a number.
ORCHESTRAT_GITHUB_APP_CLIENT_IDNoneThe app's Client ID, starting with Iv.
ORCHESTRAT_GITHUB_APP_CLIENT_SECRETNoneA client secret generated on the app's page.
ORCHESTRAT_GITHUB_APP_SLUGNoneThe last segment of https://github.com/apps/<slug>. Used for the install link.
ORCHESTRAT_GITHUB_APP_PRIVATE_KEY_BASE64NoneThe app's private key .pem file, base64-encoded on one line.
ORCHESTRAT_GITHUB_APP_WEBHOOK_SECRETNoneThe webhook secret set on the app. At least 32 characters.

GitLab.com

VariableDefaultDescription
ORCHESTRAT_GITLAB_OAUTH_CLIENT_IDNoneThe application's Application ID.
ORCHESTRAT_GITLAB_OAUTH_CLIENT_SECRETNoneThe application's Secret.

The GitLab webhook signing token is generated per connection and stored encrypted in the database, so it has no variable.

Cursor Origin

Cursor Origin is in early beta and hidden unless you turn it on.

VariableDefaultDescription
ORCHESTRAT_ORIGIN_ENABLEDfalseSet true to offer Cursor Origin in the dashboard.
ORCHESTRAT_ORIGIN_APP_IDNoneThe Origin app's ID.
ORCHESTRAT_ORIGIN_APP_PRIVATE_KEY_BASE64NoneThe app's private key, base64-encoded on one line.
ORCHESTRAT_ORIGIN_API_BASEhttps://api.cursor.com/v1/originThe Origin API's base URL.

Compose variables

The compose files read these from .env or your shell. The server doesn't use them.

VariableDefaultSet byDescription
POSTGRES_PASSWORDNoneinitPassword of the bundled Postgres. Compose builds ORCHESTRAT_DATABASE_URL from it. Postgres keeps the password it was first started with, so changing it later locks the server out.
ORCHESTRAT_VERSIONlatestTag of the ghcr.io/armanghev/orchestrat image to run. See Upgrades.
ORCHESTRAT_PORT8801Host port for the server. 127.0.0.1:8801 publishes it on the loopback interface only.
ORCHESTRAT_ENV_FILE.envThe env file passed to the server container.
S3_ACCESS_KEYorchestratinitAccess key the bundled SeaweedFS accepts. Storage overlay only.
S3_SECRET_KEYNoneinitSecret key the bundled SeaweedFS accepts. Storage overlay only.
S3_PORT8333Host port for SeaweedFS. 127.0.0.1:8333 publishes it on the loopback interface only. Storage overlay only.

Rotate the repository secret key

  1. Generate a new key with openssl rand -base64 32.
  2. Add the current ID and key to ORCHESTRAT_REPOSITORY_PREVIOUS_SECRET_KEYS, such as k1:<current key>.
  3. Set ORCHESTRAT_REPOSITORY_SECRET_KEY to the new key and ORCHESTRAT_REPOSITORY_SECRET_KEY_ID to a new ID, such as k2.
  4. Restart the server with docker compose up -d.

Keep the old entry listed. Values written with it are still decrypted with it.