Course menu

Module 3: NATLesson 3.2 (2 of 4 in this module)12 of 18 in the FortiGate Administrator course

Virtual IPs: publishing servers

Destination NAT with VIPs: static and port-forwarding VIPs, the policy that goes with them, hairpin access from the LAN, and common traps.

Intermediate · 12 min read

What you will learn

After this lesson, you can publish a DMZ server with a port-forwarding VIP, write the policy that allows it, reach it from the LAN by its public address, and diagnose a VIP that doesn't work.

  • Static VIPs
  • Port forwarding
  • VIP policies
  • Hairpin NAT

A virtual IP (VIP) is a FortiGate destination NAT object. It maps an external address (and optionally a port) to an internal server's address (and port). Traffic arriving for the external address is rewritten to the internal one before routing and policy lookup, and a firewall policy whose destination is the VIP must allow it.

In simple terms: A VIP is a public front door for an inside server. Visitors knock on the public address; the FortiGate quietly sends them to the server inside.

A real-life situation

WEB1 (10.0.2.10) in the DMZ must be reachable from the Internet on HTTPS. Customers use www.example.com, which resolves to 203.0.113.20, one of the addresses the ISP routes to FGT1. Staff in the office use the same name, so they must be able to reach it by the public address too.

What the VIP changes

Arriving on port1
Internet
Source IP
198.51.100.77
Destination IP
203.0.113.20
Destination port
443
Leaving port3
DMZ
Source IP
198.51.100.77
Destination IP
10.0.2.10 (rewritten)
Destination port
443

Highlighted fields were rewritten by the router.

Destination NAT happens first, so the routing lookup sends the packet to port3 and the policy check sees port1 → port3. The client's address is unchanged.

Configure the VIP and its policy

config firewall vip edit VIP-WEB1-HTTPS set extintf "any" set extip 203.0.113.20 set mappedip "10.0.2.10" set portforward enable set extport 443 set mappedport 443 next end config firewall policy edit 6 set name "Internet-to-WEB1" set srcintf "port1" set dstintf "port3" set srcaddr "all" set dstaddr "VIP-WEB1-HTTPS" set action accept set schedule "always" set service "HTTPS" set logtraffic all next end

The policy's destination is the VIP object, and its outgoing interface is the one facing the real server (port3). NAT stays off, so WEB1 logs the real client address. extintf any lets the VIP work from any interface, which the hairpin case below needs.

Without portforward, the VIP is static: every port on 203.0.113.20 maps to 10.0.2.10, and the policy's service field decides which ports are actually allowed. Port forwarding exposes only what you list, and can translate ports too, for example external 8443 to internal 443.

Hairpin: reaching the server from the LAN

PC1 resolves www.example.com to 203.0.113.20 and sends the request to FGT1. Because the VIP's external interface is any, the destination is translated to 10.0.2.10 on arrival at port2, and the policy lookup sees port2 → port3. So a LAN policy with the VIP as destination is needed:

config firewall policy edit 7 set name "LAN-to-WEB1-public" set srcintf "port2" set dstintf "port3" set srcaddr "LAN-subnet" set dstaddr "VIP-WEB1-HTTPS" set action accept set schedule "always" set service "HTTPS" next end

The alternative is split DNS: internal DNS answers 10.0.2.10 for www.example.com, so LAN users never use the public address.

Verify

Example output · based on Fortinet documentation; exact format varies by model and FortiOS version
FGT1 # diagnose sys session list
session info: proto=6 proto_state=01 ...
hook=pre dir=org act=dnat 198.51.100.77:60311->203.0.113.20:443(10.0.2.10:443)
hook=post dir=reply act=snat 10.0.2.10:443->198.51.100.77:60311(203.0.113.20:443)
misc=0 policy_id=6 ...
act=dnat with the mapped address in brackets, and the reply translated back to the external address. Policy 6 allowed it. (Example output, trimmed; filter with diagnose sys session filter dst 203.0.113.20 first.)

Why it works this way

The FortiGate translates the destination before it routes, so the routing table and the policy both work with the server's real address and the interface it lives behind. Using the VIP object as the policy's destination ties the two together: the policy only allows traffic that was translated by that VIP.

Common mistakes

  • Setting the policy's outgoing interface to port1 (the WAN) instead of the server's interface.
  • Using the server's address object instead of the VIP as the destination.
  • Forwarding a port the FortiGate uses itself on that address (HTTPS or SSH admin access).
  • Forgetting the hairpin policy, so the site works from outside but not from the office.
  • WEB1 using a default gateway other than FGT1, so replies bypass the FortiGate and the session breaks.

Key takeaways

✅ Key takeaways
  • A VIP maps an external address (and port) to an internal server; it is destination NAT.
  • The policy uses the VIP as destination and the server's interface as outgoing interface.
  • Static VIPs map all ports; port forwarding maps only the ports listed.
  • Hairpin access needs the VIP to apply on the LAN side and a LAN policy to the VIP, or split DNS.

Check yourself

Predict · scenario 1

A policy for VIP-WEB1-HTTPS has srcintf port1, dstintf port1. Internet users can't reach WEB1. Why?

Predict · scenario 2

A static VIP maps 203.0.113.20 to WEB1 and the policy allows only HTTPS. Can someone on the Internet reach WEB1 on SSH?

Predict · scenario 3

WEB1's logs show every visitor as 10.0.2.1. What is configured?

FAQ

Should NAT be enabled on the policy to a VIP?
Usually not. The VIP already handles destination NAT. Leaving source NAT off means the server sees each client's real address in its logs. Enable it only if the server can't route replies back through the FortiGate.
Can a VIP use the FortiGate's own WAN address?
Yes, with port forwarding. Just don't forward a port the FortiGate itself uses on that interface, such as HTTPS when administrative HTTPS access is enabled there, or the two will conflict.