skip to content

System: Accessing Public IP address from behind NAT

 Tweet Share0 Tweets

This article describes a simple solution we came up with to for what must be a common problem for anyone hosting a website on a local network or at a hosting centre with a 1:1 NAT (Network Address Translation) or similar firewall.

What is a Private Network?

As well as the public IP addresses that we use every day (yours is 207.244.77.134 and ours 204.8.124.6) the RFC1918 specification cleverly allows for a number of private networks of various sizes:

RFC1918 nameIP address rangenumber of addresses
24-bit block10.0.0.0 – 10.255.255.25516,777,216
20-bit block172.16.0.0 – 172.31.255.2551,048,576
16-bit block192.168.0.0 – 192.168.255.25565,536

Many home users will be familiar with the 16-bit block range as a means for accessing the router control panel or talking to other devices in the local network.

While everyone inside the local network can use these addresses they are not visible to the outside world. When someone else opens 192.168.0.1 they will see their router and not yours. The outside world can only see the public IP address that has been assigned to your Internet connection.

Description of the problem

From inside the private network each server or device is known only by it's private IP address and is always referenced using that address. Internal IP addresses are either assigned manually, or dynamically by the router using DHCP (Dynamic Host Configuration Protocol).

With a 1:1 NAT firewall setup, requests from outside the network are translated into requests for a local address. So in our case the public IP address 204.8.124.6 is converted to a local address 10.30.XXX.6, 204.8.124.7 is mapped to 10.30.XXX.7 and so on.

A consequence of this is that from a server inside the network it's no longer possible to access the public IP address. So any HTTP requests for locally hosted websites will fail because a DNS lookup will return the public address which is unreachable.

This makes it very difficult to run a search spider over hosted websites or to trigger scripts using programs such as Wget or cURL.

Possible solutions

If you are hosting only a small number of domains then you can set up a local DNS server (BIND) mapping those domains to local IP addresses. You could also achieve this by editing /etc/hosts.

For a large number of domains, however, this is not really an option as it means twice as much work every time the DNS is updated.

Using NAT tables to get around a NAT firewall

Sure enough there's a simpler solution using iptables. We know that a request from the server itself (telnet, web browser or web spider for example) can't reach the external IP address, but that the same request using the internal address will get through.

Using the right routing rules we can translate those requests and it should all just work. After some experimentation what we came up with was the following rules and added them to the firewall script which runs on startup:

#!/bin/sh IPTABLES="/sbin/iptables" $IPTABLES -t nat -A OUTPUT -d 204.8.124.6 -s 10.30.XXX.0/XX -j DNAT --to-destination 10.30.XXX.6 $IPTABLES -t nat -A OUTPUT -d 204.8.124.7 -s 10.30.XXX.0/XX -j DNAT --to-destination 10.30.XXX.7 ...

(to see what was going we used the LOG option in iptables to monitor requests from the server ip address in each of the NAT chains. In this case requests appeared only in the OUTPUT chain and not in PREROUTING or POSTROUTING as they would for a router)

The above rules intercept any requests from our server (subnet 10.30.XXX.0/XX) directed at our public IP addresses, which would normally drop out or fail, and translates them into requests for the appropriate local IP address.

So an HTTP/1.1 request for www.the-art-of-web.com (204.8.124.6) is translated into a request for www.the-art-of-web.com (10.30.XXX.6) meaning that the server can handle it itself. You will need a separate rule for each external/internal address pair.

Essentially what we're doing is replicating the actions taken by the NAT firewall for external requests, only we're doing it for internal requests.

These rules are to allow a server behind a NAT firewall to make requests to itself using the public IP addresses. For router configuration you need to use a combination of DNAT, SNAT and Masquerading and there are loads of examples online.

< System

Send a message to The Art of Web:


used only for us to reply, and to display your gravatar.

<- copy the digits from the image into this box

press <Esc> or click outside this box to close

User Comments

Post your comment or question

15 August, 2017

Anyone have a firewalld rule for this? God I hate centos7.

9 May, 2016

What about changing the hosts file for the internal server. i.e.
www.the-are-of-web.com 10.30.xxx.6

with this all request to the website locally resolves to internal IP instead of global IP ?

That's a valid solution, but it becomes less practical when you have 100+ domains pointing to the server, with regular changes.

15 March, 2016

Try to add this:

iptables -t nat -A PREROUTING -d <your pub IP>/32 -p tcp -m tcp --dport 2222 -j DNAT --to-destination localIP:port

8 March, 2016

How did you manage to add an OUTPUT rule (which is usually in the "filter" chain) to the "nat" chain?
I'm currently in need of doing the same thing, but i need to NAT different ports from the external IP to different internal IPs, I have already successfully added the PREROUTING rules to allow external connections, and I lack only the last bit.

top