Building a Transparent Proxy on Linux with Redsocks and Iptables

Networking tutorial - IT technology blog
Networking tutorial - IT technology blog

The Headache of Non-Proxy-Aware Applications

I often run into a specific frustration when managing remote Linux servers or IoT environments: applications that simply refuse to honor proxy settings. You set HTTP_PROXY and HTTPS_PROXY environment variables, yet the application ignores them, attempts a direct connection, and fails because it’s sitting behind a restrictive firewall.

This happens frequently with legacy software, certain CLI tools, and embedded devices like Smart TVs or Raspberry Pi projects. The root cause is that these applications aren’t “proxy-aware.” They don’t check for system variables or have a configuration menu to input proxy details. They expect a direct path to the internet.

The solution isn’t to modify every single app. Instead, I move the logic down to the network layer. By building a Transparent Proxy, the operating system intercepts traffic at the kernel level and redirects it through a proxy without the application ever knowing. To achieve this on Linux, the combination of Redsocks and Iptables is my go-to stack.

Comparing Routing Approaches

Before we look at the implementation, it helps to understand where a Transparent Proxy fits compared to other methods I’ve used in the past.

  • Standard Proxy (SOCKS/HTTP): Requires application-level configuration. If the app doesn’t support it, you’re stuck.
  • System-wide VPN (Tun/Tap): Routes everything, but can be overkill if you only have a SOCKS5 tunnel available or if the VPN protocol is blocked by the upstream provider.
  • Transparent Proxy (Redsocks + Iptables): Redirects specific TCP/UDP packets to a local daemon (Redsocks), which then forwards them to your actual proxy. It’s surgical and doesn’t require specialized VPN drivers on the client side.

Pros and Cons of Transparent Proxying

Pros

  • Zero Configuration: No need to touch application settings. If it sends a packet, it gets proxied.
  • Granular Control: You can choose to proxy only specific ports (e.g., just 80 and 443) or specific destination IPs.
  • Compatibility: Works for any language (Python, Go, Java, C++) because the redirection happens in the Linux kernel (Netfilter).

Cons

  • Complexity: Setting up Iptables rules correctly is tricky. One wrong move can lock you out of your server or create an infinite loop.
  • DNS Leaks: Standard Iptables rules often only handle TCP. DNS (UDP 53) requires extra steps to ensure your ISP isn’t still tracking your queries.

The Recommended Setup

For this setup, I assume you have a SOCKS5 or HTTP proxy server already running (perhaps an SSH tunnel or a commercial provider). We will use a Linux machine (Ubuntu/Debian) as the gateway or the local host.

I have applied this approach in production and the results have been consistently stable, especially for automated scraping bots that don’t support SOCKS5 natively.

[Application] -> [Iptables (Redirect)] -> [Redsocks (Local Port)] -> [Remote Proxy Server] -> [Internet]

Step-by-Step Implementation

1. Install Redsocks

First, install the Redsocks daemon. It acts as the bridge between the Iptables redirect and your actual proxy server.

sudo apt update
sudo apt install redsocks -y

2. Configure Redsocks

The configuration file is usually located at /etc/redsocks.conf. We need to tell Redsocks which local port to listen on and where your upstream proxy is located.

Edit the file: sudo nano /etc/redsocks.conf. Look for the redsocks section:

redsocks {
    /* local_ip is the address redsocks will listen on */
    local_ip = 127.0.0.1;
    local_port = 12345; // This is where Iptables will send traffic

    /* ip and port of your actual SOCKS5/HTTP proxy */
    ip = 1.2.3.4;
    port = 1080;

    /* type can be: socks4, socks5, http-connect, http-relay */
    type = socks5;
}

After saving, restart the service:

sudo systemctl restart redsocks

3. Routing Traffic with Iptables

This is the most critical part. We need to create a new chain in Iptables to handle the redirection. This prevents us from cluttering the default OUTPUT or PREROUTING chains.

I suggest creating a script (e.g., proxy_on.sh) because these rules are lost on reboot unless saved.

# Create a new chain named REDSOCKS
sudo iptables -t nat -N REDSOCKS

# Ignore traffic to your proxy server (to avoid infinite loops)
sudo iptables -t nat -A REDSOCKS -d 1.2.3.4 -j RETURN

# Ignore LAN and reserved IP ranges (we don't want to proxy local traffic)
sudo iptables -t nat -A REDSOCKS -d 0.0.0.0/8 -j RETURN
sudo iptables -t nat -A REDSOCKS -d 10.0.0.0/8 -j RETURN
sudo iptables -t nat -A REDSOCKS -d 127.0.0.0/8 -j RETURN
sudo iptables -t nat -A REDSOCKS -d 169.254.0.0/16 -j RETURN
sudo iptables -t nat -A REDSOCKS -d 172.16.0.0/12 -j RETURN
sudo iptables -t nat -A REDSOCKS -d 192.168.0.0/16 -j RETURN

# Redirect all remaining TCP traffic to the Redsocks local port
sudo iptables -t nat -A REDSOCKS -p tcp -j REDIRECT --to-ports 12345

# Apply the chain to all outgoing traffic from this machine
sudo iptables -t nat -A OUTPUT -p tcp -j REDSOCKS

If you are setting this up on a router/gateway to proxy traffic for other devices on the network, you would use the PREROUTING chain instead of OUTPUT:

sudo iptables -t nat -A PREROUTING -p tcp -s 192.168.1.0/24 -j REDSOCKS

4. Handling DNS

By default, Redsocks only handles TCP. If your DNS queries are still going to your local ISP, you might face “DNS Leaking” or the proxying might fail if the DNS is poisoned. I usually handle this by forcing DNS over TCP or using a dedicated DNS forwarder.

A quick fix is to use a public DNS like 1.1.1.1 and ensure Redsocks is configured to handle UDP (requires the dnstc section in redsocks.conf), but for most basic use cases, ensuring the application uses a fixed DNS IP is enough to get through the tunnel if the proxy supports it.

Testing the Setup

To verify that the transparent proxy is working, I use a simple curl command without any proxy flags:

curl ifconfig.me

If the IP returned matches your proxy server’s IP and not your local ISP IP, the redirection is successful. You can also check the Redsocks logs to see connections being handled:

sudo journalctl -u redsocks -f

Persistence and Cleanup

Iptables rules reset when you reboot. To make them permanent, I use iptables-persistent:

sudo apt install iptables-persistent
sudo netfilter-persistent save

If you ever need to disable the proxying immediately without stopping the service, simply remove the jump rule from the OUTPUT chain:

sudo iptables -t nat -D OUTPUT -p tcp -j REDSOCKS

Wrapping Up

Setting up a transparent proxy with Redsocks and Iptables is a powerful way to force compliance on applications that don’t want to play by the rules. It provides a centralized point of control for your traffic, ensuring that even the most stubborn CLI tool or IoT device stays within your secure tunnel. While the initial Iptables configuration can be intimidating, the stability and “set-it-and-forget-it” nature of this solution make it a staple in my networking toolkit.

Share: