..

How to tunnel all your traffic through a socks5 proxy in Linux?

Ever wanted to traffic all your traffic through a socks5 proxy and couldn't? Well you're in luck! Here's the script that creates two files:

  1. An xray json file you can run using xray -c config.json
  2. A WireGuard config that connects to the locally-served wireguard server set up by the command above, which you can fire up by `wg-quick client up`
#!/usr/bin/env bash

# Check if wg utility is installed
if ! command -v wg &> /dev/null; then
    echo "Error: 'wg' command not found. Please install wireguard-tools."
    exit 1
fi

# 1. Configuration & Key Generation
LISTEN_PORT=51820
SERVER_IP="127.0.0.1"
SOCKS_OUT_ADDR="127.0.0.1"
SOCKS_OUT_PORT=30808
FWMARK=51820 # Used to break the routing loop

ASSETS_DIR="${HOME}/.config/my_proxies"

# Generate Server Keys
SERVER_PRIV=$(wg genkey)
SERVER_PUB=$(echo "$SERVER_PRIV" | wg pubkey)

# Generate Client Keys
CLIENT_PRIV=$(wg genkey)
CLIENT_PUB=$(echo "$CLIENT_PRIV" | wg pubkey)

# 2. Generate Xray config.json (The Server Side)
cat <<EOF > config.json
{
  "log": { "loglevel": "warning" },
  "inbounds": [
    {
      "port": $LISTEN_PORT,
      "protocol": "wireguard",
      "settings": {
        "secretKey": "$SERVER_PRIV",
        "peers": [
          {
            "publicKey": "$CLIENT_PUB",
            "allowedIPs": ["10.0.0.2/32"]
          }
        ],
        "kernelMode": false
      },
      "tag": "wg-in"
    }
  ],
  "outbounds": [
    {
      "protocol": "socks",
      "settings": {
        "servers": [
          {
            "address": "$SOCKS_OUT_ADDR",
            "port": $SOCKS_OUT_PORT
          }
        ]
      },
      "tag": "socks-out"
    },
    {
      "protocol": "freedom",
      "settings": {},
      "streamSettings": {
        "sockopt": {
          "mark": $FWMARK
        }
      },
      "tag": "direct"
    }
  ],
  "routing": {
    "domainStrategy": "IPIfNonMatch",
    "rules": [
      {
        "type": "field",
        "inboundTag": ["wg-in"],
        "outboundTag": "direct",
        "domain": [
          "ext:geosite.dat:ir"
        ]
      },
      {
        "type": "field",
        "inboundTag": ["wg-in"],
        "outboundTag": "direct",
        "ip": [
          "ext:geoip.dat:ir"
        ]
      },
      {
        "type": "field",
        "inboundTag": ["wg-in"],
        "outboundTag": "socks-out"
      }
    ]
  }
}
EOF

# 3. Generate client.conf (For the WireGuard App)
cat <<EOF > client.conf
[Interface]
PrivateKey = $CLIENT_PRIV
Address = 10.0.0.2/24
DNS = 9.9.9.9
FwMark = $FWMARK

[Peer]
PublicKey = $SERVER_PUB
Endpoint = $SERVER_IP:$LISTEN_PORT
AllowedIPs = 0.0.0.0/0
EOF

echo "---------------------------------------------------"
echo "Success! Configuration files have been generated:"
echo "1. config.json -> Move this to your Xray config folder."
echo "2. client.conf -> Import this into your WireGuard client."
echo "---------------------------------------------------"
echo "⚠️  CRITICAL: ASSET PATH CORRECTION"
echo "Xray does NOT support setting geoip paths inside config.json."
echo "You MUST start Xray with this environment variable so it finds your DAT files:"
echo ""
echo "   export XRAY_LOCATION_ASSET=\"$ASSETS_DIR\""
echo "   xray run -c config.json"
echo "---------------------------------------------------"
echo "⚠️  REMINDER: PREVENT ROUTING LOOPS FOR SOCKS"
echo "Because your WireGuard endpoint is pointed to localhost ($SERVER_IP),"
echo "you MUST manually add a route for your actual proxy server's physical IP"
echo "through your original local default gateway."
echo ""
echo "Run this command on your host machine before starting the tunnel:"
echo "   sudo ip r add <PROXY_SERVER_PUBLIC_IP> via <YOUR_DEFAULT_GATEWAY_IP> dev <YOUR_NETWORK_INTERFACE>"
echo "---------------------------------------------------"

If you use NixOS's firewall you may need to enter this:

sudo sysctl -w net.ipv4.conf.all.rp_filter=2
sudo nft chain inet nixos-fw rpfilter { policy accept \; }
# and when you're done:
sudo nft chain inet nixos-fw rpfilter { policy drop \; }

And like the script says never forget to bypass your connection to your proxy:

sudo ip r add <PROXY_SERVER_PUBLIC_IP> via <YOUR_DEFAULT_GATEWAY_IP> dev <YOUR_NETWORK_INTERFACE>