Iptables – Cannot access LAN virtual IP from WAN using iptables NAT

heartbeatiptablesnat;virtual-ip

Here's the setup:

  • 2 servers running CentOS 5.6 (hostnames = "master1" and "master2")
  • "master1" LAN IP is 10.224.45.130 and WAN IP is 184.107.x.1
  • "master2" LAN IP is 10.224.45.131 and WAN IP is 184.107.x.2
  • Apache + Heartbeat installed on both, with "master1" as primary for httpd service in haresources.
  • Apache binds to virtual IP 10.224.45.135 (started through heartbeat)
  • iptables NAT PREROUTING from port 80 -> 10.224.45.135:80 on both servers.

(Note: I am logged into a VPN so I have access to the LAN)

I have heartbeat working fine. It will correctly create the virtual IP address on "master1" and start apache. When I stop heartbeat on "master1" to simulate a server failure heartbeat properly notifies "master2", which takes over the virtual IP and starts apache. This is all working fine.

I can point to the LAN IP for either server and it will load the site no matter which server is currently running apache (since both have an iptables NAT PREROUTING port 80 to the virtual IP address). I can also load the site when I point my browser to the virtual IP address itself.

However, if I call the public WAN IP for either server, the site will only load when I call the IP for the server that is currently running apache. For instance, if master1 is currently running apache, I can load the site by calling any three of the LAN IP addresses or the WAN IP for master1. But the site will not load if I call the WAN IP for master2. However, if I stop heartbeat on master1 so that apache starts on master2, I can then load the site by calling the WAN IP for master2 but not master1.

I'm not sure why iptables would properly route packets to the virtual IP when I access the site through the LAN IP and the WAN IP for the server running apache but not the WAN IP for the other server, even though they both point port 80 to the virtual IP. I also noticed that I can only ping the virtual IP (10.224.45.135) from the server currently running apache (and therefore the server that currently has the VIP configured on it). It was my assumption that I would be able to ping the VIP from either server. I'm not sure if this has anything to do with the reason that the WAN IP does not get routed to the VIP properly though.

Here is my iptables setup:

*filter
:FORWARD DROP [0:0]
:INPUT DROP [0:0]
:OUTPUT ACCEPT [0:0]
-A INPUT -i lo -j ACCEPT
-A INPUT -i tun0 -j ACCEPT
-A INPUT -i tap0 -j ACCEPT
-A INPUT -i br0 -j ACCEPT
-A INPUT -p icmp -m icmp --icmp-type 8 -j ACCEPT
-A INPUT -m state --state RELATED,ESTABLISHED -j ACCEPT
-A INPUT -p tcp -m tcp --dport 20 -j ACCEPT
-A INPUT -p tcp -m tcp --dport 21 -j ACCEPT
-A INPUT -p tcp -m tcp --dport 22 -j ACCEPT
-A INPUT -p tcp -m tcp --dport 25 -j ACCEPT
-A INPUT -p tcp -m tcp --dport 53 -j ACCEPT
-A INPUT -p udp -m udp --dport 53 -j ACCEPT
-A INPUT -p tcp -m tcp --dport 80 -j ACCEPT
-A INPUT -p tcp -m tcp --dport 106 -j ACCEPT
-A INPUT -p tcp -m tcp --dport 110 -j ACCEPT
-A INPUT -p tcp -m tcp --dport 143 -j ACCEPT
-A INPUT -p tcp -m tcp --dport 389 -j ACCEPT
-A INPUT -p tcp -m tcp --dport 443 -j ACCEPT
-A INPUT -p tcp -m tcp --dport 465 -j ACCEPT
-A INPUT -p tcp -m tcp --dport 587 -j ACCEPT
-A INPUT -p tcp -m tcp --dport 636 -j ACCEPT
-A INPUT -p udp -m udp --dport 694 -j ACCEPT
-A INPUT -p tcp -m tcp --dport 843 -j ACCEPT
-A INPUT -p tcp -m tcp --dport 873 -j ACCEPT
-A INPUT -p tcp -m tcp --dport 953 -j ACCEPT
-A INPUT -p tcp -m tcp --dport 993 -j ACCEPT
-A INPUT -p udp -m udp --dport 993 -j ACCEPT
-A INPUT -p tcp -m tcp --dport 995 -j ACCEPT
-A INPUT -p tcp -m tcp --dport 1194 -j ACCEPT
-A INPUT -p udp -m udp --dport 1194 -j ACCEPT
-A INPUT -p tcp -m tcp --dport 3000 -j ACCEPT
-A INPUT -p tcp -m tcp --dport 3306 -j ACCEPT
-A INPUT -p tcp -m tcp --dport 5901 -j ACCEPT
-A INPUT -p tcp -m tcp --dport 7025 -j ACCEPT
-A INPUT -p tcp -m tcp --dport 10000 -j ACCEPT
-A INPUT -p tcp -m tcp --dport 11211 -j ACCEPT
-A INPUT -p tcp -m tcp --dport 11511 -j ACCEPT
-A FORWARD -i br0 -j ACCEPT
-A FORWARD -o br0 -j ACCEPT
-A FORWARD -p tcp -m tcp --dport 80 -j ACCEPT
COMMIT
*mangle
:PREROUTING ACCEPT [30383:12077327]
:INPUT ACCEPT [30381:12077231]
:FORWARD ACCEPT [0:0]
:OUTPUT ACCEPT [26362:10490359]
:POSTROUTING ACCEPT [26362:10490359]
COMMIT
*nat
:PREROUTING ACCEPT [0:0]
:OUTPUT ACCEPT [0:0]
:POSTROUTING ACCEPT [0:0]
-A PREROUTING -p tcp -m tcp --dport 80 -j DNAT --to 10.224.45.135:80
-A PREROUTING -p tcp --dport 443 -j DNAT  --to 10.224.45.135:443
-A POSTROUTING -s 10.8.0.0/255.255.255.0 -o venet0 -j MASQUERADE
COMMIT

Best Answer

I found the answer!

I needed to add a POSTROUTING rule to the NAT table set to Masquerade for packets with a DPT of 80 or 443.

Found the answer here: http://www.debian-administration.org/articles/73#comment_22

In addition to the rules in the article, you need a POSTROUTING rule to enable masquerading if the redirection goes to another machine. For example:

iptables -t nat -A POSTROUTING -j MASQUERADE -o eth0

Otherwise, the response doesn't get back to the original machine and the connection appears to be filtered. At least this is what I found when trying to do forwarding. I appreciate that this is a few years too late to help but it might help someone else.

Related Topic