How to set up a simple transparent proxy to one location

Have you ever had a situation where an API you are using demands a whitelist of IP addresses from which it will receive connections? It is not a hard situation to get over - just assign a static IP to your server, and get on with it!

But what if you are deploying immutable servers, so each deployment has a different server? What if you want to scale your app on demand, and do not know how many IPs you will need?

The real solution is to get the API developers to use strong authentication and allow access from anywhere. But if the IP whitelist is insisted upon, we can still get by it relatively easily by setting up a simple proxy server that forwards all traffic to the API endpoint. Then that proxy server can be assigned a static, whitelisted IP address, and all your servers talk to the proxy server when they need to communicate with the API. Bingo! Problem solved.

If the traffic is HTTP or HTTPS, it's possible to do this via a Squid proxy server (preferably with caching turned off). But that's a bit heavy-handed since, if you are using Linux, it's possible to get the same results using the packer filtering framework built into the OS.

Let's say we want to access http://1.2.3.4/resource/123 but it has an IP whitelist. We will set up a server with IP 5.6.7.8, and use it as the proxy. We will configure it so when it receives packets on port 8080, it forwards them to 1.2.3.4 . This way, you can use the server for more than one purpose. Let's say API service 9.10.11.12 also requires an IP whitelist, then you can configure the server to proxy packets to there on port 8081.

First, we tell the OS that we will be forwarding packets:

sysctl -w net.ipv4.ip_forward=1

Next, we issue some iptables statements (that's the name of the packet filtering framework) telling it to set up some 'NAT' rules (Network Address Translation) to fiddle with network packets coming into a certain port to allow other hosts to communicate with the API through it:

iptables -t nat -F
iptables -t nat -A PREROUTING -p tcp -m tcp --dport 8080 -j DNAT --to-destination 1.2.3.4:80
iptables -t nat -A POSTROUTING -o eth0 -d 1.2.3.4 -p tcp --dport 80 -j SNAT --to 5.6.7.8
iptables -A FORWARD -s 0.0.0.0/0 -d 1.2.3.4 -i eth0 -o eth0 -p tcp --dport 80 -j ACCEPT

Here we assume the server's interface is called 'eth0'

Voila! Now, instead of talking to http://1.2.3.4/resource/123 , you talk to http://5.6.7.8:8080/resource/123 from anywhere within your network, and no more trouble with IP whitelisting!

Unfortunately, this will not work for situations where the hostname resolves to different IP addresses over time, such as when it is behind a dynamic load balancer; but when the IP of the service you are talking to is never expected to change, it is the most efficient solution as it requires nothing more than a Linux kernel and iptables tool, which are both standard on all server Linux distributions.