Port forwards#
A port forward rewrites the destination of traffic arriving on the uplink so it reaches a host behind the router. On its own that achieves nothing: the rewritten packet still meets the forward chain, which on a default-drop router drops it. + Add forward therefore offers to stage three things — the translation, the firewall rule that permits it, and optionally the pair of rules that make the same service reachable from inside on its public address. Every one of them is shown as a command before it is staged.
The fields#
| Field | Default | What it does |
|---|---|---|
| Rule number | ten past the highest existing forward, or 100 when there are none | Validated as 1–999999. The hint shows the number that will be used if you leave it blank. |
| Description | — | Becomes the rule's description, and the accept rule's description prefixed with allow. |
| WAN interface | the active uplink, else the first uplink, else eth1 | inbound-interface name. |
| Protocol | tcp_udp | Also tcp or udp. |
| WAN port | — | destination port. A range works: 8000-8100. |
| Target port | — | translation port. Leave blank to keep the WAN port. |
| Target host (LAN) | — | translation address. Required — the button stays disabled without it. |
The defaults for the interface come from the uplink model (GET /api/wan). When that read
fails the field falls back to eth1 and stays typeable.
What it stages#
For HTTPS to 10.0.10.20 on uplink eth1, described as https to the web server, with the
accept rule left checked:
set nat destination rule 100 inbound-interface name eth1
set nat destination rule 100 protocol tcp
set nat destination rule 100 destination port 443
set nat destination rule 100 translation address 10.0.10.20
set nat destination rule 100 description 'https to the web server'
set firewall ipv4 forward filter rule 100 action accept
set firewall ipv4 forward filter rule 100 inbound-interface name eth1
set firewall ipv4 forward filter rule 100 destination address 10.0.10.20
set firewall ipv4 forward filter rule 100 description 'allow https to the web server'The accept rule#
The checkbox reads Also stage the matching forward filter accept rule. Without it the
translated packet still hits the default drop. It is checked by default, and it is only
staged when a target host has been given.
Four things about it:
- It matches the inside address, not the public one, because that is what the packet carries by the time the forward chain sees it.
- It does not name the port. The rule permits the uplink to reach that host, not that host's one service. Narrow it afterwards in the rule editor if you want the tighter version.
- It picks a number that is free. The accept rule takes the NAT rule's number when the forward chain does not already have one — the usual convention — and counts up in tens until it finds a free one when it does. A collision here would have silently rewritten an existing rule into the new forward's hole and deleted what it permitted, which is why the page reads the firewall configuration at all.
- It is IPv4. The path is
firewall ipv4 forward filter. A service published on IPv6 needs its accept rule written by hand, and needs no translation.
Unchecking the box stages the translation alone. Do that when the forward chain already has a rule that covers the host — and then check that it does, because a forward with no accept is the classic silent failure this checkbox exists to prevent.
Hairpin (NAT reflection)#
The second checkbox — Also reachable from the LAN on the public address — covers the case
where a client inside the network resolves the service's public name and gets the router's
own public address. It needs the uplink model, so it is disabled when GET /api/wan could
not be read, and the label says so.
Two extra fields appear:
- LAN interface, chosen from the uplink model's LAN interfaces.
- Public address, read-only, taken from the uplink's live addresses and falling back to
a configured address that is not the word
dhcp. When the uplink is DHCP the hint says what that means: the rule holds a literal address, and it goes stale when the lease changes.
If the chosen LAN interface has no address with a prefix, the page says so and stages no hairpin — the masquerade half needs the LAN's network, and there is nothing to derive it from.
The pair is a second destination rule at one past the forward's number, and a source rule ten past the highest existing source rule. Continuing the example, on a router whose installer wrote source rule 100:
set nat destination rule 101 inbound-interface name eth0
set nat destination rule 101 destination address 203.0.113.10
set nat destination rule 101 protocol tcp
set nat destination rule 101 destination port 443
set nat destination rule 101 translation address 10.0.10.20
set nat destination rule 101 description 'hairpin https to the web server'
set nat source rule 110 outbound-interface name eth0
set nat source rule 110 source address 10.0.10.0/24
set nat source rule 110 destination address 10.0.10.20
set nat source rule 110 protocol tcp
set nat source rule 110 destination port 443
set nat source rule 110 translation address masquerade
set nat source rule 110 description 'hairpin https to the web server'Why both halves are needed: the destination rule translates the inside client's request for the public address to the server, and the source rule masquerades the client so the server's reply comes back through the router rather than going directly to the client, where it would arrive from an address the client never talked to and be dropped.
The LAN network in the source rule is derived from the LAN interface's own address — the
page masks the address to its prefix, so 10.0.10.1/24 becomes 10.0.10.0/24.
After you stage#
Nothing above has reached the router. The Commit Bar holds the operations, marks them as
changes that can cut you off — every path begins nat or firewall — and offers
commit-confirm. Commit, then check:
- The new rule appears in the Port forwards table with its counters at zero.
- The counters move when the service is used. If they do not, the translation is not matching: check the interface, the protocol and the port.
- The counters move but the service does not answer: the translation is matching and something after it is not. The forward-chain accept is the first thing to check, and the target host's own firewall is the second.
Editing and removing one#
Clicking the row opens the editor described on NAT: every field above can be
changed there, and Delete rule stages delete nat destination rule 100.
Deleting a forward does not delete the accept rule that was staged with it, or the hairpin pair. They are separate rules with their own numbers; remove them from the same tables and from the firewall.
See also#
- NAT — the three tables, the counters, the editor.
- Source NAT — the outbound direction, and the masquerade rule the installer writes.
- Firewall — rules — where the accept rule lands.
- Worked rulesets — publishing a service as a complete example.
- Publish a service — the same job as a guide.
- Uplinks — where the WAN address and the LAN list in this editor come from.
Checked against#
ui/src/pages/Nat.tsx,
ui/src/lib/api.ts,
ui/src/lib/format.ts,
agent/wan.go,
agent/main.go.