Back to blog

MikroTik / RouterOS  ·  Tutorial  ·  August 2026

The RouterOS Firewall
Properly

Every MikroTik ships with a default firewall that's actually decent — and almost every broken MikroTik we audit had it "improved" by someone copying rules they didn't understand. This post builds the firewall from first principles: connection tracking, a default-deny input chain that can't lock you out, a forward chain with FastTrack that doesn't sabotage your QoS, and address lists that make brute-force attacks boring.

RouterOS Firewall Connection Tracking FastTrack Address Lists Hardening MTCNA+

RouterOS chain=input → the router itself chain=forward → traffic through it SSH/WinBox to the router LAN client → internet out the WAN Two different questions: "may you talk TO me?" (input) vs "may you talk THROUGH me?" (forward). Confusing them is firewall bug #1.

The RouterOS firewall is netfilter underneath — the same engine as Linux iptables — and it rewards the same mental model: packets traverse chains of rules top-to-bottom, the first matching rule wins, and a connection-tracking table lets one cheap rule ("already established? accept") handle 99% of packets so the expensive decisions only run on the first packet of each connection.

Everything in this post hangs off three rules of thumb: input protects the router, forward protects the network, and anything not explicitly accepted gets dropped. We'll build both chains in the order that can't lock you out, wire in the inter-VLAN isolation that the VLAN post promised, turn on FastTrack without breaking the QoS post's queues, and finish with the address-list pattern that turns SSH brute-force from a threat into a log line.

Prerequisites

01

Connection Tracking — the Engine Under Everything

The firewall doesn't judge packets; it judges connections. Understand the four states and every rule in this post becomes obvious.

StateMeaning — and what to do with it
newFirst packet of a connection. The only state that needs a real decision.
establishedBelongs to a connection we already allowed. Accept, cheaply, first.
relatedNew connection spawned by an allowed one (FTP data, ICMP errors). Accept with established.
invalidTracker can't place it — stray RSTs, spoofed junk, asymmetric leftovers. Drop, always.
RouterOS — watch the tracker do its job (safe)
[admin@MikroTik] > /ip/firewall/connection print where dst-address~":443"
 #  PROTO  SRC-ADDRESS           DST-ADDRESS          TCP-STATE   TIMEOUT
 0  tcp    192.168.88.34:52114   142.250.184.4:443    established 23h59m
 1  tcp    192.168.88.51:49220   104.18.32.7:443      established 23h58m

# Every rule below that says connection-state= is consulting this table.
💡 Why State-First Is Also a Performance Rule

A busy hotel edge pushes millions of packets a minute through the firewall, but only a few hundred new connections. With the established/related accept at the top of the chain, the expensive rules below it — address lists, interface matches, port checks — run only on those few hundred. Order your chains by match frequency and the CPU barely notices the firewall exists; order them carelessly and a hEX starts dropping packets at 300 Mb/s.

02

The Input Chain — Protect the Router

Input is traffic addressed to the router itself: WinBox, SSH, DNS queries, pings. The goal is a chain that ends in drop — built in an order that can't strand you outside.

RouterOS — default-deny input, lockout-proof order
# SAFE MODE FIRST. Ctrl+X in the terminal — if you cut yourself off,
# the session drop reverts everything. Non-negotiable for firewall work.
[admin@MikroTik] > [Safe Mode taken]

[admin@MikroTik] > /ip/firewall/address-list
[admin@MikroTik] /ip/firewall/address-list> add list=MGMT address=192.168.88.0/24 comment="management subnet"

[admin@MikroTik] > /ip/firewall/filter
# 1. The cheap accept that handles almost everything
[admin@MikroTik] /ip/firewall/filter> add chain=input action=accept connection-state=established,related comment="accept est/rel"
# 2. Kill the junk early
[admin@MikroTik] /ip/firewall/filter> add chain=input action=drop connection-state=invalid comment="drop invalid"
# 3. ICMP — keep ping and path-MTU working
[admin@MikroTik] /ip/firewall/filter> add chain=input action=accept protocol=icmp comment="accept icmp"
# 4. Management, only from the management list
[admin@MikroTik] /ip/firewall/filter> add chain=input action=accept src-address-list=MGMT comment="mgmt access"
# 5. LAN needs the router's DNS (remove if clients use external DNS)
[admin@MikroTik] /ip/firewall/filter> add chain=input action=accept protocol=udp dst-port=53 in-interface-list=LAN comment="LAN dns"
# 6. THE WALL — everything else, gone
[admin@MikroTik] /ip/firewall/filter> add chain=input action=drop comment="drop all else"

# Still connected? Good. Release Safe Mode (Ctrl+X again) to commit.
⚠ Gotcha — The Drop Rule Is a One-Way Door

Rules 1–5 before rule 6 is not a style preference. Add the final drop first (or move it up while "reorganizing") and the moment it commits, your own session's packets stop matching anything above it — established saves an existing SSH session, but WinBox reconnects, DNS, and every future login die. This is the single most common way people brick remote MikroTiks. Safe Mode exists precisely for this; the second layer of protection is testing from a separate session before closing the one that made the change.

03

The Forward Chain — Protect the Network

Forward is everything transiting the router: LAN to internet, VLAN to VLAN, internet to your port-forwards. Same default-deny logic, two new ideas — FastTrack and the DSTNAT exception.

RouterOS — default-deny forward
# 1. FastTrack the established bulk (see section 04 before enabling!)
[admin@MikroTik] /ip/firewall/filter> add chain=forward action=fasttrack-connection hw-offload=yes connection-state=established,related comment="fasttrack"
[admin@MikroTik] /ip/firewall/filter> add chain=forward action=accept connection-state=established,related comment="accept est/rel"
[admin@MikroTik] /ip/firewall/filter> add chain=forward action=drop connection-state=invalid comment="drop invalid"

# 2. Inter-VLAN isolation — guests and IoT see the internet, nothing else
#    (interface lists from the VLAN post: LAN = all SVIs, WAN = uplinks)
[admin@MikroTik] /ip/firewall/filter> add chain=forward action=drop in-interface=vlan20-guest out-interface-list=LAN comment="guest isolation"
[admin@MikroTik] /ip/firewall/filter> add chain=forward action=drop in-interface=vlan30-iot out-interface-list=LAN comment="iot isolation"

# 3. From the internet, only port-forwarded traffic gets in
[admin@MikroTik] /ip/firewall/filter> add chain=forward action=accept connection-state=new connection-nat-state=dstnat in-interface-list=WAN comment="allow port-forwards"
[admin@MikroTik] /ip/firewall/filter> add chain=forward action=drop connection-state=new in-interface-list=WAN comment="drop unsolicited WAN"

# 4. LAN out to the world
[admin@MikroTik] /ip/firewall/filter> add chain=forward action=accept in-interface-list=LAN out-interface-list=WAN comment="LAN to internet"
[admin@MikroTik] /ip/firewall/filter> add chain=forward action=drop comment="drop all else"
💡 connection-nat-state=dstnat Is the Port-Forward Post, Finished

The port-forwarding post created dst-nat rules; this chain is what decides whether that traffic may actually pass. Matching connection-nat-state=dstnat instead of enumerating ports means every current and future port-forward is automatically allowed — and only port-forwards, because unsolicited WAN traffic that didn't hit a dst-nat rule fails the match and dies at the next rule. Add a forward, never touch the filter again.

04

FastTrack — Free Speed, With One Sharp Edge

FastTrack lets established connections bypass most of the firewall, NAT, and — this is the sharp edge — the queue engine. It can double throughput on small CPUs, and it silently disables QoS.

When a connection is fasttracked, its packets skip the rest of the filter rules, most of mangle, and simple queues and queue trees never see them. On a hEX pushing a gigabit, that's the difference between 60% CPU and 15%. On the hotel network from the QoS post, it's also the reason the guest bandwidth limits stopped working the day someone enabled FastTrack "for performance".

RouterOS — fasttrack selectively when QoS matters
# Option A — no QoS on this box: fasttrack everything (section 03 rule)

# Option B — QoS on guest traffic only: exempt guests from fasttrack
# so the queues still shape them, fasttrack the rest
[admin@MikroTik] /ip/firewall/filter> add chain=forward action=fasttrack-connection connection-state=established,related src-address=!10.20.0.0/24 dst-address=!10.20.0.0/24 comment="fasttrack non-guest"

# Check what's actually being fasttracked:
[admin@MikroTik] > /ip/firewall/filter print stats where action=fasttrack-connection
 #  CHAIN    ACTION                 BYTES         PACKETS
 0  forward  fasttrack-connection   84 812 331 90    71 224 118
⚠ Gotcha — "My Queues Show Zero Traffic"

If queues report almost no traffic while users clearly saturate the line, FastTrack is eating the packets before the queue engine runs. The counters don't lie — they just count what they're allowed to see. Either scope the fasttrack rule around the traffic you shape (Option B), or accept that on that box you get FastTrack or QoS per flow, not both. The same applies to mangle-based routing: fasttracked flows ignore routing marks set after the first packet.

05

Address Lists — the Firewall That Updates Itself

An address list is a named set of IPs that rules can match — and that rules can WRITE to, with timeouts. That closes the loop: the firewall observes, records, and reacts.

RouterOS — classic staged SSH brute-force trap
# Anyone opening a NEW connection to :22 gets logged in stage1.
# Doing it again within a minute promotes them stage by stage to a 10-day ban.
# Rules must sit ABOVE the mgmt accept in the input chain.
[admin@MikroTik] /ip/firewall/filter> add chain=input action=drop protocol=tcp dst-port=22 src-address-list=ssh-blacklist comment="drop banned"
[admin@MikroTik] /ip/firewall/filter> add chain=input action=add-src-to-address-list protocol=tcp dst-port=22 connection-state=new src-address-list=ssh-stage2 address-list=ssh-blacklist address-list-timeout=10d comment="stage3: ban"
[admin@MikroTik] /ip/firewall/filter> add chain=input action=add-src-to-address-list protocol=tcp dst-port=22 connection-state=new src-address-list=ssh-stage1 address-list=ssh-stage2 address-list-timeout=1m comment="stage2"
[admin@MikroTik] /ip/firewall/filter> add chain=input action=add-src-to-address-list protocol=tcp dst-port=22 connection-state=new address-list=ssh-stage1 address-list-timeout=1m comment="stage1"

# A week later, on any internet-facing box:
[admin@MikroTik] > /ip/firewall/address-list print count-only where list=ssh-blacklist
347   ← 347 bots banning themselves, zero admin effort

The same primitive solves half of practical firewalling: a MGMT list you edit in one place instead of in five rules; a country allow-list fed by a script; a wireguard-peers list the VPN post will use. When a match criterion appears in more than one rule, it should probably be an address list.

06

Verify It Actually Fires Safe to Run

A firewall you haven't tested is a hypothesis. Counters, logging, and a deliberate attack from the guest VLAN turn it into a fact.

CommandWhat it proves
/ip/firewall/filter print statsPer-rule packet counters — a rule with 0 packets forever is dead weight or mis-ordered.
/ip/firewall/connection printLive connection table — states, timeouts, who's talking to whom.
/ip/firewall/address-list printCurrent list membership, including dynamic entries with countdown timers.
/log print where topics~"firewall"Hits on rules with log=yes — turn it on per-rule while testing, off after.
/tool/torchLive per-flow view of an interface while you generate test traffic.

Then the honest test, same discipline as the VLAN post: connect a laptop to the guest VLAN and try to break in. Ping the CCTV subnet (must fail), WinBox to the router (must fail), browse the internet (must work), then watch your attempts land in filter print stats on the isolation rules. A counter that incremented while you attacked is the only proof a drop rule ever gives you.

Takeaways

  1. Input protects the router, forward protects the network — two chains, two questions, and confusing them is how "the firewall" fails to stop what everyone assumed it stopped.
  2. State first: accept established/related at the top, drop invalid right after. Everything below then runs only on new connections — correct and fast.
  3. Build toward the final drop, in Safe Mode, and test from a second session before you commit. The drop-all rule is a one-way door if anything above it is missing.
  4. connection-nat-state=dstnat admits exactly your port-forwards, present and future, without enumerating a single port in the filter.
  5. FastTrack bypasses queues and most of mangle. It's free throughput on boxes without QoS and a silent QoS-killer on boxes with it — scope it or skip it.
  6. Address lists with timeouts make the firewall self-updating — the staged brute-force trap bans hundreds of bots with four rules and no maintenance.
  7. Counters are the only truth. Attack your own network from the guest VLAN and watch the drop rules count — that's a tested firewall.

Is your MikroTik's firewall protecting or pretending?

NOCTIS audits and rebuilds RouterOS firewalls for hotels, villas, and SMBs across Crete — default-deny both chains, isolation that's actually tested, and brute-force traps on every exposed service. Most audits find at least one rule that never matched anything.

Book a Discovery Call →