Use an SSH layer-3 TUN plus NAT when a remote box can accept SSH from you, but you want its outbound traffic to leave through your machine. This is not a port forward (-L/-R/-D). It is a point-to-point tunnel (-w) that needs root on both ends and a host route so you do not kill the SSH session when you replace the remote default route.
1. Allow TUN on the SSH server
On the remote host (the SSH server you connect to), set PermitTunnel yes in sshd_config (or a drop-in under /etc/ssh/sshd_config.d/), then restart the daemon. Debian/Ubuntu use the ssh unit; RHEL-family uses sshd:
# /etc/ssh/sshd_config
PermitTunnel yes
sudo systemctl restart ssh # Debian/Ubuntu
# sudo systemctl restart sshd # RHEL, Fedora, Rocky
2. Open the tunnel as root, with your user key
sudo ssh reads /root/.ssh, not your key. Pass your identity file. -w 0:0 creates tun0 on both sides (use -w 1:1 if tun0 is already taken):
sudo ssh -w 0:0 -i /home/$USER/.ssh/id_ed25519 [email protected]
Leave that session up. Configure addresses from another terminal (or tmux).
3. Address tun0 on both sides
Local (the box with the internet you want to share):
sudo ip addr add 10.0.0.1/24 dev tun0
sudo ip link set tun0 up
Remote:
sudo ip addr add 10.0.0.2/24 dev tun0
sudo ip link set tun0 up
4. NAT on the local box
Pick the interface that actually has the default route. eth0 is often wrong on modern systems:
WAN=$(ip -4 route show default | awk '{print $5; exit}')
echo 1 | sudo tee /proc/sys/net/ipv4/ip_forward
sudo iptables -t nat -A POSTROUTING -o "$WAN" -s 10.0.0.0/24 -j MASQUERADE
On nftables-only hosts, masquerade with nft instead of iptables. Persist forwarding with net.ipv4.ip_forward=1 in /etc/sysctl.d/ only if you want this to survive reboot.
5. Pin the SSH client, then change the remote default route
If you ip route replace default on the remote first, SSH return traffic follows the tunnel and the session dies. Add a /32 for the client via the old gateway, then replace default:
# on the remote, before touching default
CLIENT=$(echo "$SSH_CLIENT" | awk '{print $1}')
GW=$(ip -4 route show default | awk '{print $3; exit}')
DEV=$(ip -4 route show default | awk '{print $5; exit}')
sudo ip route add "$CLIENT"/32 via "$GW" dev "$DEV"
sudo ip route replace default via 10.0.0.1 dev tun0
Verify
# on the remote
ping -c 3 8.8.8.8
curl -4 ifconfig.me # should be the local machine's public IP
Teardown
# remote: restore its original default, drop the /32
sudo ip route replace default via "$GW" dev "$DEV"
sudo ip route del "$CLIENT"/32
# local: remove NAT (use the same $WAN as above)
sudo iptables -t nat -D POSTROUTING -o "$WAN" -s 10.0.0.0/24 -j MASQUERADE
# then exit the sudo ssh -w session; tun0 goes away with it