Firewall Blocklist

Block inbound traffic from IPs and CIDRs across one or more agents via nftables.

ServerBee can centrally manage an inbound-traffic blocklist. The server holds the canonical list, and each opted-in agent applies it via nftables.

Requirements

  • Linux only — agent uses the nft CLI.
  • CAP_FIREWALL_BLOCK (bit 512) must be enabled on the agent. It is on by default; capabilities are agent-owned, so to turn it off add firewall_block to the agent's [capabilities] deny list. See Capabilities.
  • Agent process needs root or CAP_NET_ADMIN.

Manual blocking

Settings → Firewall → Add block. Enter an IP (1.2.3.4) or a CIDR (10.0.0.0/8). Choose the scope (All servers, Selected, All except). Optionally add a comment.

The server rejects targets that overlap a protected range:

  • Loopback (127.0.0.0/8, ::1)
  • RFC 1918 (10/8, 172.16/12, 192.168/16, fc00::/7, fe80::/10)
  • Multicast / unspecified
  • Any CIDR in firewall.allow_list (server.toml)
  • server.trusted_proxies
  • Any agent's reported external IP

A 409 response with the matched reason is returned in those cases.

Protect your own public IP. The "agent external IP" guardrail relies on the IPv4 / IPv6 address each agent reports about itself. On hosts where the agent's primary interface is a private bridge (Docker, NAT VPS, multi-homed), the reported address may not be the real public IP — and the guardrail will not catch an attempt to block it.

To be safe, add your VPS's public IP (or CIDR) to firewall.allow_list in server.toml. Anything that overlaps this list is refused at create time, no matter who requests it. Example:

[firewall]
allow_list = ["198.51.100.42", "203.0.113.0/29"]

This is also the way to protect your bastion / admin IPs from accidental auto-block actions.

Auto-block from alerts

Brute-force and port-scan alert rules can append a block_source_ip action that auto-inserts the event's source IP. See Security Events → Auto-block source IP.

Auto-block is deduplicated by canonical target. If a row already exists and covers the triggering server, the auto-block is silently skipped. If it exists but does not cover the triggering server, the conflict is audited (firewall_auto_block_skipped_conflict) and no row is created — the operator can broaden the existing row manually.

Agent execution

Each opted-in agent maintains an inet serverbee nftables table:

table inet serverbee {
    set block_v4 { type ipv4_addr; flags interval; }
    set block_v6 { type ipv6_addr; flags interval; }
    chain input {
        type filter hook input priority -10;
        ip  saddr @block_v4 drop
        ip6 saddr @block_v6 drop
    }
}

The server pushes incremental adds/removes over WebSocket. On agent reconnect or capability transition, it sends a Reset followed by a full Sync. The agent acks the result of each entry; failed entries stay eligible for retry on the next sync.

Removing the cleanup

Capabilities are Agent-owned, so there is no Server-side switch. To stop using the feature:

  1. On the Agent host, add firewall_block to [capabilities].deny in /opt/serverbee/etc/agent.toml (preserve any existing deny entries).
  2. Run sudo serverbee restart agent. The capability transition resets the synchronized blocklist and removes ServerBee's table.
  3. Verify with sudo nft list table inet serverbee. If the Agent could not complete the reset (for example it was offline or lacked nftables privileges), remove only ServerBee's table manually:
sudo nft delete table inet serverbee

Audit log

Every action is recorded in the audit log and shown on the Firewall page's Activity tab: firewall_block_created, firewall_block_deleted, firewall_block_applied_agent, firewall_block_removed_agent, firewall_block_rejected_server, firewall_block_rejected_agent, firewall_auto_block_skipped_conflict, firewall_reset_acked.

Limitations

  • nftables only — no iptables fallback
  • IPv4 and IPv6, no domain names
  • Permanent blocks — no scheduled expiry
  • input chain only — does not filter forward / output