# Upgrade Falak

> Upgrade the Falak control plane with falak-ctl update — backup, image pull, migrations, health checks, rollback and old image cleanup.

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

Upgrades are one command. `falak-ctl` takes a backup first and rolls back automatically if anything fails.

```bash
sudo falak-ctl update                   # latest release
sudo falak-ctl update --version v0.2.6  # a specific release
```

## What an update does

1. Takes a backup: `backups/falak-backup-<ts>-pre-update-<old version>.tar.gz`.
2. Fetches the new deploy bundle (checksum verified) and pulls the new images. If a pull fails, nothing changes.
3. Recreates the stack. The `control-plane` service runs the migrations; `horizon`, `reverb` and `scheduler` wait until it is healthy.
4. Recreates every service whose **mounted config files** changed, and prints their names.
5. Health-checks every container and `https://<domain>/up`.
6. Removes older Falak images (see below).
7. Prints how many server agents are older than the shipped build.

If step 3, 4 or 5 fails, `falak-ctl` **rolls back automatically**: it restores the previous deploy files and `FALAK_VERSION`, restores the database, storage and Fleet CA from the pre-update backup (the new migrations may already have run), and starts the previous version again.

`--skip-backup` skips step 1, so there is nothing to roll back to. Do not use it in production.

## Old images

Each release pulls new `falak-control-plane`, `falak-edge` and `falak-builder` images (about 1 GB together), so a host that updates often fills its disk. After a successful update, falak-ctl records the version it came from as `FALAK_PREVIOUS_VERSION` in `.env` and removes every other tag of those three images. The current and the previous version stay, so a manual rollback (`falak-ctl update --version <previous>`) needs no download.

- Third-party images (Postgres, Valkey, Grafana, …), images still used by a container and volumes are never touched.
- Run it on its own with `sudo falak-ctl prune-images` (`--dry-run` lists what it would remove).
- Set `FALAK_PRUNE_IMAGES=0` in `/opt/falak/.env` to keep every image.
- With `FALAK_PULL=0` (images built locally, e.g. `--build-from-source`), an update never prunes: removed images could not be pulled again. `falak-ctl prune-images` still works there and warns first.

## The built-in registry (0.5.0)

Falak 0.5.0 adds a built-in image registry for Docker builds. `falak-ctl update` adds `FALAK_REGISTRY_*` to `.env` and writes the weekly garbage collection cron entry. If the update was run by an older falak-ctl, run `sudo falak-ctl up` once afterwards. Then create the `registry.<domain>` DNS record and check it with `sudo falak-ctl registry status`. See [The built-in image registry](/docs/operations/install/#the-built-in-image-registry).

Containers reaching databases on their own server need agent 0.4.5 or newer; update the agents (below).

## Upgrade the agents

An update does **not** touch your servers. Update agents afterwards from **Servers** (per server, the ones you select, or **Update all agents**) or through the API. See [Agent upgrades](/docs/servers/agent-upgrades/).

## Upgrading from 0.2.x

### Mounted config files (falak-ctl v0.2.5 and older)

An update replaces `/opt/falak/observability/` and `/opt/falak/deploy/`, but a running container keeps the files it was started with, and `docker compose up` only recreates services whose compose definition changed. falak-ctl v0.2.5 and older did not detect this, so Loki could keep an old `loki.yaml` (access logs in **Network Logs** were then not queryable).

An update is run by the **already installed** falak-ctl. After updating **from** v0.2.5 or older, run once:

```bash
sudo falak-ctl reload-configs
```

### The PHP thread hotfix

If you added `FRANKENPHP_CONFIG=num_threads 24` to `/opt/falak/custom.env` on 0.2.x, the update keeps working: a thread count in `FRANKENPHP_CONFIG` still wins over the automatic sizing (containers log a notice). It is no longer needed, because agents now long-poll their own `agent-api` service. Remove the line, then:

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

`falak-ctl doctor` reports the line until you remove it. See [Performance](/docs/operations/performance/).

### Laravel sites logging to stderr

Falak migrated Laravel sites that used `LOG_CHANNEL=stderr` (the old default) to `daily`, as a new environment version effective on their next deployment. Redeploy Laravel sites to get their web request logs into Loki. The migration cannot tell a deliberate `stderr` from the old default; set it back if you really want stderr.

### Releases deployed before the permission hardening

Release and `shared/` directories are now closed to other local users (mode 0750 plus an ACL for the edge). Releases deployed before stay open until they are pruned; redeploy each site a few times (or enough to exceed **Releases to keep**) to replace them.

## Releasing (maintainers)

Pushing a tag `vX.Y.Z` (`vX.Y.Z-rc.N` for pre-releases, which are not tagged `latest`) runs `.github/workflows/release.yml`, which builds multi-arch `falak-control-plane`, `falak-builder` and `falak-edge` images to `ghcr.io/<owner>/…:<tag>` and `:latest`, builds `falak-agent`, `falak` and `falak-builder` binaries, and creates the GitHub release with the binaries, `falak-deploy.tar.gz`, `install.sh` (pinned to the tag), `falak-ctl` and `SHA256SUMS`. After the first release, make the three GHCR packages public so hosts can pull anonymously.

## Next steps
