# Provisioning

> What Falak puts on a server — packages, the falak user, PHP, FrankenPHP or Caddy, Node.js, databases, swap, unattended upgrades, SSH hardening, firewall.

Source: https://falak.sh/docs/servers/provisioning/

After the agent enrolls, Falak first runs the [machine check](/docs/servers/machine-check/): it looks at the software already on the server and decides per component to install it, use what is there, or stop with a fix. Then the control plane sends one declarative **provisioning plan** (`provision.apply`) built from the server's type and software choices. The agent applies it step by step, skipping what is already in place. Re-provisioning (server page → **Re-provision**) sends the same plan again and is safe.

## The plan, step by step

| Step | What happens |
|---|---|
| **hostname** | Set from the server name, lower-cased to an RFC 1123 name (for example `App 1` → `app-1`). Servers you connect yourself keep their hostname. |
| **timezone** | The server's timezone (default `UTC`) |
| **swap** | A swap file: 2 GB on machines under 2 GB RAM, 4 GB under 8 GB, none from 8 GB. (Skipped inside containers, and when the machine already has swap.) |
| **apt** | Base packages plus the chosen database, cache and Docker packages (below), except components the machine check found already installed |
| **user:falak** | The `falak` user: shell `/bin/bash`, home `/home/falak`, groups `www-data` (and `docker` with Docker), **no sudo** |
| **php:&lt;version&gt;** | Each chosen PHP version with the standard extensions; PHP-FPM when the runtime is PHP-FPM; the default version becomes `php` on the CLI |
| **frankenphp** | FrankenPHP 1.9.1 as the server's edge (embeds Caddy), SHA-256 verified; it joins the sites' groups |
| **node:&lt;version&gt;** | Node.js from nodejs.org, checksum verified |
| **caddy** | Standalone Caddy (from the official Caddy apt repository) on servers that serve HTTP without FrankenPHP: PHP-FPM servers and load balancers |
| **service:&lt;name&gt;** | `fail2ban` plus the database, cache and Docker services, enabled and started |
| **unattended_upgrades** | Security updates on, automatic reboot **off** (reboot time 04:00 if you enable it) |
| **ssh** | Hardened `sshd` configuration (below), verified before reload so you are not locked out |

Afterwards the default firewall rules are applied (SSH; plus HTTP/HTTPS on app, web and lb servers). The whole plan may take up to 30 minutes (`provision_timeout` 1800 s). Transient download failures are retried with backoff.

## Packages

Base packages on every server:

```text
acl ca-certificates curl fail2ban git htop jq rsync sqlite3 unattended-upgrades unzip zip
```

| Choice | Packages | Service |
|---|---|---|
| PostgreSQL | `postgresql`, `postgresql-contrib` | `postgresql` |
| MySQL | `mysql-server` | `mysql` |
| MariaDB | `mariadb-server` | `mariadb` |
| Redis | `redis-server` | `redis-server` |
| Valkey | `valkey-server` | `valkey-server` |
| Docker | `docker.io`, `docker-compose-v2`, `docker-buildx` | `docker` |

Software the machine check found is used instead: for example Docker from Docker's repository (`docker-ce`, `docker-compose-plugin`, `docker-buildx-plugin`) or PostgreSQL from apt.postgresql.org. Falak never installs Ubuntu's package next to it.

A database engine added later (server **Settings → Database engine**) is installed by the same plan. Database versions come from the distribution: on Ubuntu 24.04 that is PostgreSQL 16, MySQL 8.0, MariaDB 10.11; on 22.04 PostgreSQL 14, MySQL 8.0, MariaDB 10.6. Pinning a PostgreSQL version is not supported yet.

## PHP

- Versions offered: 8.1, 8.2, 8.3, 8.4 (default), 8.5.
- Extensions installed for every version: `bcmath`, `cli`, `curl`, `gd`, `igbinary`, `intl`, `mbstring`, `mysql`, `pgsql`, `readline`, `redis`, `soap`, `sqlite3`, `xml`, `zip`.
- Add or remove versions and change the default on the server page under **PHP**. Edit `php.ini` settings there too.

## SSH configuration

Falak writes this `sshd` configuration:

```text title="Managed by Falak"
Port 22
PermitRootLogin prohibit-password
PasswordAuthentication no
KbdInteractiveAuthentication no
PubkeyAuthentication yes
X11Forwarding no
MaxAuthTries 4
```

Password logins stop working after provisioning. Make sure your SSH key is on the machine (root's `authorized_keys`, or an [organization SSH key](/docs/servers/ssh-keys/) for the `falak` user) before you connect a server you still log into with a password.

## Runtimes installed later

Some runtimes are installed when a site first needs them, not during provisioning:

- **Bun** 1.4.2 and **Deno** 2.9.7, when a Bun or Deno site targets the server;
- a **PHP-FPM pool** and the site user, when a site is added to the server.

While that happens, the site's target is "preparing" and deployments wait for it.

## Download mirrors

Servers download FrankenPHP, Node.js, Bun and Deno from GitHub and nodejs.org. Point them at your own HTTPS mirror with `FALAK_FRANKENPHP_MIRROR`, `FALAK_NODE_MIRROR`, `FALAK_BUN_MIRROR`, `FALAK_DENO_MIRROR`. See [Configuration](/docs/operations/configuration/#runtime-download-mirrors).

## Version pins (operators)

| Variable | Default |
|---|---|
| `FALAK_FRANKENPHP_VERSION` | `1.9.1` |
| `FALAK_FRANKENPHP_SHA256` | unset (verified against the release otherwise) |
| `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` |

## Next steps
