minsec

Multiplayer mode

Report your bans; pull crowd-sourced bans.

Your server knows which addresses are attacking it. So does everyone else's. Multiplayer mode is how we help each other.

It is handled by the separate minsec-sync binary, so the resident daemon is tiny, fast, and auditable.

What is sent

One record per automatic ban:

FieldExampleNotes
ts1724371190when the ban fired
ip203.0.113.7/32the attacker's network, IPv6 aggregated to /64
filtersshdthe rule that matched — an opaque name, not free text
count5matching hits inside the ban window
ban_ttl3600local ban length, in seconds
escalation2repeat-offender depth for this attacker; omitted on a first ban

No log lines, usernames, hostnames, or anything about your users or your traffic. Manual bans and unbans are not reported.

Reports are signed with a per-install Ed25519 key generated at first enrollment. The server identifies the installation by a random UUID, nothing derived from your hardware or network. Full privacy statement.

Opting in

sudo install -m 0644 /usr/share/doc/minsec/sync.toml.example /etc/minsec/sync.toml
sudo systemctl enable --now minsec-sync.timer

The config file's presence is the switch. The timer runs minsec-sync run once an hour: it enrolls automatically on the first run (solving a small proof-of-work, a few seconds of one core), then reports new bans and refreshes the blocklist.

Report and pull are independent:

# /etc/minsec/sync.toml
report = true     # contribute your automatic bans
pull   = true     # pull the crowd blocklist

You can pull without contributing, or contribute without pulling. See minsec-sync.toml(5).

Opting out

sudo rm /etc/minsec/sync.toml
sudo nft flush set inet minsec crowd4
sudo nft flush set inet minsec crowd6

Removing the file stops everything at the next timer tick; the two flush commands clear the already-pulled list immediately.

The dynamic blocklist

The crowd list goes into its own nftables sets, crowd4 and crowd6, enforced after your allowlist and after your local bans. They are separate from ban4/ban6 so you can always tell which blocks came from the crowd:

sudo nft list set inet minsec crowd4

Full replaces are one atomic nft transaction; most refreshes are a delta or a 304 Not Modified.

Commands

minsec-sync status          # enrollment, cursor and feed state — start here
minsec-sync enroll          # generate key + enroll (run does this automatically)
minsec-sync report          # submit new automatic bans from the events log
minsec-sync pull            # refresh crowd4/crowd6
minsec-sync pull --dry-run  # print the nft script instead of applying it
minsec-sync run             # report + pull; what the timer runs

pull --dry-run is the honest answer to "what is this about to do to my firewall?" — it prints the exact nft script and applies nothing.

State — the key, the host id, the events-log cursor, the feed cursors — lives in /var/lib/minsec/sync/.

How an address gets listed

Nothing is published on one report. An address enters the feed only when enough independent installations agree on it, each vote weighted by that reporter's standing, and quorum is counted per abuse category rather than in aggregate. Independence is counted by enrollment network rather than by key, so minting extra keys buys no extra votes. New agents start on probation: their reports carry weight but do not count toward quorum until the probation period is up. Each agent has a daily ceiling on what it can store; an agent that keeps pushing past it is quarantined and its reports accepted-and-discarded. One noisy or hostile agent moves nothing.

Expiry happens server-side, on a 48-hour horizon unless the address is seen again, and arrives as removals in the next delta.

The crowd sets also expire on their own, as a failsafe. Entries are added with a 24-hour kernel timeout, and any pull that finds the last full replace more than 12 hours old refetches the whole list and rewrites the set, restarting the clock. A working sync never lets anything expire; a sync that stops — dead network, backend outage, a timer someone disabled — drains crowd4 and crowd6 within a day, instead of enforcing a frozen snapshot until the machine reboots. Your own bans in ban4/ban6 are untouched.

minsec-sync status prints the age of the last successful pull and of each family's last full replace, so a sync that has quietly stopped is visible.

Details of the tiers and the delta protocol: blocklist feed.

Wrongly listed?

Mail delist@minsec.io with the address. Delisting removes it from the blocklist feed and the DNSBL together, and takes effect at the next scoring tick — usually a few minutes. The DNSBL and the feed are correct from that moment; agents drop the address at their next hourly pull.