Redirecting All Container Traffic via SOCKS Proxy Using tun2socks

Published 17.06.2025

Sometimes it becomes necessary to route all outgoing traffic from a specific container through a proxy server. This can be useful for ensuring anonymity, bypassing geo-restrictions, or for testing network configurations. In this article, we’ll look at how to set up such a system using the tun2socks utility and iptables rules, as well as how to manage this process with systemd.


What is tun2socks?

tun2socks is a powerful tool that allows you to redirect network traffic intended for a TUN device through a SOCKS proxy. It creates a virtual network interface (TUN device), and all traffic flowing through it is encapsulated into a SOCKS connection. This is especially convenient when direct application-level proxying is impossible or undesirable.


Installing tun2socks

First, we need to install tun2socks. We’ll use pre-compiled binaries from GitHub.

  1. Go to the tun2socks releases page: https://github.com/xjasonlyu/tun2socks/releases

  2. Select the latest stable version and download the appropriate archive for your architecture (e.g., tun2socks-linux-amd64.tar.gz for 64-bit Linux systems).

  3. Unpack the archive and move the executable file to a system path, for example, /usr/local/bin/:

    # Example for linux-amd64, replace version with the actual one
    wget https://github.com/xjasonlyu/tun2socks/releases/download/v2.5.1/tun2socks-linux-amd64.tar.gz
    tar -xvf tun2socks-linux-amd64.tar.gz
    sudo mv tun2socks-linux-amd64/tun2socks /usr/local/bin/tun2socks
    sudo chmod +x /usr/local/bin/tun2socks
    

    Make sure the path to the binary in your script matches the actual one. In our example, it’s /usr/local/bin/tun2socks.


Traffic Redirection Script

Now, let’s look at the script that automates the process of setting up the TUN device, iptables, and starting tun2socks.

Important note: For correct operation with systemd, we’ll slightly modify the script so that tun2socks runs in the background, allowing the script to exit while systemd manages the tun2socks process.

#!/bin/bash
set -euo pipefail

# Configuration
TUN_DEV="tun0" # TUN device name
TUN_ADDR="10.0.0.2/24" # IP address for the TUN device
FWMARK="100" # Mark for traffic
ROUTE_TABLE="100" # Routing table number
CONTAINER_IP="172.29.172.2" # IP address of your container whose traffic needs to be redirected
SOCKS_PROXY="socks5://username:[email protected]:yyyy" # SOCKS5 proxy address (with authentication)
TUN2SOCKS_BIN="/usr/local/bin/tun2socks" # Path to the tun2socks executable

# Path to the PID file that systemd will use
PID_FILE="/var/run/tun2socks.pid"

# Function to clean up rules
cleanup() {
    echo "[INFO] Cleaning up old routes and iptables..."
    # Delete rules in reverse order of creation
    iptables -t nat -D POSTROUTING -o "$TUN_DEV" -j MASQUERADE 2>/dev/null || true
    iptables -t mangle -D PREROUTING -s "$CONTAINER_IP" -p tcp -j MARK --set-mark "$FWMARK" 2>/dev/null || true

    ip route flush table "$ROUTE_TABLE" 2>/dev/null || true
    ip rule del fwmark "$FWMARK" table "$ROUTE_TABLE" priority "$FWMARK" 2>/dev/null || true

    ip link set "$TUN_DEV" down 2>/dev/null || true
    ip tuntap del dev "$TUN_DEV" mode tun 2>/dev/null || true

    # Remove PID file
    rm -f "$PID_FILE" 2>/dev/null || true
}

# Check command line arguments
if [ "$#" -eq 1 ] && [ "$1" == "cleanup_only" ]; then
    cleanup
    echo "[INFO] Cleanup complete."
    exit 0
fi

# Call cleanup at startup to ensure cleanliness, unless in cleanup_only mode
cleanup

echo "[INFO] Creating $TUN_DEV..."
ip tuntap add dev "$TUN_DEV" mode tun
ip addr add "$TUN_ADDR" dev "$TUN_DEV"
ip link set "$TUN_DEV" up

echo "[INFO] Configuring ip rule and iptables..."
ip rule add fwmark "$FWMARK" table "$ROUTE_TABLE" priority "$FWMARK"
ip route replace default dev "$TUN_DEV" table "$ROUTE_TABLE"

iptables -t mangle -A PREROUTING -s "$CONTAINER_IP" -p tcp -j MARK --set-mark "$FWMARK"
iptables -t nat -A POSTROUTING -o "$TUN_DEV" -j MASQUERADE

echo "[INFO] Starting tun2socks..."
"$TUN2SOCKS_BIN" \
  --device "$TUN_DEV" \
  --proxy "$SOCKS_PROXY" \
  --nohup \
  --log-level info &

# Save tun2socks PID for systemd
echo $! > "$PID_FILE"

echo "[INFO] Setup complete. tun2socks is running."

Script Breakdown

Let’s break down what each part of the script does:

Configuration

At the beginning of the script, key variables are defined:

  • TUN_DEV: The name of the virtual network interface (e.g., tun0).
  • TUN_ADDR: The IP address and subnet mask that will be assigned to TUN_DEV. This address will be used as the gateway for the container.
  • FWMARK: An arbitrary numerical mark that will be used to tag packets intended for redirection.
  • ROUTE_TABLE: The number of a custom routing table where marked traffic will be directed.
  • CONTAINER_IP: Crucial parameter! This is the IP address of your container whose traffic you want to redirect. You’ll need to find it.
  • SOCKS_PROXY: The full address of your SOCKS5 proxy, including protocol, username, password, and port.
  • PID_FILE: The path to the file where the PID of the tun2socks process will be written for systemd to track.

Cleanup Function

The cleanup() function is responsible for removing all previously created iptables rules, routes, and the TUN device itself. This is important to ensure a “clean” state before each new setup and when stopping the service. It also removes the PID file.

Startup and Cleanup Logic

The script checks command-line arguments. If it’s run with the cleanup_only argument, it only executes the cleanup function and exits. Otherwise, it first cleans up previous settings and then proceeds to create new ones.

Creating the TUN Device

  • ip tuntap add dev "$TUN_DEV" mode tun: Creates a new TUN interface with the specified name.
  • ip addr add "$TUN_ADDR" dev "$TUN_DEV": Assigns an IP address to the created TUN interface.
  • ip link set "$TUN_DEV" up: Activates the TUN interface.

Configuring ip rule and iptables

This is the core of the traffic redirection mechanism:

  • ip rule add fwmark "$FWMARK" table "$ROUTE_TABLE" priority "$FWMARK": Creates a routing rule that states: “any packet with mark FWMARK must be processed using routing table ROUTE_TABLE.” The FWMARK priority ensures this rule is considered before others.

  • ip route replace default dev "$TUN_DEV" table "$ROUTE_TABLE": Within our special ROUTE_TABLE, we set a default route that points to our TUN device. This means all traffic that enters this table will be directed through TUN_DEV.

  • iptables -t mangle -A PREROUTING -s "$CONTAINER_IP" -p tcp -j MARK --set-mark "$FWMARK": This is an iptables rule in the PREROUTING chain (which processes packets before they go through routing) in the mangle table (which is used for modifying packets). It says: “if a TCP packet originates from CONTAINER_IP, mark it with FWMARK.” This is how we identify the traffic that needs to be redirected.

  • iptables -t nat -A POSTROUTING -o "$TUN_DEV" -j MASQUERADE: This rule is in the nat table in the POSTROUTING chain (which processes packets immediately before they are sent out). It performs masquerading (SNAT), meaning it changes the source IP address of outgoing packets passing through TUN_DEV to the IP address associated with TUN_DEV. This is necessary for the proxy to work correctly.

Starting tun2socks

  • "$TUN2SOCKS_BIN" --device "$TUN_DEV" --proxy "$SOCKS_PROXY" --nohup --log-level info &: Starts tun2socks itself. It binds to the created TUN_DEV and uses the specified SOCKS_PROXY to redirect all traffic that arrives at TUN_DEV. The --nohup flag allows tun2socks to continue running even after the parent process (the script) exits, and & runs it in the background. --log-level info is useful for debugging.

  • echo $! > "$PID_FILE": Saves the PID of the just-launched background tun2socks to a file so systemd can track it.


How to Use (with systemd)

Now that the script is ready, we can integrate it with systemd for convenient management.

  1. Save the script: Create a file, for example, /usr/local/bin/tun2socks_redirect.sh, and paste the modified script content into it.

    sudo nano /usr/local/bin/tun2socks_redirect.sh
    
  2. Make it executable:

    sudo chmod +x /usr/local/bin/tun2socks_redirect.sh
    
  3. Identify the container’s IP address: If you’re using Docker, you can find the container’s IP address by running docker inspect <container_name> | grep "IPAddress".

  4. Update CONTAINER_IP and SOCKS_PROXY: Make sure to change the values of CONTAINER_IP and SOCKS_PROXY in the /usr/local/bin/tun2socks_redirect.sh script to your own.


Creating the Systemd Unit File

Let’s create a systemd unit file for our service.

  1. Create the file /etc/systemd/system/tun2socks-redirect.service:

    sudo nano /etc/systemd/system/tun2socks-redirect.service
    
  2. Paste the following content:

    [Unit]
    Description=Tun2socks Traffic Redirection Service
    After=network-online.target
    Wants=network-online.target
    
    [Service]
    Type=forking
    # Use Type=forking because our script starts tun2socks in the background
    # and then exits. tun2socks itself daemonizes (thanks to --nohup).
    # PIDFile is used to track the tun2socks PID.
    PIDFile=/var/run/tun2socks.pid
    ExecStartPre=/usr/local/bin/tun2socks_redirect.sh
    # ExecStart is the command systemd will track.
    # Since our script starts tun2socks in the background, systemd will monitor tun2socks via PIDFile.
    ExecStart=/bin/true
    # ExecStopPost runs after the service exits, for cleanup
    ExecStopPost=/usr/local/bin/tun2socks_redirect.sh cleanup_only
    # User=root - because the script requires root privileges
    User=root
    Restart=on-failure
    RestartSec=5s
    
    [Install]
    WantedBy=multi-user.target
    

Explanations for the Unit File:

  • [Unit]:
    • Description: A brief description of the service.
    • After=network-online.target: The service will start after the network is fully configured.
    • Wants=network-online.target: Indicates a desired dependency on the network.
  • [Service]:
    • Type=forking: Informs systemd that the main service process will “fork” a child process (our tun2socks), and the parent process (the script) will exit. systemd will use PIDFile to track the true service process.
    • PIDFile=/var/run/tun2socks.pid: The path to the file where our script saves the PID of the running tun2socks. This is critical for Type=forking.
    • ExecStartPre=/usr/local/bin/tun2socks_redirect.sh: A command that runs before the main service starts. Here, our script sets up the TUN device and iptables rules, and also starts tun2socks in the background.
    • ExecStart=/bin/true: Since tun2socks is already started by our ExecStartPre script and systemd tracks it via PIDFile, we don’t need to start anything else in ExecStart. /bin/true simply returns a successful exit code.
    • ExecStopPost=/usr/local/bin/tun2socks_redirect.sh cleanup_only: A command that runs after the service stops. When called with the cleanup_only argument, the script only cleans up the rules.
    • User=root: The service must run as root, as it modifies network settings and iptables rules.
    • Restart=on-failure: If the service exits with an error, systemd will attempt to restart it.
    • RestartSec=5s: Delay before attempting a restart.
  • [Install]:
    • WantedBy=multi-user.target: The service will be started during system boot in multi-user mode.

Enabling and Starting the Systemd Service

After creating the Unit file and refining the script:

  1. Reload the systemd daemon:

    sudo systemctl daemon-reload
    
  2. Enable the service for automatic startup on boot:

    sudo systemctl enable tun2socks-redirect.service
    
  3. Start the service:

    sudo systemctl start tun2socks-redirect.service
    
  4. Check the service status:

    sudo systemctl status tun2socks-redirect.service
    

    You should see that the service is active (active (running)).

  5. Check the logs:

    journalctl -u tun2socks-redirect.service -f
    

    This will help you monitor the output of the script and tun2socks.

Now, your service will automatically start when the system boots and will attempt to keep tun2socks and the routing rules operational. To stop the service, use sudo systemctl stop tun2socks-redirect.service, and it will automatically clean up the rules. To restart, use sudo systemctl restart tun2socks-redirect.service.


Conclusion

Thus, we have configured a system that redirects all TCP traffic from a specified container through a SOCKS proxy server. This method provides flexibility and control over network traffic, allowing you to easily manage its routing through external proxy services, and integration with systemd significantly increases reliability and ease of management.

I hope this article was helpful! If you have any questions or suggestions, feel free to leave comments.

Get in Touch

Ready to discuss your project and offer the best solution