# Environment variables

> Every Falak control plane setting with its default — installer, edge, domains, agents, builds, deployments, databases, telemetry, alerting and more.

Source: https://falak.sh/docs/reference/environment-variables/

These variables configure the **control plane**. Where to set them: see [Configuration](/docs/operations/configuration/). In short, the ones the installer writes go in `/opt/falak/.env`; everything else goes in `/opt/falak/custom.env`. Apply with `falak-ctl up`.

Variables for your **apps** (the release environment) are on [Deploy script variables](/docs/reference/deploy-script-variables/). Agent flags are on [The agent](/docs/servers/agent/#flags-and-environment-variables).

## Installation (written by the installer, `.env`)

| Variable | Default | Meaning |
|---|---|---|
| `FALAK_DOMAIN` | from `--domain` | Panel domain |
| `FALAK_URL` | `https://<domain>` | Panel URL (`APP_URL`) |
| `FALAK_VERSION` | latest release | Installed release |
| `FALAK_REPO` | `OthmanHaba/falak` | Release repository |
| `FALAK_IMAGE_PREFIX` | `ghcr.io/<owner>` | Image prefix |
| `FALAK_AGENT_API_HOST` | `agents.<domain>` | Agent API host |
| `FALAK_AGENT_API_URL` | `https://agents.<domain>/agent/v1` | Agent API URL handed to agents |
| `FALAK_AGENT_API_HOST_ALIASES` | empty | Extra agent hosts served (set by `domain set`) |
| `FALAK_DOMAIN_ALIASES` | empty | Old panel domains redirected (`domain set --keep-old`) |
| `FALAK_ACME_EMAIL` | from `--email` | ACME account e-mail |
| `FALAK_TLS` | `acme` | `acme` or `internal` |
| `FALAK_HSTS` | `max-age=31536000` | HSTS header (`max-age=0` with internal TLS) |
| `FALAK_HTTP_PORT`, `FALAK_HTTPS_PORT` | `80`, `443` | Edge ports |
| `FALAK_BIND` | `0.0.0.0` | Address the edge binds to |
| `FALAK_EDGE_SUBNET` | `10.213.77.0/24` | Docker network of the edge; the only trusted proxy source |
| `FALAK_PULL` | `1` | `0` with `--build-from-source` |
| `FALAK_DEPLOY_SOURCE` | | From `--source-dir` |
| `APP_KEY` | generated | Laravel encryption key. **Encrypts every secret, including the Fleet CA key.** |
| `DB_PASSWORD`, `REDIS_PASSWORD` | generated | Postgres and Valkey passwords |
| `REVERB_APP_ID`, `REVERB_APP_KEY`, `REVERB_APP_SECRET` | generated | Websocket credentials |
| `FALAK_BUILDER_TOKEN` | generated `kbt_…` | Token of the host builder (`FALAK_LOCAL_BUILDER_TOKEN` in the app) |
| `FALAK_OTLP_TOKEN` | generated | Token agents send to the OTLP gateway |
| `GRAFANA_ADMIN_PASSWORD` | generated | Grafana `admin` password |
| `COMPOSE_PROFILES` | `observability` or empty | Compose profiles |
| `FALAK_LOG_LEVEL` | `warning` | Control plane log level |

## Sign-up (`.env`)

| Variable | Default | Meaning |
|---|---|---|
| `FALAK_REGISTRATION` | `open` | Who can create an account: `open` (anyone), `invite` (only through an invitation link), `closed` (nobody; use `falak-ctl admin create`). An unknown value counts as `closed`; the first account can always register. See [Who can sign up](/docs/operations/configuration/#who-can-sign-up). |

## Mail

| Variable | Default |
|---|---|
| `MAIL_MAILER` | `log` (nothing sent); use `smtp` |
| `MAIL_HOST`, `MAIL_PORT`, `MAIL_USERNAME`, `MAIL_PASSWORD` | —, `587`, —, — |
| `MAIL_FROM_ADDRESS` | `falak@localhost` |

## Performance

| Variable | Default | Meaning |
|---|---|---|
| `FALAK_WORKER_MODE` | `1` | Panel in FrankenPHP worker mode; `0` = classic |
| `FALAK_PHP_WORKERS` | 2 × CPUs | Panel workers |
| `FALAK_PHP_MAX_THREADS` | max(8, 4 × CPUs) | Panel thread cap |
| `FALAK_PHP_THREADS` | | Starting threads in classic mode |
| `FALAK_AGENT_API_THREADS` | `128` | `agent-api` thread cap |
| `FALAK_HORIZON_MAX_PROCESSES` | `4` | Horizon worker processes |

## Domains and edge

| Variable | Default | Meaning |
|---|---|---|
| `FALAK_TEST_DOMAIN` | unset | Wildcard test domain base |
| `FALAK_TEST_DOMAIN_TLS` | `acme` | `acme` or `internal` |
| `FALAK_GENERATED_DOMAIN_SUFFIX` | `sslip.io` | `nip.io`, your own sslip.io-style domain, or `off` |
| `FALAK_DNS_RESOLVER` | `doh` | `doh` or `system` |
| `FALAK_DNS_DOH_URL` | `https://cloudflare-dns.com/dns-query` | DNS-over-HTTPS endpoint |
| `FALAK_ACME_CA` | Caddy default | ACME directory for servers' certificates |
| `FALAK_EDGE_APPLY_DELAY` | `2` | Seconds to debounce Caddy config applies |

## Agents (Fleet)

| Variable | Default | Meaning |
|---|---|---|
| `FALAK_INSTALL_TOKEN_TTL` | `1440` | Install token lifetime (minutes) |
| `FALAK_AGENT_OFFLINE_AFTER` | `60` | Seconds without heartbeat before offline |
| `FALAK_AGENT_COMMAND_LEASE` | `90` | Seconds before an unacknowledged command is redelivered or failed (min 10) |
| `FALAK_AGENT_UPGRADE_BATCH_SIZE` | `2` | Servers upgraded at a time by a bulk agent update |
| `FALAK_AGENT_UPGRADE_TIMEOUT` | `600` | Seconds before an upgrade fails (min 60) |
| `FALAK_AGENT_WAKE_DRIVER` | `database` (`redis` in the Compose stack) | How long-polls are woken |
| `FALAK_AGENT_WAKE_REDIS` | `default` | Redis connection for wake-ups |
| `FALAK_AGENT_TRUSTED_PROXIES` | `127.0.0.1/32,::1/128` (the edge subnet in Compose) | Proxies allowed to forward client-cert fingerprints |
| `FALAK_AGENT_DOWNLOAD_URL` | the panel | Where installers download `falak-agent` (`{arch}` placeholder) |
| `FALAK_AGENT_BINARIES_PATH` | `storage/falak/agent` | Served agent binaries |
| `FALAK_AGENT_SHA256_AMD64`, `FALAK_AGENT_SHA256_ARM64` | | Pinned checksums for external downloads |
| `FALAK_AGENT_VERSION` | `FALAK_VERSION` | Shipped agent version when no sidecar file exists |
| `FALAK_CA_PATH` | `storage/falak/ca` | Where the CA certificate is written for the edge |
| `FALAK_PANEL_URL` | `APP_URL` | Panel URL handed to agents |

## Builds

| Variable | Default | Meaning |
|---|---|---|
| `FALAK_BUILD_TIMEOUT` | `1800` | Build timeout (s) |
| `FALAK_BUILD_HEARTBEAT_TIMEOUT` | `90` | Fail a running build without heartbeat (s) |
| `FALAK_BUILD_QUEUE_TTL` | `3600` | Fail a build no builder picked up (s) |
| `FALAK_LOCAL_BUILDER_TOKEN` | `FALAK_BUILDER_TOKEN` | Host builder token (empty = only builder servers) |
| `FALAK_LOCAL_BUILDER_NAME` | `control-plane` | Host builder name |
| `FALAK_LOCAL_BUILDER_MODES` | `native` | Add `docker` only when it can reach BuildKit |
| `FALAK_BUILDER_DOWNLOAD_URL` | the panel | `falak-builder` download for builder servers |
| `FALAK_BUILDER_BINARIES_PATH` | `storage/falak/builder` | Served builder binaries |
| `FALAK_ARTIFACTS_DRIVER` | `local` | `local` or `s3` |
| `FALAK_ARTIFACTS_PATH` | `storage/falak/artifacts` | Local artifacts |
| `FALAK_ARTIFACTS_URL` | `FALAK_PANEL_URL` / `APP_URL` | Public https base for artifact URLs |
| `FALAK_ARTIFACTS_MAX_BYTES` | `4294967296` (4 GiB) | Maximum upload |
| `FALAK_ARTIFACTS_KEEP` | `10` | Artifacts kept per site |
| `FALAK_ARTIFACTS_MAX_AGE_DAYS` | `90` | Artifact maximum age |
| `FALAK_ARTIFACTS_S3_ENDPOINT`, `_REGION`, `_BUCKET`, `_KEY`, `_SECRET`, `_PREFIX`, `_PATH_STYLE` | —, `us-east-1`, —, —, —, `artifacts`, `false` | S3 artifact storage |
| `FALAK_REGISTRY_URL` | `registry.<domain>` (installer; `registry.falak.local` without it) | Registry for Docker builds |
| `FALAK_REGISTRY_HOST` | `registry.<domain>` (installer) | Host the edge serves the built-in registry on |
| `FALAK_REGISTRY_HOST_ALIASES` | set by `falak-ctl domain set` | Earlier registry hosts, still served |
| `FALAK_REGISTRY_NAMESPACE` | `falak` | Image namespace |
| `FALAK_REGISTRY_USERNAME`, `FALAK_REGISTRY_PASSWORD` | `falak`, generated (installer) | Registry credentials |
| `FALAK_REGISTRY_DELETED_SITE_GRACE_DAYS` | `7` | Days after the build before a deleted site's images are pruned |

## Deployments and sites

| Variable | Default | Meaning |
|---|---|---|
| `FALAK_DEPLOY_HOOK_TIMEOUT` | `1800` | Deploy script section timeout (s) |
| `FALAK_DEPLOY_WAIT_TIMEOUT_MINUTES` | `30` | Fail a `waiting` deployment after this |
| `FALAK_COMPOSE_WAIT_TIMEOUT` | `300` | `docker compose up --wait-timeout` (s) |
| `FALAK_SITES_ROOT` | `/srv/falak/sites` | Sites root on servers |
| `FALAK_SITE_COMMAND_TIMEOUT` | `600` | Site commands timeout (s) |
| `FALAK_PROCESSES_APPLY_DELAY` | `2` | Debounce for process changes (s) |
| `FALAK_PROCESSES_STATUS_POLL` | `5` | Crash-loop poll interval (minutes; 0 disables) |

## Runtimes on servers

| Variable | Default |
|---|---|
| `FALAK_FRANKENPHP_VERSION` | `1.9.1` |
| `FALAK_FRANKENPHP_SHA256` | unset |
| `FALAK_NODE_20`, `FALAK_NODE_22`, `FALAK_NODE_24` | `20.19.5`, `22.20.0`, `24.9.0` |
| `FALAK_BUN_VERSION` | `1.4.2` |
| `FALAK_DENO_VERSION` | `2.9.7` |
| `FALAK_FRANKENPHP_MIRROR`, `FALAK_NODE_MIRROR`, `FALAK_BUN_MIRROR`, `FALAK_DENO_MIRROR` | unset (upstream) |

## Databases and backups (apps)

| Variable | Default | Meaning |
|---|---|---|
| `FALAK_BACKUP_UPLOAD_URL_TTL` | `43200` | Presigned upload URL lifetime (s) |
| `FALAK_BACKUP_DOWNLOAD_URL_TTL` | `21600` | Presigned download URL lifetime (s) |
| `FALAK_STORAGE_ALLOW_PRIVATE_ENDPOINTS` | `false` | Allow storage on private addresses |

## Network

| Variable | Default |
|---|---|
| `FALAK_PRIVATE_NETWORK_CIDR` | `10.90.0.0/24` |
| `FALAK_WIREGUARD_PORT` | `51820` |
| `FALAK_DOCKER_NETWORKS` | `172.16.0.0/12,192.168.0.0/16` (Docker address ranges that may reach app-server databases; see [Configuration](/docs/operations/configuration/#docker-address-ranges)) |

## Telemetry and observability

| Variable | Default | Meaning |
|---|---|---|
| `FALAK_OTLP_ENDPOINT` | `https://<domain>/otlp` with observability | Where agents send OTLP |
| `FALAK_METRICS_BACKEND` | `victoriametrics` | Or `mimir` |
| `FALAK_METRICS_QUERY_URL` | `http://gateway:9090/prometheus` with `--observability`, else unset | Metrics query URL |
| `FALAK_MIMIR_TENANT`, `FALAK_METRICS_TOKEN` | | Mimir tenant / token |
| `FALAK_LOKI_URL`, `FALAK_LOKI_TENANT` | `http://loki:3100` with `--observability`, else unset | Loki |
| `FALAK_TEMPO_URL` | `http://tempo:3200` with `--observability`, else unset | Tempo |
| `FALAK_GRAFANA_URL` | `http://grafana:3000` with `--observability`, else unset | Grafana API (from the control plane) |
| `FALAK_GRAFANA_PUBLIC_URL` | `https://grafana.<domain>` | Grafana links in the browser |
| `FALAK_GRAFANA_TOKEN` | created by the installer | Grafana service account token |
| `FALAK_GRAFANA_HOST` | `grafana.<domain>` | Grafana host at the edge |
| `FALAK_GRAFANA_METRICS_URL`, `FALAK_GRAFANA_LOKI_URL`, `FALAK_GRAFANA_TEMPO_URL` | gateway, loki, tempo | Datasource URLs as Grafana sees them |
| `FALAK_GRAFANA_DASHBOARDS_PATH` | bundled dashboards | Dashboard JSON directory |
| `FALAK_GRAFANA_PREINSTALL_DISABLED` | `true` | Skip Grafana's app downloads |
| `FALAK_TELEMETRY_ENVIRONMENT` | `production` | Default environment attribute |
| `FALAK_TRACES_SAMPLE_RATIO` | `1.0` | Default trace sampling |
| `FALAK_TELEMETRY_HTTP_TIMEOUT`, `FALAK_TELEMETRY_HTTP_CONNECT_TIMEOUT` | `15`, `3` | Backend query timeouts (s) |
| `FALAK_LOGS_RETENTION` | `360h` | Loki retention |
| `FALAK_TRACES_RETENTION` | `360h` | Tempo retention |
| `FALAK_METRICS_RETENTION` | `30d` | VictoriaMetrics retention |
| `FALAK_INSIGHTS_RETENTION_DAYS` | `30` | Insights occurrences retention |
| `FALAK_INSIGHTS_HEARTBEAT_GRACE` | `120` | Seconds before a heartbeat is missed |

## Alerting

| Variable | Default |
|---|---|
| `FALAK_ALERTING_RETENTION_DAYS` | `90` |
| `FALAK_ALERTING_ALLOW_PRIVATE_WEBHOOKS` | `false` |
| `FALAK_ALERTING_QUEUE` | `default` |
| `FALAK_TELEGRAM_API` | `https://api.telegram.org` |

## Source control

| Variable | Default | Meaning |
|---|---|---|
| `FALAK_WEBHOOK_URL` | `APP_URL` | Public base URL for provider webhooks |
| `FALAK_WEBHOOK_RATE_LIMIT` | `120` | Deliveries per minute per webhook |
| `FALAK_GITHUB_APP_WEBHOOK_RATE_LIMIT` | `600` | Deliveries per minute per GitHub App |
| `GITHUB_APP_ID`, `GITHUB_APP_SLUG`, `GITHUB_APP_PRIVATE_KEY`, `GITHUB_APP_WEBHOOK_SECRET` | | Operator-managed GitHub App |
| `GITHUB_CLIENT_ID`, `GITHUB_CLIENT_SECRET`, `GITHUB_URL`, `GITHUB_API_URL` | —, —, `https://github.com`, `https://api.github.com` | GitHub OAuth |
| `GITLAB_CLIENT_ID`, `GITLAB_CLIENT_SECRET`, `GITLAB_URL` | —, —, `https://gitlab.com` | GitLab OAuth |
| `BITBUCKET_CLIENT_ID`, `BITBUCKET_CLIENT_SECRET`, `BITBUCKET_URL`, `BITBUCKET_API_URL` | —, —, `https://bitbucket.org`, `https://api.bitbucket.org/2.0` | Bitbucket OAuth |

## Cloud providers

| Variable | Default |
|---|---|
| `FALAK_HETZNER_API_URL` | `https://api.hetzner.cloud/v1` |
| `FALAK_DIGITALOCEAN_API_URL` | `https://api.digitalocean.com/v2` |
| `FALAK_VULTR_API_URL` | `https://api.vultr.com/v2` |
| `FALAK_LINODE_API_URL` | `https://api.linode.com/v4` |
| `FALAK_LIGHTSAIL_API_URL` | `https://lightsail.{region}.amazonaws.com` |
| `FALAK_PROVIDERS_HTTP_TIMEOUT`, `FALAK_PROVIDERS_HTTP_CONNECT_TIMEOUT` | `30`, `10` |
| `FALAK_PROVIDERS_HTTP_RETRIES`, `FALAK_PROVIDERS_HTTP_RETRY_SLEEP_MS` | `3`, `500` |
| `FALAK_PROVIDERS_CATALOG_TTL` | `3600` |

## Templates, recipes, terminal

| Variable | Default |
|---|---|
| `FALAK_TEMPLATES_PATH` | the bundled catalog (`/opt/falak/templates` in the image) |
| `FALAK_TEMPLATES_CACHE_TTL` | `3600` |
| `FALAK_RECIPES_TIMEOUT` | `900` |
| `FALAK_TERMINAL_IDLE_TIMEOUT` | `900` |
| `FALAK_TERMINAL_MAX_DURATION` | `3600` |
| `FALAK_TERMINAL_DEFAULT_USER` | `root` |

## falak-ctl (read from `.env` by falak-ctl itself)

| Variable | Default |
|---|---|
| `FALAK_BACKUP_KEEP` | `14` |
| `FALAK_BACKUP_PASSPHRASE` | unset (unencrypted) |
| `FALAK_BACKUP_S3_ENDPOINT`, `_BUCKET`, `_REGION`, `_ACCESS_KEY`, `_SECRET_KEY`, `_PREFIX` | —, —, `us-east-1`, —, —, `falak` |
| `FALAK_PRUNE_IMAGES` | `1` (`0` keeps every old Falak image after an update) |
| `FALAK_REGISTRY_GC` | `1` (`0` removes the weekly registry garbage collection cron entry) |
| `FALAK_PREVIOUS_VERSION` | set by `update`: the version kept as the rollback target when old images are pruned |
| `FALAK_DIR`, `FALAK_PROJECT` (shell environment) | `/opt/falak`, `falak` |
| `FALAK_LOG_TAIL` (shell environment) | `200` |

Paths like `storage/falak/agent` are inside the control-plane container's Laravel storage (the `app-storage` volume).
