112

I would like do some NAT in iptables. So that, all the packets coming to 192.168.12.87 and port 80 will be forwarded to 192.168.12.77 port 80.

How to do this with iptables?

Or

Any other ways to achieve the same?

6
  • @Matthewlfe, For some reason, I need to forward all the apache request from (192.168.12.87) to (192.168.12.77).
    – sat
    Apr 3, 2014 at 18:08
  • 1
    @Matthewlfe, I have two production servers. One is connected with public static ip address. Due to some connectivity issues, I am not able to connect to DB and other systems from 192.168.12.87. So, I need to forward all the request to 192.168.12.77.
    – sat
    Apr 3, 2014 at 18:24
  • @lain, I am not familiar with iptables. And, I seen some examples. But, It seems to be require two ethernet. Link: revsys.com/writings/quicktips/nat.html
    – sat
    Apr 3, 2014 at 18:27
  • You could also use proxy mode in your web server config to send requests to 192.168.12.77 from 192.168.12.87 (if your webserver supports it)
    – krisFR
    Apr 3, 2014 at 18:44
  • askapache.com/htaccess/…
    – dmourati
    Apr 3, 2014 at 22:00

2 Answers 2

106

These rules should work, assuming that iptables is running on server 192.168.12.87 :

#!/bin/sh

echo 1 > /proc/sys/net/ipv4/ip_forward

iptables -F
iptables -t nat -F
iptables -X

iptables -t nat -A PREROUTING -p tcp --dport 80 -j DNAT --to-destination 192.168.12.77:80
iptables -t nat -A POSTROUTING -p tcp -d 192.168.12.77 --dport 80 -j SNAT --to-source 192.168.12.87

You have to DNAT incoming traffic on port 80, but you will also need to SNAT the traffic back.


Alternative (and best approach IMHO) :

Depending on what your Web Server is (Apache, NGinx) you should consider an HTTP Proxy on your front-end server (192.168.12.87) :

9
  • Works as long as ufw is disabled, even though the port is allows in ufw, but if ufw is enabled, this forwarding stuff doesnt work, any idea ?
    – Sudhir N
    Sep 25, 2016 at 11:35
  • 2
    Great question with great answer. Another use-case this is useful for is if you need to temporarily redirect all the traffic coming to one service, say squid, to another ip/port so as to perform some maintenance on original service without the need to reconfigure all the clients! Very handy!
    – PF4Public
    Dec 15, 2016 at 19:20
  • 4
    " but you will also need to SNAT the traffic back." -> You saved my day. Thank you
    – obayhan
    Feb 27, 2017 at 14:11
  • 1
    This solution isnt working for me. I need to forward from eth0 to a virtual network (virb0) which is used by a KVM-guest. I tried adding the -i and -o options but -o isnt allowed for prerouting. Any suggestions? Dec 23, 2017 at 16:37
  • 4
    Be careful with this solution. I completely lost access to my remote machine now.
    – Soerendip
    Dec 25, 2018 at 8:03
35

The reason a seemingly obvious iptables -t nat -A PREROUTING -d 192.168.12.87 -p tcp --dport 80 -j DNAT --to-destination 192.168.12.77 will not work is how the return packets will be routed.

You can set up rules that will cause the packets send to 192.168.12.87 to simply be NATted to 192.168.12.77, but 192.168.12.77 will then send replies directly back to the client. Those replies will not go through the host where your iptables rule is doing NAT, hence the packets in one direction are translated, but packets in the other direction are not.

There are three approaches to solving this problem.

  1. On the first host don't just do DNAT, but also do SNAT such that return traffic will be send back through the first host. The rule could look something like iptables -t NAT -A POSTROUTING -d 192.168.12.77 -p tcp --dport 80 -j SNAT --to-source 192.168.12.87
  2. Take inspiration from DSR load balancing and DNAT the packets at Ethernet layer instead of at IP layer. By replacing the destination MAC of the packets with the MAC of 192.168.12.77 and sending it on the Ethernet without touching the IP layer, then 192.168.12.77 could have 192.168.12.87 configured on a dummy interface and thus be able to terminate the TCP connection with the server IP known to the client.
  3. Use the naive (but not working) solution on the first host. Then handle the return packets on the second host by doing a SNAT on the return traffic. A rule could look like iptables -t nat -A OUTPUT -p tcp --sport 80 -j SNAT --to-source 192.168.12.87

Each of those three solutions have drawbacks, so you need to carefully consider, if you really need to do this particular forwarding.

  1. Using SNAT will lose the client IP, so host number 2 will think all connections came from 192.168.12.87. Additionally you'll use bandwidth through host number 1 for all reply packets, which would take a more direct route with the other approaches.
  2. The DSR approach will break all other communication between the two nodes. The DSR approach is really only appropriate when the server address is not the primary IP of any of the hosts. Each host need to have a primary IP, which is not the DSR IP.
  3. Using connection tracking on one host to translate in one direction and connection tracking on another host to translate in the other direction is plain ugly, and there are various ways it could break. For example if port numbers are modified by NAT on either host, there is no way to reconstruct those. It is also not a given, that connection tracking will work correctly, if the first packet it sees is a SYN-ACK rather than an ACK.

Of the three approaches I think the first is the one, which is most likely to work. So if you don't need to know the client IP addresses, that is the one I would recommend.

You can also choose to forget about NAT altogether and not try to solve the problem on MAC or IP layer. You can go all the way up to the HTTP layer and look for a solution there. In that case the solution you will find is an HTTP proxy. If you install an HTTP proxy on 192.168.12.87 and configure it appropriately, you can have it forward the requests to 192.168.12.77 and forward the answers back. Additionally it can insert an X-Forwarded-For header preserving the original client IP. The server on 192.168.12.77 then need to be configured to trust the X-Forwarded-For header from 192.168.12.87.

2
  • 1
    I'm surprised -j MASQUERADE is not mentioned here; isn't it the usual approach with DNAT?
    – remram
    Dec 4, 2015 at 19:11
  • 7
    @remram I mentioned SNAT instead of MASQUERADE, because that is what the documentation says. The exact wording in the documentation is: It should only be used with dynamically assigned IP (dialup) connections: if you have a static IP address, you should use the SNAT target.
    – kasperd
    Dec 4, 2015 at 22:17

You must log in to answer this question.

Not the answer you're looking for? Browse other questions tagged .