TTR Networks

Beginner · Setting up VyOS with NAT · section 4 of 7

Port forwarding

✓ Lab-tested 17 October 2026 on VyOS 2026.10.16-0024-rolling

Before adding anything, check what the internet (our server at 192.0.2.10) can reach right now:

  • The public LAN is wide open. The web server answers, and so does a database listener on port 5432 that should never be reachable from outside. Nothing is filtering: R1 is just routing.
  • The NAT-LAN can't be reached at all. There's no route to 10.0.0.0/24 on the internet, and R1 has no reason to send anything there.
  • Port 8080 on R1's WAN address is refused: nothing is listening, and nothing is forwarded yet.

To publish one service from the NAT-LAN, use destination NAT, also called port forwarding. Traffic arriving on eth0 for TCP port 8080 has its destination rewritten to 10.0.0.10 port 80, the web server on the NAT-LAN host.

Note what the web server sees: the real client address (192.0.2.10). Destination NAT only changes the destination, so the server's logs and access controls still work.

Using the forward from inside

Try the same URL from the public LAN, and it fails. The rule only matches traffic arriving on eth0, and this request came in on eth2. Getting it to work from inside is called hairpin NAT (or NAT reflection), and it needs extra rules, including source NAT so that replies come back through R1. Most networks avoid the problem with split DNS instead: inside, the name resolves to the private address directly.

From the internet, before port forwarding (real output)
root@server:~# curl -sS -m 5 http://198.51.100.2/
hello from pubhost
root@server:~# nc -zv -w 3 198.51.100.2 5432
Connection to 198.51.100.2 5432 port [tcp/postgresql] succeeded!
root@server:~# curl -sS -m 5 http://10.0.0.10/
curl: (7) Failed to connect to 10.0.0.10 port 80 after 0 ms: Couldn't connect to server
root@server:~# curl -sS -m 5 http://203.0.113.2:8080/
curl: (7) Failed to connect to 203.0.113.2 port 8080 after 0 ms: Couldn't connect to server
  • Lines 1–2: The public LAN's web server: expected.
  • Lines 3–4: Its database, too: not expected, and nothing stops it.
  • Lines 5–6: The NAT-LAN: no route from the internet.
  • Lines 7–8: Nothing forwarded yet, so R1 refuses it.
Stage 3: forward WAN port 8080 to the inside web server
set nat destination rule 100 description 'WAN port 8080 to the web server on lanhost'
set nat destination rule 100 inbound-interface name 'eth0'
set nat destination rule 100 protocol 'tcp'
set nat destination rule 100 destination port '8080'
set nat destination rule 100 translation address '10.0.0.10'
set nat destination rule 100 translation port '80'
  • Line 2: Only traffic arriving from the internet.
  • Lines 3–4: TCP port 8080 on the WAN address…
  • Lines 5–6: …becomes 10.0.0.10 port 80.
The forward in action (real output)
root@server:~# curl -sS -m 5 http://203.0.113.2:8080/
hello from lanhost
root@lanhost:~# cat /tmp/http.log
192.0.2.10 - - [17/Oct/2026 00:54:16] "GET / HTTP/1.1" 200 -
  • Lines 1–2: From the internet, R1's WAN address on port 8080 reaches the private web server.
  • Line 4: The web server sees the real client, 192.0.2.10.
NAT rules and translations (real output)
vyos@R1:~$ show nat destination rules
Rule    Source     Destination    Proto    In-Int    Translation
------  ---------  -------------  -------  --------  -------------
100     0.0.0.0/0  0.0.0.0/0      TCP      eth0      10.0.0.10
        sport any  dport 8080                        port 80
vyos@R1:~$ show nat destination translations
Pre-NAT           Post-NAT      Proto    Timeout    Mark    Zone
----------------  ------------  -------  ---------  ------  ------
203.0.113.2:8080  10.0.0.10:80  tcp      117        0
  • Line 9: 203.0.113.2:8080 rewritten to 10.0.0.10:80.
The same URL from inside (real output)
root@pubhost:~# curl -sS -m 5 http://203.0.113.2:8080/
curl: (7) Failed to connect to 203.0.113.2 port 8080 after 2 ms: Couldn't connect to server
  • Lines 1–2: Arrives on eth2, not eth0, so the rule doesn't match: no hairpin NAT.

Check your understanding

A port forward works from home but not from a laptop in the office. What's the most likely reason?

  • The forward is configured on the wrong port
  • The rule only matches traffic arriving on the WAN interface; office traffic arrives on a LAN interface
  • The office laptop needs NAT turned off
  • Destination NAT doesn't support TCP