Take the 2-minute tour ×

This is a Canonical Question about Hairpin NAT (Loopback NAT).

The generic form of this question is:

We have a network with clients, a server, and a NAT Router. There is port forwarding on the router to the server so some of it's services are available externally. We have DNS pointing to the external IP. Local network clients fail to connect, but external work.

  • Why does this fail?
  • How can I create a unified naming scheme (DNS names which work both locally and externally)?

This question has answeres merged from multiple other questions. They originally referenced FreeBSD, D-Link, Microtik, and other equipment. They're all trying to solve the same problem however.

share|improve this question


If your purpose is to test the access from the internet, there is no point in messing with the router's routes and/or DNS settings anyway for at best, from the inside you would be verifying that the inside portion of the router works. I suggest you use a proxy server somewhere on the outside. –  mjv Oct 10 '09 at 6:42

7 Answers 7

up vote 3 down vote accepted

What you're looking for is called "hairpin NAT". Requests from the internal interface for an IP address assigned to the external interface should be NAT'ted as though they came in from the external-side interface.

I don't have any FreeBSD familiarity at all, but reading the "pf" manual for OpenBSD (http://www.openbsd.org/faq/pf/rdr.html) the proposed solutions of split-horizon DNS, using a DMZ network, or TCP proxying lead me to believe that "pf" doesn't support hairpin NAT.

I'd look at going the route of split-horizon DNS and not using IP addresses in URLs internally but, instead, using names.

share|improve this answer

Since this has been elevated to be the canonical question on hairpin NAT, I thought it should probably have an answer that was more generally-valid than the currently-accepted one, which (though excellent) relates specifically to FreeBSD.

This question applies to services provided by servers on RFC1918-addressed IPv4 networks, which are made available to external users by introducing destination NAT (DNAT) at the gateway. Internal users then try to access those services via the external address. Their packet goes out from the client to the gateway device, which rewrites the destination address and immediately injects it back into the internal network. It is this sharp about-turn the packet makes at the gateway that gives rise to the name hairpin NAT, by analogy with the hairpin turn.

The problem arises when the gateway device rewrites the destination address, but not the source address. The server then receives a packet with an internal destination address (its own), and an internal source address (the client's); it knows it can reply directly to such an address, so it does so. Since that reply is direct, it doesn't go via the gateway, which therefore never gets a chance to balance the effect of inbound destination NAT on the initial packet by rewriting the source address of the return packet.

The client thus sends a packet to an external IP address, but gets a reply from an internal IP address. It has no idea that the two packets are part of the same conversation, so no conversation happens.

The solution is that for packets which require such destination NAT, and which reach the gateway from the internal network, to also perform source NAT (SNAT) on the inbound packet, usually by rewriting the source address to be that of the gateway. The server then thinks the client is the gateway itself, and replies directly to it. That in turn gives the gateway a chance to balance the effects of both DNAT and SNAT on the inbound packet by rewriting both source and destination addresses on the return packet.

The client thinks it's talking to an external server. The server thinks it's talking to the gateway device. All parties are happy. A diagram may be helpful at this point:

enter image description here

Some consumer gateway devices are bright enough to recognise those packets for which the second NAT step is needed, and those will probably work out-of-the-box in a hairpin NAT scenario. Others aren't, and so won't, and it is unlikely that they can be made to work. A discussion of which consumer-grade devices are which is off-topic for Server Fault.

Proper networking devices can generally be told to work, but - because they are not in the business of second-guessing their admins - they do have to be told do so. Linux uses iptables to do the DNAT thus:


which will enable simple DNAT for the HTTP port, to an internal server on But to enable hairpin NAT, one would also need a rule such as:

iptables -t nat -A POSTROUTING -d -p tcp --dport 80 -j MASQUERADE

Note that such rules need to be in the right place in the relevant chains in order to work properly, and depending on settings in the filter chain, additional rules may be needed to permit the NATted traffic to flow. All such discussions are outside the scope of this answer.

But as others have said, properly-enabling hairpin NAT isn't the best way to handle the problem. The best is split-horizon DNS, where your organisation serves different answers for the original lookup depending on where the requesting client is, either by having different physical servers for internal vs. external users, or by configuring the DNS server to respond differently according to the address of the requesting client.

share|improve this answer
I am wondering a bit about the addresses on packets exchanged between gateway and server. Would it not be more consistent if the server saw the public IP address of the router as the client IP? Technically both can work, but to remain consistent with how other servers see the clients, it would have to use the public IP. –  kasperd Jun 1 at 14:40
I'm assuing you're referring to the last case, "proper hairpin NAT". The crucial thing is to rewrite the source address on the inbound packet in such a way that it goes back to the router, which can then reverse both the DNAT and the SNAT and thus avoid the problem. Which of its many address the router uses to do this is more a point of taste, and if you're doing this with iptables, is certainly something you can configure if you so choose. –  MadHatter Jul 11 at 7:44

The problem here is, that your router does not NAT your internal client's address. Thus, the TCP handshake fails.

Let's assume following IPs

  • Client:
  • Server:
  • Router internal: 192.168.1
  • Router external:

Here is what is happening:

  1. Client ( sends TCP-SYN to your external IP, Port 80 (
  2. Router sees port forwarding rule and forwards the packet to the server ( without changing the source IP (
  3. Client waits for a SYN-ACK from the external IP
  4. Server send his answer back to the client directly, because it's on the same subnet. It does not send the packet to the router, which would reverse the NAT.
  5. Client recieves a SYN-ACK from instead of And discards it.
  6. Client still waits for a SYN-ACK from and times out.
share|improve this answer

Why not use split horizon dns instead of hardcoding IP addresses everywhere? You would have ext.yourdomain pointing to 217.x.x.x on the outside, and then 192.x.x.x on the inside.

share|improve this answer
If you have a moment, could you expand on what Split-Horizon DNS is, how it works, and the major drawbacks. This is a canonical question now and it'd be nice to have a more complete answer. –  Chris S Dec 12 '13 at 14:45

Ill answer to my questions just to broaden horizons for those with similar problems.

I am contacted my ISP and asked them to try solving my problems. What they had offered me is another public IP address just for server, Now I have local traffic on the WAN side of FreeBSD and We made specific pipes for faster throughput fol local traffic to public IP of Server

share|improve this answer
This solution implements a Perimeter network or DMZ and is a good alternative to both Hairpin NAT and Split-Horizon DNS. –  Chris S Dec 12 '13 at 14:47

If it's an original D-Link router (i.e., not Rev. D / Firmware Version 1.00VG from Virgin Media), you should be able to adjust the settings to work around this. (However, I agree with the previous poster's suggestion of DD-WRT for many other reasons!)

  1. Log into the router's web interface
  2. Click the Advanced tab at the top
  3. Click the Firewall Settings tab at the left
  4. Click the Endpoint Independent radio button under TCP Endpoint Filtering, as shown in the screenshot below (or see the router emulator at D-Link's website)
  5. Save changes; you're done

D-Link router web UI screenshot

This screenshot is from the Rev. C model; yours may be slightly different.

share|improve this answer

In FreeBSD using PF it's easy as (in your pf.conf file):

extif = "tun0"
intif = "em0"
{other rules}...
nat on $intif from any to port 80 -> ($extif) would be the internal web server.

share|improve this answer

Your Answer


