No manual router commands
RouterOS Bouncer
How it works
Section titled “How it works”- CrowdSec decidesThe Local API holds a decision about an address.
- The bouncer syncsIt reads new decisions and expires the ones that ended.
- RouterOS enforcesAddresses land on a firewall address list the managed rules match.
- You watch itPrometheus metrics, a health endpoint and a Grafana dashboard.
Why cs-routeros-bouncer? 1.5.0
Section titled “Why cs-routeros-bouncer? ”Most MikroTik bouncers regenerate an address list from a scheduled script. This one keeps a session open and applies each CrowdSec decision as a single call to the RouterOS API.
Per-decision writes (~1–3 ms/op)
Reconciliation, not hope
Observable while it runs
One binary, MIT-licensed
What it writes to your router
Section titled “What it writes to your router”CrowdSec decides which addresses are hostile. This bouncer enforces that decision and does nothing else — no detection, no scoring, no opinion of its own. Enforcing means writing to a production firewall, so here is the whole of what it writes, and the whole of what it will not clean up for you.
What it writes
A stock configuration puts 8 rules on the router: 4 kinds, one set per protocol family. These, verbatim.
/ip/firewall/filter add chain=input action=passthrough comment="crowdsec-bouncer:filter-input-counting-v4 @cs-routeros-bouncer"/ip/firewall/filter add chain=input action=drop src-address-list=crowdsec-banned comment="crowdsec-bouncer:filter-input-input-v4 @cs-routeros-bouncer"/ip/firewall/raw add chain=prerouting action=passthrough comment="crowdsec-bouncer:raw-prerouting-counting-v4 @cs-routeros-bouncer"/ip/firewall/raw add chain=prerouting action=drop src-address-list=crowdsec-banned comment="crowdsec-bouncer:raw-prerouting-input-v4 @cs-routeros-bouncer"/ipv6/firewall/filter add chain=input action=passthrough comment="crowdsec-bouncer:filter-input-counting-v6 @cs-routeros-bouncer"/ipv6/firewall/filter add chain=input action=drop src-address-list=crowdsec6-banned comment="crowdsec-bouncer:filter-input-input-v6 @cs-routeros-bouncer"/ipv6/firewall/raw add chain=prerouting action=passthrough comment="crowdsec-bouncer:raw-prerouting-counting-v6 @cs-routeros-bouncer"/ipv6/firewall/raw add chain=prerouting action=drop src-address-list=crowdsec6-banned comment="crowdsec-bouncer:raw-prerouting-input-v6 @cs-routeros-bouncer"Banned addresses go on crowdsec-banned and crowdsec6-banned. The two passthrough rules match no address list and take no decision; they count the packets the block evaluates, which is what makes “evaluated” and “dropped” two separate numbers in the metrics.
What it does not do
- It enforces; it does not decide
- Every ban comes from CrowdSec. Take CrowdSec away and this has nothing to write: no scenarios, no scoring, no address of its own. How a decision becomes a rule
- One decision type, not four
- Of the CrowdSec decision types,
banis the only one enforced by default. The bouncer has exactly one action — put the address on a list the firewall drops — so a captcha decision could be listed incrowdsec.supported_decisions_typesbut would be enforced as a block, which is not what a captcha means. The setting is there for custom decision types that do mean “block”. How decisions are processed - The rules go in at the top
- By default the managed block is inserted at the top of every chain it touches, above your existing rules:
firewall.rule_placement.strategyistopby default. For an operator whose ruleset is ordered deliberately this is the most consequential thing the bouncer does to it — so it is worth saying that placement is the most configurable thing here, not the least: five strategies (top,bottom,before_comment,after_comment,position), each overridable per table and per protocol family, with a fallback for when the anchor rule is missing. Rule placement - The first sync is a bulk import
- The first reconciliation pulls every active decision the Local API holds, CrowdSec's CAPI community blocklists included:
crowdsec.originsis empty by default, so no origin is filtered out. That is tens of thousands of addresses written in one pass, and on a small router you will watch it happen in the CPU graph. CAPI blocklists - Every reconciliation pass costs the router CPU
- Not only at startup, and not only when there is drift to repair: the pass runs on every
crowdsec.reconciliation_intervaltick and re-reads the whole address list each time, because RouterOS evaluates address-list queries with an unindexed linear scan. Measured on an RB5009 holding 22,000 entries, sampled at 100 ms on the router itself: a ~2-second plateau averaging 31% against a 5% baseline, with single-core slices reaching 50–100%, in every cycle. At the default 15-minute interval that is four transients an hour. Your own monitoring may well not show it — the standard SNMPhrProcessorLoadOID reports a one-minute average, which flattens a two-second spike to roughly 6%. Performance tuning - What the daemon leaves behind
- Shutdown removes every rule above and no address-list entry. Entries expire on their own MikroTik timeout, which is the CrowdSec decision duration; protection therefore outlives the daemon by whatever is left of it.Caveat: A decision whose duration resolves to zero or less — CrowdSec does emit negative remaining durations — is written with no timeout at all, so that entry stays on the router until something removes it: the next reconciliation, or you. A decision carrying no duration field is discarded earlier and never reaches the router.
Requirements
Section titled “Requirements”- CrowdSec 1.5+ with the Local API reachable from the host running the bouncer
- MikroTik RouterOS 7.x with the API service enabled (port 8728, or 8729 for TLS)
- A dedicated RouterOS API user with permission to read and write firewall rules and address lists
Frequently asked questions
Section titled “Frequently asked questions”What is cs-routeros-bouncer?
cs-routeros-bouncer is a free, open-source CrowdSec bouncer for MikroTik RouterOS. It syncs CrowdSec ban/unban decisions into RouterOS firewall rules (filter and raw, IPv4 and IPv6) through the RouterOS API, with startup and periodic reconciliation, Prometheus metrics, and safe rule cleanup.
Which CrowdSec and RouterOS versions does it support?
It requires CrowdSec 1.5+ with the Local API (LAPI) reachable from the bouncer host, and MikroTik RouterOS 7.x with the API service enabled (port 8728, or 8729 for TLS), using a dedicated RouterOS API user with the appropriate permissions.
Is cs-routeros-bouncer free and open source?
Yes. cs-routeros-bouncer is MIT-licensed, written in Go, distributed as a single static binary, with the full source on GitHub and no paid tier.
Does cs-routeros-bouncer support IPv6?
Yes. Each RouterOS rule type it manages (filter input, raw prerouting, and optional filter output) has an IPv6 equivalent, and IPv4/IPv6 rule placement can be configured together or overridden independently per protocol.
How is cs-routeros-bouncer different from address-list or script-based CrowdSec bouncers for MikroTik?
cs-routeros-bouncer talks to the RouterOS API directly and applies each ban or unban as an individual real-time call (about 1–3 ms), instead of periodically regenerating address lists via scheduled scripts. It also runs startup and periodic reconciliation against MikroTik's actual state, so drift is repaired automatically.