I live in Thailand. Sometimes my internet connection is slow, because my ISP has poor international connectivity with some destinations (Europe, for instance). Sometimes routes that the ISP chooses have a lot of packet losses, or just slow. I needed a way to route SOME of the devices on my LAN another way. I decided to use NordVPN because they have a lot of servers worldwide and my ISP provides a reliable route to SOME of them (I use docker run -it trishmapow/nordvpn-tools FR --load 30 --fping | awk '{ print $NF,$0 }' | sort -k1,1 -n | cut -f2- -d' ' | head -n 10
to find the best servers with the lowest ping for instance). However, I didn't want to deal with installing a VPN client on every device, so I decided to make one inside my Raspberry (but without having the Raspberry use the VPN connection itself, because I have other services running on it).
- Raspberry Pi wired by LAN cable
- Through
raspi-config
go toAdvanced options
-Network Interface Names
- chooseNo
to have the primary lan wired interface calledeth0
. Reboot. - Install Docker
- My network is 192.168.86.0, and the IP address of my Raspberry is 192.168.86.2, adjust accordingly in the instructions below.
#####
# Create a special subnetwork just for this Docker container
#####
docker network create --subnet=172.30.0.0/16 vpn
#####
# Load Docker container that connects to NordVPN via
# a predefined token (can be obtained in their control panel)
# 172.30.0.2 will be the container's IP address (must match the subnet above)
#####
docker run -ti --net vpn --ip 172.30.0.2 --restart=unless-stopped \
--cap-add=NET_ADMIN --cap-add=NET_RAW --name vpn \
-e TOKEN=####INSERT_NORDVPN_TOKEN#### \
-e CONNECT=Netherlands \
-e POST_CONNECT="iptables -I FORWARD -j ACCEPT" \
-e TECHNOLOGY=NordLynx -d ghcr.io/bubuntux/nordvpn
#####
# Confirm that the container has connected to NordVPN
#####
docker logs vpn
#####
# Add some iptables magic to route external traffic into the container
# 192.168.86.0 is my LAN network
# 192.168.86.2 is the IP address of my Raspberry Pi (adjust accordingly)
#####
sudo iptables -t mangle -I PREROUTING -s 192.168.86.0/24 ! -d 192.168.86.2 -j MARK --set-mark 42
sudo iptables -t nat -I POSTROUTING -j MASQUERADE
sudo iptables -I FORWARD -i eth0 -j ACCEPT
echo "200 vpn_gateway" | sudo tee -a /etc/iproute2/rt_tables
####
# I assume that your iptables is saved every time your Raspberry shuts down.
# If it doesn't, install `netfilter-persistent`
####
# sudo apt install netfilter-persistent
# sudo netfilter-persistent save
#####
# Create a systemd service which will enable routing of traffic
# into the container every time the Raspberry restarts
# (netfilter-persistent doesn't save ip routes)
#####
cat <<'EOF' | sudo tee /usr/bin/vpn_gateway.sh
#!/bin/bash
ip route add default table vpn_gateway via 172.30.0.2
ip rule add fwmark 42 table vpn_gateway
EOF
sudo chmod +x /usr/bin/vpn_gateway.sh
cat <<'EOF' | sudo tee /lib/systemd/system/vpn_gateway.service
[Unit]
Description=vpn_gateway Service
After=docker.service
BindsTo=docker.service
ReloadPropagatedFrom=docker.service
[Service]
ExecStart=/usr/bin/vpn_gateway.sh
ExecReload=/usr/bin/vpn_gateway.sh
RemainAfterExit=yes
[Install]
WantedBy=multi-user.target
EOF
sudo systemctl daemon-reload
sudo systemctl enable vpn_gateway.service
sudo systemctl start vpn_gateway.service
#####
# Configure your LAN devices to use 192.168.86.2 as the gateway
# (instead of 192.168.1.1 default in my case).
# Your devices will now be connected through the VPN gateway.
# Done.
#####