Source NAT#
Source NAT rewrites the source address of traffic leaving the router, which is what lets a
network of private addresses reach the internet. The Source NAT table on the NAT page
lists every rule under nat source rule <n> with its live counters, and clicking a row
opens an editor for it. There is no + Add source NAT button here: new source rules come
from the installer, from the hairpin option on a port forward, from the Uplinks page, or
from the CLI. This page covers all four, and what the editor can do to what they wrote.
The table#
| Column | From |
|---|---|
| # | The rule number. |
| Description | description. |
| Out | outbound-interface name, or any. |
| Source | source address, or any. |
| Translation | translation address, or the word masquerade when the rule sets none. |
| Packets / Bytes | show nat source statistics, keyed by rule number. |
masquerade is the value most rules carry: it means "use whatever address the outbound
interface currently has", which is the only thing that works on a DHCP or PPPoE uplink. A
fixed value translates to that address instead.
What the installer writes#
When the installer's NAT box is left checked and there is both a WAN and a LAN with an address, it writes exactly one rule:
set nat source rule 100 description "LAN to WAN"
set nat source rule 100 outbound-interface name eth1
set nat source rule 100 source address 10.0.10.0/24
set nat source rule 100 translation address masqueradeThe source address is the LAN's network, derived from the LAN interface's address. A second
segment — a guest VLAN, a lab network — is not covered by that rule and will leave with
private addresses until it has one of its own
(packaging/wheelhouse-install).
Per-uplink rules from the Uplinks page#
The Uplinks page is where a second uplink gets its masquerade. Two places offer it:
- The add-uplink wizard has a checkbox, Masquerade behind it (nat source rule N), with the hint that without it traffic sent that way leaves with private addresses.
- An uplink that has no source NAT rule gets a panel offering to stage one.
Both stage the same three operations, at the next free source rule number:
set nat source rule 110 outbound-interface name eth2
set nat source rule 110 translation address masquerade
set nat source rule 110 description 'Wheelhouse: masquerade behind eth2'The number is computed from the existing rules: 100 when the highest existing rule is
below 100, and ten past the highest when it is 100 or more
(agent/wan.go sourceNATByInterface).
The Uplinks table's NAT column names the rule and its translation for each uplink, and
links here to edit it. The uplink model treats a rule as that uplink's NAT when it names the
uplink as its outbound interface, sets a translation and is not disabled; a masquerade
rule wins over a fixed one when an uplink has both.
The editor#
Clicking a source row opens the same panel the destination rules use, relabelled for the direction:
| Field | Command |
|---|---|
| Outbound interface | set nat source rule <n> outbound-interface name <iface> |
| Protocol | set nat source rule <n> protocol <tcp\|udp\|tcp_udp\|icmp> |
| Source address | set nat source rule <n> source address <addr-or-cidr> |
| Source port | set nat source rule <n> source port <port> |
| Translation address | set nat source rule <n> translation address <addr-or-masquerade> |
| Translation port | set nat source rule <n> translation port <port> |
| Log matches | set nat source rule <n> log |
| Disabled | set nat source rule <n> disable |
| Description | set nat source rule <n> description <text> |
Clearing a field stages the matching delete. Delete rule stages
delete nat source rule <n>.
Writing one by hand#
There is no add editor, so a source rule that the wizards do not cover is typed. From the console, a second segment behind the same uplink:
set nat source rule 120 description 'guest to WAN'
set nat source rule 120 outbound-interface name eth1
set nat source rule 120 source address 10.0.20.0/24
set nat source rule 120 translation address masqueradeOr through the API, staged and committed the way the UI would do it:
curl -sk -X POST https://<router>:8443/api/stage \
-H "Authorization: Bearer wh_…" -H 'Content-Type: application/json' \
-d '[{"op":"set","path":["nat","source","rule","120","outbound-interface","name","eth1"]},
{"op":"set","path":["nat","source","rule","120","source","address","10.0.20.0/24"]},
{"op":"set","path":["nat","source","rule","120","translation","address","masquerade"]}]'
curl -sk -X POST https://<router>:8443/api/commit \
-H "Authorization: Bearer wh_…" -H 'Content-Type: application/json' \
-d '{"confirm_minutes":2}'Either way the rule appears in this table on the next read, with counters.
See also#
- NAT — the page these tables live on.
- Port forwards — the hairpin option stages a source rule too.
- Worked rulesets — a segment that needs both a filter rule and a translation.
- Uplinks — the page that offers a per-uplink masquerade rule.
- Authenticating — the header the API example above uses.
Checked against#
ui/src/pages/Nat.tsx,
ui/src/pages/Wan.tsx,
agent/wan.go,
agent/main.go,
packaging/wheelhouse-install.