Capabilities
How each agent decides which features it exposes, configured entirely on the agent host.
ServerBee enforces the principle of least privilege through per-agent capabilities. Capabilities are owned by the agent host: each agent computes its own capability set from its config file (and optional CLI flags) and reports it to the server. The server can read and display these capabilities, but it cannot change them — there is no server-side toggle.
This is a deliberate trust-boundary decision. The machine that runs the agent is the only place that decides what that agent will do. A compromised or misconfigured server cannot silently turn on a remote shell, file access, or command execution on your hosts.
Capability List
ServerBee defines 11 capability bits across two risk levels. The valid mask is 2047 (bits 0..=10).
High Risk (Disabled by Default)
| Capability | Key | Bit Value | Description |
|---|---|---|---|
| Web Terminal | terminal | CAP_TERMINAL (1) | Allow opening a remote terminal via browser |
| Remote Exec | exec | CAP_EXEC (2) | Allow remote command execution |
| File Manager | file | CAP_FILE (64) | Allow remote file browsing, editing, upload/download |
| Docker Management | docker | CAP_DOCKER (128) | Allow Docker container monitoring, log streaming, and container actions |
These capabilities allow executing arbitrary code or accessing the filesystem on the target server, so they are disabled by default. Enable them only on trusted hosts by editing that host's agent config.
File Manager requires additional agent-side configuration (root_paths, deny_patterns) for path sandbox security. See the Agent Setup and Configuration pages for details.
Low Risk (Enabled by Default)
| Capability | Key | Bit Value | Description |
|---|---|---|---|
| Auto Upgrade | upgrade | CAP_UPGRADE (4) | Allow remote binary upgrades |
| ICMP Ping | ping_icmp | CAP_PING_ICMP (8) | Allow ICMP probe tasks |
| TCP Probe | ping_tcp | CAP_PING_TCP (16) | Allow TCP port probe tasks |
| HTTP Probe | ping_http | CAP_PING_HTTP (32) | Allow HTTP probe tasks |
| Security Events | security_events | CAP_SECURITY_EVENTS (256) | Allow agent to report SSH login / brute-force / port-scan events (see Security Events) |
| Firewall Blocklist | firewall_block | CAP_FIREWALL_BLOCK (512) | Allow agent to apply the server-pushed nftables blocklist. Requires root or CAP_NET_ADMIN plus the nft CLI on the host. See Firewall Blocklist |
| IP Quality | ip_quality | CAP_IP_QUALITY (1024) | Allow the Agent to run service-unlock probes and report results; optional metadata and risk enrichment runs on the Server |
An agent with no [capabilities] overrides defaults to 1852 (auto upgrade + the three ping probes + security events + firewall blocklist + IP quality), which keeps the high-risk terminal, exec, file, and Docker capabilities off.
Configuring Capabilities (on the agent host)
An agent computes its capability bitmask as:
- Start from the built-in default set (
CAP_DEFAULT = 1852). - Apply the config file
[capabilities]block —allowadds bits,denyremoves bits. Within this layer,denywins overallow. - Apply CLI
--allow-cap/--deny-capflags on top, for ad-hoc overrides. The CLI layer wins over the config layer. - Reconcile against subsystem availability:
fileis dropped unless[file].enabled = truewith at least oneroot_path, andfirewall_blockis dropped when the startupnftprobe fails (binary, kernel, or privileges missing). A reported capability always means the agent can actually serve it.
Unknown capability keys are a hard error at startup, so a typo fails fast rather than silently dropping a capability.
Config file
For installer-managed deployments, edit /opt/serverbee/etc/agent.toml on the agent host. Manual deployments may use /etc/serverbee/agent.toml or agent.toml in the working directory:
[capabilities]
# Turn on high-risk capabilities this host should expose.
allow = ["terminal", "file"]
# Strip default capabilities this host should not expose.
deny = ["ip_quality"]Restart the agent for changes to take effect:
sudo serverbee restart agentEnvironment variables
The same block can be supplied via environment variables (Figment, SERVERBEE_ prefix, __ nesting):
SERVERBEE_CAPABILITIES__ALLOW=["terminal","file"]
SERVERBEE_CAPABILITIES__DENY=["ip_quality"]CLI flags
For one-off overrides, pass repeated flags when launching the agent:
serverbee-agent --allow-cap terminal --allow-cap file --deny-cap ip_qualityAt install time
The install script accepts --caps to seed the agent's capability config during enrollment:
curl -fsSL https://raw.githubusercontent.com/ZingerLittleBee/ServerBee/main/deploy/install.sh | sudo sh -s -- agent \
--server-url https://monitor.example.com \
--enrollment-code YOUR_ONE_TIME_CODE \
--caps terminal,fileRunning the installer interactively also prompts for capabilities, with the defaults pre-checked.
Temporary grants
Editing the config and restarting the agent is the right way to enable a capability permanently. For short-lived, ad-hoc needs — "give me a terminal on this box for the next 30 minutes" — the agent ships a host-local CLI that temporarily turns on an off-by-default capability, then automatically turns it back off when the window ends.
Temporary grants are a host-local mechanism, fully consistent with the agent-owned trust model: only someone with a shell on the agent host can issue one. The server and the web/iOS UI remain read-only and cannot grant a capability. The server merely mirrors what the agent reports, gates control-plane requests on it, audits the change, and can fire an alert.
CLI
Run these subcommands on the agent host (typically with sudo, since they write under state_dir and the daemon usually runs as the agent user/root). They share the daemon's config (/opt/serverbee/etc/agent.toml for installer-managed deployments), so the grants file location and the maximum duration come from the same [capabilities] block.
# Temporarily enable an off-by-default capability for a bounded duration.
serverbee-agent grant terminal --for 30m --reason "debugging a stuck deploy"
serverbee-agent grant file --for 2h
serverbee-agent grant docker --for 1d
# Revoke an active grant early.
serverbee-agent revoke terminal
# List the currently active grants (cap, remaining seconds, who granted it, reason).
serverbee-agent grants- The duration passed to
--foris<number><unit>where the unit is one ofs(seconds),m(minutes),h(hours), ord(days) — e.g.90s,30m,2h,1d.--reasonis optional free-form text recorded with the grant. grantonly turns on a capability that is currently off. Granting a capability that is already enabled inagent.tomlis rejected ('terminal' is already enabled in agent.toml; nothing to grant).- A duration longer than
temporary_max_duration(default24h, see Configuration) is refused. - The CLI is one-shot: it writes the grants file and exits. The running daemon picks the change up within a few seconds — there is no need to restart the agent.
Restart and expiry semantics
Grants are persisted to <state_dir>/capability_grants.json (default /var/lib/serverbee/capability_grants.json, written 0600) with an absolute expires_at (a Unix epoch timestamp), not a relative countdown. This makes the behavior robust:
- Survives restarts — if the agent restarts mid-window, the grant is reloaded and remains active for the rest of its original window.
- Expires at the original deadline — restarting does not extend a grant. A grant for
30mexpires 30 minutes after it was issued regardless of how many times the agent restarts in between. - Fails safe to OFF — if the grants file is missing, empty, corrupt, or written by an unknown schema version, the agent treats it as "no grants" and the capability stays off. A temporary grant can never strengthen the permanent set; it can only flip an otherwise-off bit on for its window.
- Expiry bounds running work, not just new requests — when a
terminalgrant expires or is revoked, live terminal sessions opened under it are closed immediately (the browser sees the session end), and asecurity_eventsgrant starts the agent's security pipeline the moment it becomes effective and stops it when the window closes — including grants issued while the agent was already running.
What the server sees
When a grant becomes active (or expires/is revoked), the agent re-reports its effective capability set, so the server opens or closes the gate live:
- The change is mirrored into
servers.capabilitiesand broadcast to browsers, so the UI updates in real time. - The transition is written to the audit log as
capability_temporarily_granted,capability_grant_expired, orcapability_grant_revoked. - A temporary grant of a high-risk capability (
terminal,exec,file, ordocker) also evaluates the event-drivencapability_grant_detectedalert rule. Expiry, revoke, and low-risk grants are audited but do not fire an alert. - Everything the agent executes for the server is re-synced against the new capability set: ping tasks are re-filtered, network probe targets and IP-quality services are re-pushed, and the firewall blocklist is reset (and re-sent only while
firewall_blockis still effective). Revoking a ping capability stops those probes immediately, and revokingfirewall_blockremoves ServerBee's nftables rules from the host without waiting for a reconnect.
A grant issued while the agent is disconnected from the server is applied locally and shows up on reconnect, but it does not produce a granted audit entry or alert. The server only sees the post-reconnect capability state, not the moment of transition, so it cannot distinguish a freshly-granted capability from one that was already active. Plan around this if you rely on the alert as a tripwire.
In the web UI
While a temporary grant is active, the affected capability is shown with an amber Temporary badge and a live countdown to expiry, in both the Server Detail → Capabilities dialog and the Settings → Capabilities fleet matrix. The badge disappears automatically when the grant expires or is revoked.
Enforcement model
The agent host is the single source of truth, but enforcement happens at two boundaries for defense in depth.
Server-side gating (based on reported capabilities)
The server records what each agent reports and rejects control-plane requests for capabilities the agent has not enabled:
- Terminal: the WebSocket upgrade is rejected with 403
- Exec:
POST /api/tasksand scheduled task runs filter out servers whose agent lacksexecand write synthetic results (exit_code = -2) - Auto Upgrade:
POST /api/servers/{id}/upgradereturns 403 whenupgradeis not reported - Ping and Traceroute: probe tasks are filtered by capability; traceroute requires
ping_icmp - File Manager: file endpoints reject requests before dispatch when
fileis not reported - Docker: Docker read/action endpoints and the Docker log WebSocket routes require
dockerand agent runtime Docker support
Because capabilities are agent-owned, the denial reason is always agent_capability_disabled.
Agent-side enforcement
Even if a server-side request slips through, the agent re-checks capabilities locally:
- It returns a
CapabilityDeniedmessage for unauthorized commands - On receiving
CapabilityDenied, the server writes a synthetic result (exit_code = -1) - Denial events are recorded in the audit log
Reporting and display
When an agent connects (or reconnects), it sends SystemInfo carrying agent_local_capabilities. The server:
- Persists that value into the
servers.capabilitiescolumn as a display mirror (so the dashboard can show capabilities even while the agent is offline). - Broadcasts
CapabilitiesChangedto all connected browsers so the UI reflects the current set in real time.
If ping-related bits change between reconnects, the server automatically re-syncs ping tasks for the agent.
Frontend behavior
The web and iOS clients display capabilities read-only:
- Server Detail → Capabilities: a read-only summary of which capabilities the agent has enabled, with a note that they are configured in the agent config file
- Settings → Capabilities: a read-only fleet matrix showing the enabled/disabled state per server
- Tasks page: servers whose agent lacks
execare greyed out - Terminal button: hidden for servers whose agent lacks
terminal - Files button: hidden for servers whose agent lacks
file - Docker link: hidden for servers whose agent lacks
docker
Runtime capability fields
The server response exposes three capability fields, which are all equal under the agent-owned model:
capabilities: the persisted mirror of the last value the agent reportedagent_local_capabilities: the live value reported by the connected agenteffective_capabilities: the value actually enforced (identical to the agent-local value)
The fields are kept distinct in the API for forward compatibility and so an offline server can still display its last-known capabilities from the mirror.