Skip to content

Security hardening

This page explains Falak’s security model and what you should do on top of the defaults.

  • 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_KEY and never sent to the UI unless explicitly revealed. Reveals are audited.
  • /opt/falak/.env is 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.
  • 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), fail2ban running, unattended security upgrades on.
  • The falak user 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 .env or bootstrap/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.
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).
  • 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.