Network Address Translation (NAT) in RouterOS rewrites IP addresses (and optionally ports) as packets traverse the router. All NAT rules live in /ip firewall nat and are evaluated on the first packet of each new connection only — subsequent packets follow the same translation automatically via connection tracking.
RouterOS has two NAT chains:
Chain
Purpose
srcnat
Rewrites the source address of outgoing packets (masquerade, src-nat, netmap outbound)
dstnat
Rewrites the destination address of incoming packets (port forwarding, dst-nat, netmap inbound)
dstnat rules are evaluated before routing; srcnat rules are evaluated after routing. Connection tracking must be enabled for NAT to work correctly.
Both actions translate the source address of outgoing packets, but they differ in how the replacement address is determined.
Use action=masquerade when your WAN IP is dynamic (DHCP, PPPoE, or any address that changes). Masquerade automatically reads the current IP of the outgoing interface at translation time and adapts when the IP changes. This makes it slightly slower at high connection rates due to the interface-IP lookup on each new connection.
comment="Masquerade all LAN traffic to dynamic WAN IP"
Use action=src-nat when your WAN IP is static. You specify the exact replacement address with to-addresses. This avoids the per-connection interface-IP lookup and performs better at scale.
dst-nat (destination NAT) redirects inbound connections from the router’s public IP/port to an internal host. This is the standard mechanism for port forwarding.
Mandatory matchers for a port-forward rule:
chain=dstnat
in-interface — the WAN interface (prevents forwarding of internal traffic)
protocol — tcp or udp (required when matching ports)
dst-port — the external port(s) to intercept
Forward external TCP/80 to an internal web server:
action=netmap provides static 1:1 address translation — every IP in a source range maps to a corresponding IP in the target range. It is used when you have a block of public IPs and want each to map directly to an internal host, in both directions.
Because RouterOS has no single “bidirectional” NAT action, you create two paired rules: one dstnat rule for inbound and one srcnat rule for outbound.
Single-host 1:1 NAT (one public IP ↔ one internal host):
/ipfirewallnat
# Inbound: public IP 203.0.113.20 -> internal 192.168.88.20
Both subnets must be the same size. RouterOS maps addresses positionally — the Nth address in the source range maps to the Nth address in the target range.
Important: After adding or changing netmap rules, clear existing connections so the new rules apply to active flows:
Hairpin NAT solves the problem of internal clients reaching an internal server using the server’s public IP. Without hairpin NAT, the dstnat rule rewrites the destination but the server receives a connection from an internal IP, sends the reply directly back on the LAN, and the client never gets the translated response — the session breaks.
How hairpin works: A second srcnat rule matches LAN-originated traffic destined for the internal server (after dstnat has rewritten the destination). It masquerades the source address to the router’s LAN IP, so the server sends all replies back through the router, which can then deliver them correctly to the client.
Full hairpin NAT example (web server at 192.168.88.10, public IP 203.0.113.5):
/ipfirewallnat
# Step 1: Port forward (applies to both internet clients AND LAN hairpin)
# Step 2: Hairpin srcnat - rewrite source so server replies via router
addchain=srcnat action=masquerade \
src-address=192.168.88.0/24 \
dst-address=192.168.88.10 \
protocol=tcp dst-port=80,443 \
comment="Hairpin NAT: LAN clients using public IP for internal server"
The hairpin srcnat rule should be placed before the general masquerade rule to ensure it matches first.
Why the dst-address in hairpin srcnat is the internal IP: By the time srcnat evaluates the packet, dstnat has already rewritten the destination from the public IP to the internal server IP. So the hairpin srcnat rule must match on the post-dstnat destination (192.168.88.10), not the original public IP.
Alternative using src-nat with explicit gateway IP (avoids masquerade overhead):
/ipfirewallnat
addchain=srcnat action=src-nat \
src-address=192.168.88.0/24 \
dst-address=192.168.88.10 \
protocol=tcp dst-port=80,443 \
to-addresses=192.168.88.1 \
comment="Hairpin NAT: explicit LAN gateway as source"
Here to-addresses is the router’s LAN interface IP (e.g. 192.168.88.1).
Port forward not working — traffic not reaching internal host
Confirm the dstnat rule has in-interface set to the correct WAN interface (not the LAN interface).
Check that connection-state is not inadvertently blocking traffic in the firewall filter forward chain before NAT takes effect. dstnat runs before routing, but filter forward runs after.
Verify the internal host has the router as its default gateway — otherwise reply packets bypass the router.
Check rule hit counters with /ip firewall nat print stats. Zero hits means the rule is not matching.
masquerade/src-nat not translating outbound traffic
Confirm out-interface matches the actual WAN interface name exactly.
Verify connection tracking is enabled: /ip firewall connection tracking print.
Check that the srcnat rule position is correct — rules above it may be matching first.
Hairpin NAT not working — internal clients cannot reach server via public IP
Confirm the hairpin srcnat rule is present and placed before the general masquerade rule.
The dst-address in the hairpin srcnat must match the internal server IP (post-dstnat rewrite), not the public IP.
Verify hit counters on both the dstnat and hairpin srcnat rules increment during a test from a LAN client.
NAT not applying after rule change
NAT decisions are cached per connection on the first packet. Existing connections are not affected by new rules. Clear connections to force re-evaluation:
/ipfirewallconnectionremove [find]
Checking NAT order of operations
RouterOS processes packets in this order for a forwarded packet:
RAW prerouting
dstnat (NAT chain, prerouting)
Routing decision
Filter forward chain
srcnat (NAT chain, postrouting)
RAW postrouting
This means dstnat rewrites happen before filter forward rules see the packet — the filter chain sees the already-translated destination address.