Route all transmission-daemon traffic over OpenVPN by using network namespaces
So I have:
- Debian 11 server with transmission-daemon installed,
- an OpenVPN client config file.
I need to connect to OpenVPN but not to route anything except Transmission through the tunnel. Let's do this!
Starting the OpenVPN client service
.ovpn config to the
/etc/openvpn/client directory and change its extension to
If server pushes defalut route, add following line to the config to ignore it:
pull-filter ignore redirect-gateway
Enable and start OpenVPN:
systemctl enable openvpn-client@your-config-name systemctl start openvpn-client@your-config-name
You can check if it's working by running for example
systemctl status openvpn-client@your-config-name.
First of all, make sure to enable IP forwarding. To do so, add
net.ipv4.ip_forward = 1 line to
/etc/sysctl.conf and run
Create network namespace called
vpn and a pair of veth devices.
VETH_ADDR=10.200.1.1 VPEER_ADDR=10.200.1.2 OUT_IFACE=tun0 # this is the OpenVPN tunnel interface VETH_IFACE=vethns1 VPEER_IFACE=vpeerns1 VPN_NS=vpn ip netns add $VPN_NS ip link add $VETH_IFACE type veth peer name $VPEER_IFACE ip link set $VPEER_IFACE netns $VPN_NS ip addr add $VETH_ADDR/24 dev $VETH_IFACE ip link set $VETH_IFACE up ip netns exec $VPN_NS ip addr add $VPEER_ADDR/24 dev $VPEER_IFACE ip netns exec $VPN_NS ip link set $VPEER_IFACE up ip netns exec $VPN_NS ip link set lo up ip netns exec $VPN_NS ip route add default via $VETH_ADDR
Define new routing table, call it
echo "100 vpn" >> /etc/iproute2/rt_tables
Add fwmark matching rule for this table (I use value of
100 here just for convenience, it can be anything, but must match the value in iptables rule):
ip rule add fwmark 100 table vpn
tun0 as the default route of the table
10.8.0.8 is ipv4 address assigned to my
ip r add default via 10.8.0.8 dev tun0 table vpn
Okay, routing and netns stuff is done, time for some iptables.
192.168.1.2 is the ipv4 address of our linux box.
9091 is the transmission's web interface port and we want it to be accessible:
iptables -t nat -A PREROUTING -d 192.168.1.2 -p tcp -m tcp --dport 9091 -j DNAT --to-destination 10.200.1.2:9091 iptables -t nat -A POSTROUTING -s $VPEER_ADDR/24 -o $OUT_IFACE -j MASQUERADE iptables -t nat -A POSTROUTING -s 192.168.1.0/24 -d 10.200.1.0/24 -j MASQUERADE iptables -t mangle -A PREROUTING -s 10.200.1.0/24 ! -d 10.200.1.1 -j MARK --set-xmark 0x64/0xffffffff
At this point, internet should be accessible from within the
vpn netns and all traffic coming from apps launched inside it must flow through the
Does it work? Check it before continuing
Let's run some tests, first, see if you can at least ping google:
ip netns exec vpn ping 126.96.36.199
If it works, try DNS resolving next. Sometimes it may be a problem, depending on your system DNS resolver:
ip netns exec vpn host google.com
If it fails to resolve, it's most probably because you have some local resolver server put to your
/etc/resolv.conf (pushed by your router, for example), and it's, obviously, not accessible from within the
vpn namespace because all traffic goes through
There are several ways of solving the issue.
- Add some rules to the
vpnrouting table for your LAN. I don't like it because it kinda defeats the purpose: we wanted to route ALL traffic, coming from that netns, through the VPN.
- (Not really a solution.)
ip-netnsutil supports overriding
resolv.conffor programs launched by
ip netns exec. Just create a file named
/etc/netns/vpn/resolv.confand put some external resolver there, and it will be used instead of
/etc/resolv.conf. It's ok for
ip netns exec, but we're not going to use it for starting transmission-daemon.
- Just change the system resolver (in
/etc/resolv.conf). For instance, set it to some public DNS service and mark the file immutable with
chattr +ito prevent it from being modified by DHCP clients, network managers and other smart stuff. Or, if you feel that you can't stand the lack of privacy when using public DNS services, you can create some more complicated setup with local dnsmasq resolver listening at
localhost:53and dnscrypt-proxy as its backend... well it's up for you. Just make it work.
- I could make another trick and also add a mount namespace with substituted
/etc/resolv.conf, but I didn't bother. I just use the 3rd option.
Preparations are done and we're ready to launch transmission-daemon, but we need to launch it inside our new
vpn network namespace. Fortunately, since version 242 systemd supports
NetworkNamespacePath option that is very handy for us.
Copy the unit file, we're going to edit it:
cp /lib/systemd/system/transmission-daemon.service /etc/systemd/system/
[Service] section add the following line:
Probably reload systemd configuration and enable service if needed:
systemctl daemon-reload systemctl enable transmission-daemon
systemctl start transmission-daemon
Try connecting to
192.168.1.2:9091 and happy torrenting!