Security hardening
This page explains Falak’s security model and what you should do on top of the defaults.
What Falak does by default
Section titled “What Falak does by default”Control plane
Section titled “Control plane”- TLS everywhere: Let’s Encrypt for the panel, HSTS (
max-age=31536000), the agent API on its own host with mutual TLS against Falak’s Fleet CA. - Secrets (site variables, git and provider credentials, database passwords, DNS tokens, GitHub App keys) are stored encrypted with
APP_KEYand never sent to the UI unless explicitly revealed. Reveals are audited. /opt/falak/.envis mode 600;backups/is mode 700.- Containers run with
no-new-privileges. The app trusts proxy headers only from the edge subnet (FALAK_EDGE_SUBNET). - Outbound requests the control plane makes on users’ behalf are guarded: alert webhooks, backup storage endpoints and template URL imports refuse private, loopback and link-local addresses by default.
Servers
Section titled “Servers”- The agent dials out; it listens only on loopback (OTLP) and a unix socket.
- Firewall: nftables, inbound drop by default; only SSH, plus 80/443 on servers that serve HTTP.
- SSH: keys only (
PasswordAuthentication no,PermitRootLogin prohibit-password,MaxAuthTries 4),fail2banrunning, unattended security upgrades on. - The
falakuser has no sudo. Sites can run as isolated Linux users. - Release and
shared/directories are mode 0750 with an ACL for the edge only; other local users cannot read.envorbootstrap/cache/config.php. - Deploys verify downloaded runtimes and agent binaries by SHA-256.
- Compose files are checked against a policy (no privileged containers, host namespaces, extra capabilities, host mounts, devices or Docker socket) unless an admin allows privileged Compose.
Hardening checklist
Section titled “Hardening checklist”| Action | |
|---|---|
| ☐ | Restrict sign-up. By default anyone who can reach the panel can create an account (with its own empty organization; it cannot see yours). On a public panel, set FALAK_REGISTRATION=invite (sign-up only through an invitation link) or closed (accounts only via falak-ctl admin create) in /opt/falak/.env, then falak-ctl up. See Who can sign up. |
| ☐ | Turn on two-factor authentication for every member (per user; not enforceable per organization yet). |
| ☐ | Give members the lowest role that works. recipes.run, terminal.*, fleet.agents.manage and sites.compose.policy are admin-only because they amount to root on your servers. |
| ☐ | Create scoped API tokens with expiry for CI and agents, never * tokens for automation. |
| ☐ | Schedule encrypted backups (FALAK_BACKUP_PASSPHRASE) and copy them off the host. The Fleet CA key and APP_KEY are in them. |
| ☐ | Restrict Grafana to operators: dashboards are not filtered per organization inside Grafana. |
| ☐ | Keep the database port closed; open it per source address only. See Remote access. |
| ☐ | Use your own domains in production, not shared sslip.io names (no cookie isolation between their users). |
| ☐ | Keep Allow privileged compose off unless you trust everyone who can create sites. |
| ☐ | Protect staging with basic auth or IP allow lists (routing rules). |
| ☐ | Limit SSH on servers to your IPs with a firewall rule if possible (the SSH port itself always stays open to avoid lock-out). |
| ☐ | Bind the panel to one address with FALAK_BIND if the host has several interfaces. |
| ☐ | Configure mail so password resets and alerts work. |
| ☐ | Watch the Audit log (audit.view). |
Known limits
Section titled “Known limits”- The alert webhook SSRF guard checks the host but does not resolve DNS, so DNS rebinding is not blocked.
- Deleting an organization revokes its agents but does not destroy provider machines.
- Octane’s FrankenPHP server binds its port on all interfaces; the default-drop firewall blocks it from outside.