# Machine check

> Before provisioning, Falak checks the software already on a server and installs, reuses, completes or stops with a fix.

Source: https://falak.sh/docs/servers/machine-check/

Servers you bring often have software on them already: Docker from Docker's repository, nginx, a PostgreSQL from
apt.postgresql.org, a Redis in a container. Since v0.6.0 Falak checks the machine **before** it provisions it, and never
replaces or removes software it didn't install.

The check runs after the agent enrolls and on every **Re-provision**. It only reads the machine; nothing changes until
provisioning starts.

## What it looks at

- Installed packages and **where they came from**: Ubuntu's archive, a vendor repository (Docker, PostgreSQL, MySQL,
  Caddy…), a snap, or a manual install
- Docker: the engine, which package provides `docker compose` and `docker buildx`, snap or rootless setups, and
  `daemon.json` settings that matter (`iptables`, `userns-remap`, address pools)
- Databases and caches: PostgreSQL, MySQL, MariaDB, Redis, Valkey: version, source, service
- Web servers (nginx, Apache, Caddy) and the ports Falak needs, with the process or container holding each:
  80, 443, 2019, 5432, 3306, 6379
- SSH: the effective `sshd` settings, the order of `sshd_config.d` files, and whether a user who may log in has a key
- Firewalls (ufw, firewalld, other nftables tables), swap, hostname, Node and PHP installs, unattended upgrades, fail2ban

The check executes only root-owned programs and reports no secrets (credentials in repository URLs are removed).

## Decisions

Each component gets one decision:

| Decision | Meaning |
|---|---|
| **Install** | Nothing there: Falak installs it as before |
| **Use existing** | A working, supported install is there: Falak uses it and installs nothing for it |
| **Install missing parts** | Partly there: Falak installs only the missing pieces, **from the same source** (Docker from Docker's repository gets `docker-compose-plugin`; Ubuntu's `docker.io` gets `docker-compose-v2`) |
| **Blocked** | A conflict Falak won't resolve on its own; the row says why and how to fix it |
| **Not managed** | Found, but not part of this server's setup |

Common examples:

| On the machine | Result |
|---|---|
| Docker from Docker's repository with compose and buildx | Use existing |
| PostgreSQL 17 from apt.postgresql.org | Use existing; the cluster and its version stay |
| nginx on port 80 | Blocked: stop or move it |
| A container publishing 6379, and the server should run Redis | Blocked: stop the container or publish another port |
| MariaDB installed, the server is set up for MySQL | Blocked: Falak won't run two engines of a kind |
| A version older than Falak supports (Docker 20.10, PostgreSQL 14, MySQL 8.0, MariaDB 10.6, Redis 6.0, Valkey 7.2) | Blocked: upgrade it from the same source |
| Password login only, no SSH key for a user who may log in | Blocked: Falak turns off password login, so add a key first |
| ufw or firewalld active | Warning: allow ports in both firewalls |
| Existing swap, a customised automatic-updates config, own fail2ban jails | Kept |

On servers you connect yourself, Falak keeps the machine's hostname. Existing swap is kept instead of creating
`/swapfile`.

## Needs attention

If anything is blocked, the server shows **Needs attention** and nothing is installed. Open the server page: the
**Machine check** panel lists every component with what Falak found, what it will do, and for each blocked row the fix.

1. Fix the blocked items on the machine (for example `sudo systemctl disable --now nginx`).
2. Click **Re-check**.
3. When nothing blocks any more, click **Provision**.

A server that was already provisioned never goes to **Needs attention**: if a Re-provision finds a conflict, the
server keeps running as it is, its status message starts with "Re-provisioning stopped.", and nothing is applied.

The machine check needs agent v0.6.0 or later. Older agents provision as before; update the agent (server page →
**Update agent**), then **Re-provision**.

## API

`GET /api/v1/servers/{server}/inspection` returns the latest check and decisions. `POST` on the same path runs a
re-check, and `POST /api/v1/servers/{server}/provision` continues once nothing blocks. See
[Servers API](/docs/api/servers/#machine-check).

## Next steps
