# Configuration

> Configure a Falak installation — .env versus custom.env, sign-up, mail, domains, runtime mirrors, Docker address ranges, artifact storage and falak-ctl up.

Source: https://falak.sh/docs/operations/configuration/

A Falak installation is configured by two files on the control plane host. After editing either, run `falak-ctl up` to apply.

## `.env` versus `custom.env`

| File | Written by | Reaches |
|---|---|---|
| `/opt/falak/.env` | The installer (secrets and settings); you may edit it | **Only** the variables `deploy/compose.yml` passes to each container |
| `/opt/falak/custom.env` | You (optional) | **Every** variable, loaded into the Laravel containers (`control-plane`, `agent-api`, `horizon`, `reverb`, `scheduler`) |

Rule of thumb: settings listed in the table below go in `.env`, along with falak-ctl's own (`FALAK_BACKUP_*`, `FALAK_PULL`, `FALAK_PRUNE_IMAGES`). Any other control plane setting from the [environment variables reference](/docs/reference/environment-variables/) — for example `FALAK_AGENT_UPGRADE_BATCH_SIZE`, `FALAK_DEPLOY_WAIT_TIMEOUT_MINUTES`, `FALAK_WEBHOOK_URL`, download mirrors (`FALAK_*_MIRROR`), `GITHUB_APP_*`, OAuth client ids — goes in `custom.env`.

A variable that is in neither `compose.yml` nor `custom.env` never reaches the app. If a setting seems to be ignored, move it to `custom.env`. The other way round, a variable compose passes by name always comes from `.env`: setting it in `custom.env` has no effect.

Both files are included in `falak-ctl backup`. Keep them mode 600.

### Variables passed from `.env`

| Area | Variables |
|---|---|
| Identity of the install | `FALAK_DOMAIN`, `FALAK_URL`, `FALAK_VERSION`, `FALAK_REPO`, `FALAK_IMAGE_PREFIX` |
| Image registry | `FALAK_REGISTRY_URL`, `FALAK_REGISTRY_HOST`, `FALAK_REGISTRY_HOST_ALIASES`, `FALAK_REGISTRY_USERNAME`, `FALAK_REGISTRY_PASSWORD` |
| Secrets | `APP_KEY`, `DB_PASSWORD`, `REDIS_PASSWORD`, `REVERB_APP_ID`, `REVERB_APP_KEY`, `REVERB_APP_SECRET`, `FALAK_BUILDER_TOKEN`, `FALAK_OTLP_TOKEN`, `GRAFANA_ADMIN_PASSWORD` |
| Agents | `FALAK_AGENT_API_HOST`, `FALAK_AGENT_API_URL`, `FALAK_AGENT_API_HOST_ALIASES`, `FALAK_AGENT_API_THREADS` |
| Edge | `FALAK_TLS`, `FALAK_ACME_EMAIL`, `FALAK_ACME_CA`, `FALAK_HSTS`, `FALAK_HTTP_PORT`, `FALAK_HTTPS_PORT`, `FALAK_BIND`, `FALAK_EDGE_SUBNET`, `FALAK_DOMAIN_ALIASES` |
| Sign-up | `FALAK_REGISTRATION` |
| Domains | `FALAK_TEST_DOMAIN`, `FALAK_TEST_DOMAIN_TLS`, `FALAK_GENERATED_DOMAIN_SUFFIX`, `FALAK_DNS_RESOLVER`, `FALAK_DNS_DOH_URL` |
| Mail | `MAIL_MAILER`, `MAIL_HOST`, `MAIL_PORT`, `MAIL_USERNAME`, `MAIL_PASSWORD`, `MAIL_FROM_ADDRESS` |
| Performance | `FALAK_WORKER_MODE`, `FALAK_PHP_WORKERS`, `FALAK_PHP_THREADS`, `FALAK_PHP_MAX_THREADS`, `FALAK_HORIZON_MAX_PROCESSES`, `FALAK_LOG_LEVEL` |
| Observability | `COMPOSE_PROFILES`, `FALAK_OTLP_ENDPOINT`, `FALAK_GRAFANA_HOST`, `FALAK_GRAFANA_URL`, `FALAK_GRAFANA_PUBLIC_URL`, `FALAK_GRAFANA_TOKEN`, `FALAK_LOKI_URL`, `FALAK_TEMPO_URL`, `FALAK_METRICS_QUERY_URL`, `FALAK_LOGS_RETENTION`, `FALAK_TRACES_RETENTION`, `FALAK_METRICS_RETENTION`, `FALAK_GRAFANA_PREINSTALL_DISABLED` |
| falak-ctl | `FALAK_BACKUP_KEEP`, `FALAK_BACKUP_PASSPHRASE`, `FALAK_BACKUP_S3_*`, `FALAK_PULL`, `FALAK_PRUNE_IMAGES`, `FALAK_PREVIOUS_VERSION`, `FALAK_REGISTRY_GC` (read by falak-ctl itself) |

## Who can sign up

By default anyone who can reach the panel can create an account (and gets an empty organization of their own). On a panel reachable from the internet, set `FALAK_REGISTRATION` in `/opt/falak/.env`, then `falak-ctl up`:

| Value | Sign-up |
|---|---|
| `open` (default) | Anyone |
| `invite` | Only through an invitation link (invite from **Settings → Members**): the person opens the e-mailed link, chooses *Sign up* and registers with the invited address, which also joins the organization |
| `closed` | Nobody; the *Sign up* links are hidden. Create accounts with `falak-ctl admin create <email>` |

An unknown value counts as `closed`. A panel without any account always accepts the first sign-up, so the first administrator can register before the setting matters.

## Mail

Falak sends invitations, password resets and e-mail alerts. Out of the box `MAIL_MAILER=log` (nothing is sent). In `/opt/falak/.env`:

```dotenv title="/opt/falak/.env"
MAIL_MAILER=smtp
MAIL_HOST=smtp.postmarkapp.com
MAIL_PORT=587
MAIL_USERNAME=…
MAIL_PASSWORD=…
MAIL_FROM_ADDRESS=falak@example.com
```

Then `falak-ctl up`.

## Domains for new services

| Variable | Default | |
|---|---|---|
| `FALAK_GENERATED_DOMAIN_SUFFIX` | `sslip.io` | `nip.io`, the domain of a self-hosted [sslip.io server](https://github.com/cunnie/sslip.io), or `off` |
| `FALAK_TEST_DOMAIN` | unset | Wildcard base for `<slug>.<test domain>`; becomes the default choice |
| `FALAK_TEST_DOMAIN_TLS` | `acme` | `internal` for private setups |
| `FALAK_DNS_RESOLVER` | `doh` | `doh` (DNS-over-HTTPS, no local cache) or `system` |
| `FALAK_DNS_DOH_URL` | `https://cloudflare-dns.com/dns-query` | Any DNS-over-HTTPS JSON endpoint, e.g. `https://dns.google/resolve` |

Organizations can still pick their generated-domain provider in **Settings → Domains**. See [Domains](/docs/guides/domains/).

## Runtime download mirrors

Servers download FrankenPHP, Node.js, Bun and Deno release binaries during provisioning (SHA-256 verified). To use an HTTPS mirror with the same path layout (air-gapped servers, a caching proxy), set these in **`/opt/falak/custom.env`**, then `falak-ctl up`:

| Variable | Replaces | Fetched path |
|---|---|---|
| `FALAK_FRANKENPHP_MIRROR` | `https://github.com/php/frankenphp/releases/download` | `<mirror>/v<version>/frankenphp-linux-<arch>` |
| `FALAK_NODE_MIRROR` | `https://nodejs.org/dist` | `<mirror>/v<version>/SHASUMS256.txt`, `node-v<version>-linux-<arch>.tar.gz` |
| `FALAK_BUN_MIRROR` | `https://github.com/oven-sh/bun/releases/download` | `<mirror>/bun-v<version>/SHASUMS256.txt`, `bun-linux-<arch>.zip` |
| `FALAK_DENO_MIRROR` | `https://github.com/denoland/deno/releases/download` | `<mirror>/v<version>/deno-<arch>-unknown-linux-gnu.zip{,.sha256sum}` |

Unset means upstream. Mirrors apply to servers provisioned (or runtimes installed) after the change.

## Docker address ranges

Containers on an app or worker server (Compose stacks, Docker sites, functions) reach that server's [databases](/docs/databases/create-databases/#containers-and-databases-on-the-same-server) through the Docker bridge (agent 0.4.5+). The engines accept connections from Docker's default address pools, `172.16.0.0/12,192.168.0.0/16`, and the firewall only lets them in on the Docker bridges. If the Docker daemon on your servers uses other `default-address-pools`, set `FALAK_DOCKER_NETWORKS` (comma-separated IPv4 CIDRs, /8 to /30) in **`/opt/falak/custom.env`** and run `falak-ctl up`. It applies to database users created or updated afterwards. Entries that are not such ranges are ignored with a warning in the logs (Docker's defaults apply when none is left).

## Build artifacts

Native build artifacts are stored on the control plane (`app-storage` volume) by default and served to agents through signed URLs. To use S3 instead (in `custom.env`):

| Variable | Default |
|---|---|
| `FALAK_ARTIFACTS_DRIVER` | `local` (`s3` to use a bucket) |
| `FALAK_ARTIFACTS_S3_ENDPOINT`, `FALAK_ARTIFACTS_S3_REGION`, `FALAK_ARTIFACTS_S3_BUCKET` | —, `us-east-1`, — |
| `FALAK_ARTIFACTS_S3_KEY`, `FALAK_ARTIFACTS_S3_SECRET` | — |
| `FALAK_ARTIFACTS_S3_PREFIX`, `FALAK_ARTIFACTS_S3_PATH_STYLE` | `artifacts`, `false` |
| `FALAK_ARTIFACTS_KEEP` | `10` per site |

## Webhook base URL

If git providers must reach Falak under a different hostname, set `FALAK_WEBHOOK_URL` (in `custom.env`) to that public base URL.

## Apply changes

```bash
sudo falak-ctl up
```

`up` starts or recreates services whose definition changed, waits until healthy, recreates services whose mounted config files changed, and runs a health check.

## Next steps
