Skip to main content
RunBook Academy

OPNsenseXIII · Port Forwarding and NAT ReflectionPort forwarding

Port forwarding and the associated firewall rule — automatic vs manual

Intermediate⏱ ~13 minpfctl

What you'll learn

  • Use the auto-generated associated rule by default
  • Disable the associated rule and write manual rules when required
  • Recognise the security implications of disabling the auto rule
  • Read the generated rdr and pass rules in pfctl -s rules

Prerequisites

Verified against OPNsense 25.x · FreeBSD 14.x · PF (FreeBSD packet filter) FreeBSD 14.x · Unbound 1.20+ · Kea DHCP OPNsense 25.x plugin · WireGuard in-kernel + OPNsense plugin · strongSwan (IPsec plugin) OPNsense 25.x plugin · OpenVPN 2.6.x · Suricata 7.x · 2026-08-14

Not yet marked complete on this device.

A port forward in OPNsense has two parts: the rdr rule that rewrites the destination, and the firewall rule that permits the rewritten packet to pass. The two are usually created together — OPNsense generates both from a single GUI entry, with the firewall rule marked as “associated” with the port forward.

The associated rule is convenient, but it is also rigid. There are cases where the operator needs a custom rule — for source restrictions, rate limits, or logging — that the auto rule does not provide. In those cases, the operator disables the associated rule and writes a manual one.

This lesson covers when to use the auto rule, when to disable it, and how to write a manual rule that does what the operator wants without breaking the port forward.

The auto-generated associated rule

When you check “Add associated filter rule” in the port forward form, OPNsense creates a firewall rule on the WAN interface that matches the post-DNAT destination and port. The rule is added above the WAN’s default deny and below any explicit WAN rules.

The rule looks like:

pass in quick on igb1 inet proto tcp from any to 192.0.2.10 port = 443

The rule has a Description field that references the port forward it is associated with. The operator can edit the rule’s source, destination, schedule, logging, and other fields, but the rule remains associated with the port forward. Deleting the port forward removes the rule.

The auto-generated rule is the right choice for most port forwards. It is the path of least resistance: the operator configures the port forward, OPNsense creates both rules, the service is exposed. The default deny on the WAN still blocks everything else.

Read-only / Safeassociated rule
$ pfctl -s rules | grep -A 1 '@101' | head -5
@101 pass in quick on igb1 inet proto tcp from any to 192.0.2.10 port = 443
[ Permit HTTPS to internal server (192.0.2.10). Owner: NetOps. Associated with port forward rdr-443. ]

Illustrative output

When the auto rule is enough

The auto rule is enough for the simple case: a service exposed to the entire Internet, no source restrictions, no rate limits, no special logging. The rule permits the flow; the firewall’s default state tracking handles the rest.

The auto rule is also enough when the operator wants the service exposed but does not want to expose anything else on the same internal host. The auto rule is restricted to the specific port and protocol; other ports on the internal host remain unreachable from the WAN.

When to disable the auto rule

The auto rule has four limitations that lead operators to disable it:

  1. No source restrictions. The auto rule allows traffic from any. If the operator wants to restrict the source (e.g. allow only specific countries, allow only partner networks), the auto rule does not express this.
  2. No rate limiting. The auto rule has no per-source or per-destination rate limits. Operators who need to protect the internal service from abuse must write a manual rule with rate-limit options.
  3. No advanced logging. The auto rule logs only the rule match (in the firewall log); it does not log payload or application-level events. Operators who need deep logging for compliance must add manual rules with logging options.
  4. No NAT reflection configuration. The auto rule does not enable or disable NAT reflection (hairpin) — that is a separate setting under Firewall → Settings → Advanced. If the operator wants different reflection behaviour per port forward, manual rules are required.

When any of these are required, the operator disables the associated rule and writes a manual one. The trade-off: more flexibility, more responsibility. The manual rule must correctly permit the post-DNAT flow or the port forward is broken.

Writing a manual rule that matches the port forward

A manual rule that replaces the auto rule:

Interface:       WAN
Direction:       in
Protocol:        TCP
Source:          any (or restricted)
Destination:     192.0.2.10 (the internal IP, post-DNAT)
Destination port: 443
Action:          pass

The destination is the post-DNAT internal IP. The destination port is the post-DNAT internal port (same as the external port in most cases, but they can differ — the port forward can map external 8443 to internal 443).

If the operator wants source restrictions, the Source field is an alias. For example, Source = partner_networks (an alias of the partner’s source IPs).

If the operator wants rate limits, the rule’s Advanced options include a per-rule state limit. For example, max-src-states 100 limits each source IP to 100 simultaneous connections.

If the operator wants logging, the rule’s Log checkbox enables firewall log entries for every match.

Read-only / Safemanual rule with source restriction
$ pfctl -s rules | grep -A 1 '@105' | head -5
@105 pass in quick on igb1 inet proto tcp from 203.0.113.0/24 to 192.0.2.10 port = 443
[ Permit partner-network HTTPS to internal API server. Source: partner alias. Owner: NetOps. ]

Illustrative output

The relationship between the rdr rule and the pass rule

The rdr rule and the pass rule are evaluated at different stages of the packet flow. The rdr rule rewrites the destination. The pass rule permits the (post-DNAT) flow.

PF evaluates rdr rules on the incoming path before filter rules. The filter rule then matches against the post-DNAT packet. If the filter rule permits, PF creates state. If the filter rule blocks (or no rule permits), PF drops the packet.

The two rules are linked by the destination. The rdr rule’s target becomes the filter rule’s destination. If they disagree (e.g. the rdr rule points to 192.0.2.10 and the filter rule permits 192.0.2.20), the filter rule never matches.

The discipline: when changing a port forward’s destination, also update any manual firewall rules that reference the old destination. OPNsense does not auto-update manual rules.

A production pattern

A typical production pattern for a port-forwarded service:

  1. Create the port forward with the associated rule enabled.
  2. Test the port forward from an external host. Verify the service is reachable.
  3. If the service needs source restrictions, rate limits, or advanced logging, edit the associated rule to add these. The auto rule is editable; the operator does not need to disable it.
  4. If the auto rule cannot express the requirement (e.g. the operator wants a per-port-forward logging level that the auto rule does not support), disable the auto rule and write a manual one.
  5. Verify with pfctl -s rules and pfctl -s nat that both rules are present and correctly configured.

The key insight: the auto rule is editable. Many operators disable it and rewrite from scratch when an edit would have sufficed. The cleaner path is to edit the auto rule, save, and verify.

Summary

  • The auto-generated associated rule is created by default and permits the post-DNAT flow. It is editable.
  • Disable the auto rule when you need source restrictions, rate limits, advanced logging, or per-port-forward NAT reflection configuration that the auto rule cannot express.
  • A manual rule replaces the auto rule. The destination must be the post-DNAT internal IP and port.
  • Editing the port forward does not update manual rules that reference the old destination.
  • The rdr rule and the pass rule are linked by the destination. They must agree or the flow does not work.

Knowledge check · 4 questions

  1. Q1. You need to expose a web service to the Internet, but only from a specific partner network (203.0.113.0/24). The auto-generated associated rule allows traffic from `any`. What is the cleanest fix?

  2. Q2. A port forward with the associated rule enabled generates a firewall rule whose destination is the WAN IP, not the internal IP.

  3. Q3. Which of the following are valid reasons to disable the auto-generated associated rule and write a manual one? Select all that apply.

  4. Q4. You disable the associated rule for a port forward and forget to write a manual rule. The port forward appears in the GUI and `pfctl -s nat` shows the rdr rule. What happens to inbound traffic?

Passing score: 75%. Answers are checked in this browser.