Binions ships hardened by default, so a fresh install is locked down before you change a thing. Every daemon runs as its own restricted user inside a strict systemd sandbox, the host carries a default-drop firewall, and only one service — the Traefik web edge — is meant to face the public internet. This page explains what that hardening is and the few steps left to you as the operator.
Secure by default. The defaults below are applied at install time. You do not need to enable them — the operator’s job is to keep them in place and protect the one public edge.
Binions installs an nftables firewall with a default-drop policy: anything not explicitly allowed is rejected. Because the whole platform runs on a single host and the daemons talk to each other over the loopback interface, very little needs to be reachable from outside at all. Network surfaces fall into three clear tiers:
| Tier | What it is | Who can reach it |
|---|---|---|
| Public | The Traefik HTTP/HTTPS edge — the front door for any web traffic you publish | The internet (behind your own firewall) |
| LAN / cluster only | The object-storage (S3) endpoint and the tracing UI | Your LAN / cluster |
| Loopback only | Every daemon’s /health and /metrics, the Traefik admin API, the storage console | The host itself — never off-host |
In short: only the web edge is exposed by design. Health and metrics endpoints and all admin APIs stay on the host’s loopback address and are never published.
Each of the platform’s background services is isolated at the operating-system level. Every daemon runs as its own dedicated service user (one user per daemon, with no login shell and no privileges it doesn’t need), and its systemd unit applies a hardened sandbox. The key protections are:
NoNewPrivileges stops a daemon (or anything it spawns) from gaining new rights.ProtectSystem=strict makes the OS file tree read-only, so a daemon can only write to the few paths it owns.ProtectHome hides /home, /root, and /run/user from the service.PrivateTmp gives each daemon its own isolated /tmp.SystemCallFilter allow-lists only the system calls the daemon needs.MemoryHigh / MemoryMax bound how much RAM a daemon can use, so one service can’t starve the host.The practical effect is containment: even if one daemon were compromised, the blast radius is a single unprivileged user that can’t escalate, can’t write to the system, and can’t read another daemon’s files or secrets.
The webhook caller — the daemon that lets a playbook make outbound HTTP requests — carries an SSRF allow-list (server-side request forgery protection). Outbound targets must be explicitly listed; an empty list denies everything. This means a malformed or hostile input can’t trick a playbook into calling arbitrary addresses on your internal network. Add only the destinations your automations genuinely need.
Tip. Treat the webhook allow-list like the firewall: start closed, then open exactly the destinations a playbook requires. The default deny-all is the safe state.
The hardening above is in place out of the box. A handful of operator responsibilities complete the picture:
You can confirm a daemon’s sandbox at any time by inspecting its unit. For example:
systemctl show binions-webhookcaller \
--property=NoNewPrivileges,ProtectSystem,ProtectHome,PrivateTmp,MemoryMax
Good to know. Hardening is layered: the firewall limits what can reach the host, the sandbox limits what each daemon can do on it, and the allow-list limits where a daemon can reach out. No single control is the whole defence — together they keep the platform contained.