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
- Source IP
- 198.51.100.77
- Destination IP
- 203.0.113.20
- Destination port
- 443
- Source IP
- 198.51.100.77
- Destination IP
- 10.0.2.10 (rewritten)
- Destination port
- 443
Highlighted fields were rewritten by the router.
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
endThe 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
endThe alternative is split DNS: internal DNS answers 10.0.2.10 for www.example.com, so LAN users never use the public address.
Verify
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 ...
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
- 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
A policy for VIP-WEB1-HTTPS has srcintf port1, dstintf port1. Internet users can't reach WEB1. Why?
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?
WEB1's logs show every visitor as 10.0.2.1. What is configured?