How to tunnel all your outgoing traffic, but keep your connection to your VPS
Add this to your wireguard config:
[Interface]
# under interface add:
PostUp = /etc/wireguard/post-up.sh
PostDown = /etc/wireguard/post-down.sh
Fill in the variables and use these AI-written bash scripts, post up:
#!/bin/bash
#
# This script is executed by WireGuard's PostUp hook.
# It creates a new routing table and rules to ensure that traffic
# originating from the server's public IP is routed through the
# public gateway, preserving new and established connections.
# ==============================================================================
# Configuration - PLEASE FILL IN THESE VALUES
# ==============================================================================
# Your server's public IPv4 address.
# Example: PUBLIC_IPV4=""
PUBLIC_IPV4=""
# Your server's public IPv6 address (optional, leave blank if none).
# Example: PUBLIC_IPV6="2001:db8::1"
PUBLIC_IPV6=""
# Your server's public-facing network interface.
# Find with: ip a | grep 'state UP'
# Example: PUBLIC_INTERFACE="eth0"
PUBLIC_INTERFACE="eth0"
# The gateway for your public IPv4 address.
# Find with: ip route | grep default
# Example: GATEWAY_IPV4="198.51.100.1"
GATEWAY_IPV4=""
# The gateway for your public IPv6 address (optional, leave blank if none).
# Find with: ip -6 route | grep default
# Example: GATEWAY_IPV6="2001:db8::ffff"
GATEWAY_IPV6=""
# --- Advanced Configuration ---
# A unique ID for the custom routing table. Choose a number between 1 and 252
# that is not already in use in /etc/iproute2/rt_tables.
TABLE_ID=52
TABLE_NAME="keep_connections"
# The priority for the routing rule. Lower numbers are checked first.
PRIORITY=1000
# ==============================================================================
# Script Logic - DO NOT EDIT BELOW THIS LINE
# ==============================================================================
set -e # Exit immediately if a command exits with a non-zero status.
echo "--- [WG PostUp] Maintaining public connectivity ---"
# Add a named routing table for clarity. This makes it easier to identify its purpose.
if ! grep -q "^\s*$TABLE_ID\s*$TABLE_NAME\s*$" /etc/iproute2/rt_tables; then
echo "Adding routing table '$TABLE_NAME' to /etc/iproute2/rt_tables"
# Using tee with sudo to ensure we have permission to write to the file
echo "$TABLE_ID $TABLE_NAME" | sudo tee -a /etc/iproute2/rt_tables > /dev/null
fi
# --- Add routes to the custom table ---
# These routes define how to send traffic out through the public interface.
# IPv4
if [[ -n "$PUBLIC_IPV4" && -n "$GATEWAY_IPV4" ]]; then
echo "Adding IPv4 default route to table '$TABLE_NAME'..."
ip route add default via "$GATEWAY_IPV4" dev "$PUBLIC_INTERFACE" table "$TABLE_ID"
else
echo "Skipping IPv4 route configuration (address or gateway not set)."
fi
# IPv6
if [[ -n "$PUBLIC_IPV6" && -n "$GATEWAY_IPV6" ]]; then
echo "Adding IPv6 default route to table '$TABLE_NAME'..."
ip -6 route add default via "$GATEWAY_IPV6" dev "$PUBLIC_INTERFACE" table "$TABLE_ID"
else
echo "Skipping IPv6 route configuration (address or gateway not set)."
fi
# --- Add policy routing rules ---
# These rules tell the kernel to use our custom table for any traffic coming *from* the public IP.
# IPv4
if [[ -n "$PUBLIC_IPV4" ]]; then
if ! ip rule list | grep -q "from $PUBLIC_IPV4 lookup $TABLE_NAME"; then
echo "Adding IPv4 policy rule..."
ip rule add from "$PUBLIC_IPV4/32" table "$TABLE_ID" priority "$PRIORITY"
else
echo "IPv4 policy rule already exists."
fi
fi
# IPv6
if [[ -n "$PUBLIC_IPV6" ]]; then
if ! ip -6 rule list | grep -q "from $PUBLIC_IPV6 lookup $TABLE_NAME"; then
echo "Adding IPv6 policy rule..."
ip -6 rule add from "$PUBLIC_IPV6/128" table "$TABLE_ID" priority "$PRIORITY"
else
echo "IPv6 policy rule already exists."
fi
fi
echo "--- [WG PostUp] Script finished successfully ---"
post down:
#!/bin/bash
#
# This script is executed by WireGuard's PostDown hook.
# It cleans up the rules and routes created by the PostUp script
# to restore the server's default routing behavior.
# ==============================================================================
# Configuration - MUST MATCH YOUR PostUp SCRIPT
# ==============================================================================
# Your server's public IPv4 address.
# Example: PUBLIC_IPV4="198.51.100.5"
PUBLIC_IPV4=""
# Your server's public IPv6 address (optional, leave blank if none).
# Example: PUBLIC_IPV6="2001:db8::1"
PUBLIC_IPV6=""
# --- Advanced Configuration ---
TABLE_ID=52
TABLE_NAME="keep_connections"
PRIORITY=1000
# ==============================================================================
# Script Logic - DO NOT EDIT BELOW THIS LINE
# ==============================================================================
set -e # Exit immediately if a command exits with a non-zero status.
echo "--- [WG PreDown] Cleaning up routing rules ---"
# --- Remove policy routing rules ---
# IPv4
if [[ -n "$PUBLIC_IPV4" ]]; then
# Use a loop to be safe, in case a rule was added multiple times by mistake.
while ip rule list | grep -q "from $PUBLIC_IPV4.*lookup $TABLE_NAME"; do
echo "Removing IPv4 policy rule..."
ip rule del from "$PUBLIC_IPV4/32" table "$TABLE_ID" priority "$PRIORITY"
done
fi
# IPv6
if [[ -n "$PUBLIC_IPV6" ]]; then
while ip -6 rule list | grep -q "from $PUBLIC_IPV6.*lookup $TABLE_NAME"; do
echo "Removing IPv6 policy rule..."
ip -6 rule del from "$PUBLIC_IPV6/128" table "$TABLE_ID" priority "$PRIORITY"
done
fi
# --- Flush the custom routing table ---
# This removes the default routes we added to our custom table.
echo "Flushing routing table '$TABLE_NAME'..."
ip route flush table "$TABLE_ID"
if [[ -n "$PUBLIC_IPV6" ]]; then
ip -6 route flush table "$TABLE_ID"
fi
echo "--- [WG PostDown] Script finished successfully ---"