Setup VPN for WAN out only

Hi, I’d like to setup a VPN for WAN traffic only (if possible for some specific applications only) but if not possible, I’d be ok with all WAN out traffic.

My VPN provider offers: Ubuntu, Fedora and CentOS configs, but I believe that none of those fit with DietPI distro (correct me if I’m wrong). Anyway, I can always use a manual OpenVPN config as workaround.

Also, I need to keep SSH on the local network otherwise I’d loose access to my server.

Is this something possible? Thank you.

dietpi-vpn supports ovpn files for config.
To exlude local traffic you need to modify your open vpn config. private / locale IP ranges go through your default interface and the rest is routed through the virtual VPN interface.
See the following link for information:
https://stackoverflow.com/questions/70224509/exclude-ip-from-openvpn-route

It’s also possible to route only app specific traffic through the VPN interface, but it needs some work.
If the app runs on it’s own port you can mark this kind of traffic and then route all marked traffic through the VPN. This can be down with iptable rules, see:
https://www.privateproxyguide.com/using-iptables-to-route-specific-traffic-through-a-vpn/

Ok, first things first, I’m trying to get all traffic to go through the VPN and so far, I seemed to have accomplished it with the config that I added these 3 lines that should let the LOCAL traffic (these are my vlans) out of it:

route 10.0.2.0 255.255.255.0 net_gateway
route 10.0.3.0 255.255.255.0 net_gateway
route 192.168.2.0 255.255.255.0 net_gateway

However, after applying and doing so, I could see that WAN in the server is in fact using the VPN and I’m still able to maintain the local SSH connection to it (great). But… none of my server services are reachable at this point and I don’t get why.

I’m using the exact same host that is accessing through SSH, but for some reason I can’t reach any of my local servers through the web browser. Not even FTP or SMB. Any clue?

Also, I’d like to know how to disable the VPN, because I’ve tried turning off and running service dietpi-vpn stop and even so, I still can’t reach anything. It’s like if the VPN settings (killswitch) were still applied.

It’s like if the dietpi-vpn changed the iptables configs and didn’t revert back when I stopped the VPN. I can see that most of connections are set to DROP (probably due to the killswitch setting, which I then toggled off).

I’m afraid at this point of logging out from SSH and losing access to my server.

I guess the answer is not coming through the same interface which got the request.
Can you check a route to a local client, it should show dev eth0

ip route get <CLIENT_IP>

And do you maybe have any DROP rules in your iptables?

iptables -L -v -n

I guess you need to deactivate the kill switch and not jsut stop the service. These DROP rules you see come from the kill switch, it only allows connections throught the VPN

I fixed the DROP but “reseting” the settings in dietpi-vpn. However, now again, with the right config applied (kill switch on, start on boot etc) and the exceptions posted above, I can’t access any of the hosted services. This is the iptables:

Chain INPUT (policy DROP 174 packets, 9036 bytes)
 pkts bytes target     prot opt in     out     source               destination         
  289 82906 ACCEPT     all  --  lo     *       0.0.0.0/0            0.0.0.0/0           
  395 92135 ACCEPT     all  --  *      *       0.0.0.0/0            0.0.0.0/0            ctstate RELATED,ESTABLISHED
    0     0 ACCEPT     tcp  --  *      *       0.0.0.0/0            0.0.0.0/0            tcp dpt:22

Chain FORWARD (policy DROP 42 packets, 2520 bytes)
 pkts bytes target     prot opt in     out     source               destination         

Chain OUTPUT (policy DROP 22 packets, 1953 bytes)
 pkts bytes target     prot opt in     out     source               destination         
  289 82906 ACCEPT     all  --  *      lo      0.0.0.0/0            0.0.0.0/0           
  224 79848 ACCEPT     all  --  *      tun0    0.0.0.0/0            0.0.0.0/0           
    0     0 ACCEPT     all  --  *      *       0.0.0.0/0            192.168.0.0/16      
  133  7139 ACCEPT     all  --  *      *       0.0.0.0/0            172.16.0.0/12       
   43 17605 ACCEPT     all  --  *      *       0.0.0.0/0            10.0.0.0/8          
  246 93742 ACCEPT     udp  --  *      *       0.0.0.0/0            181.214.206.12       udp dpt:443
    0     0 ACCEPT     udp  --  *      *       0.0.0.0/0            191.96.168.25        udp dpt:443
    0     0 ACCEPT     udp  --  *      *       0.0.0.0/0            195.78.54.47         udp dpt:443
    0     0 ACCEPT     udp  --  *      *       0.0.0.0/0            195.78.54.119        udp dpt:443
    0     0 ACCEPT     udp  --  *      *       0.0.0.0/0            181.214.206.17       udp dpt:443
    0     0 ACCEPT     udp  --  *      *       0.0.0.0/0            181.214.206.28       udp dpt:443
    0     0 ACCEPT     udp  --  *      *       0.0.0.0/0            191.96.168.115       udp dpt:443
    0     0 ACCEPT     udp  --  *      *       0.0.0.0/0            191.96.168.121       udp dpt:443
    0     0 ACCEPT     udp  --  *      *       0.0.0.0/0            195.78.54.38         udp dpt:443
    0     0 ACCEPT     udp  --  *      *       0.0.0.0/0            191.96.168.10        udp dpt:443

FYI: This is a DMZ’d device that has only “return traffic” rule as accepted in the router. But this shouldn’t be an issue since it works without the VPN. This means that I can’t start connections from server → client in my LAN. Not sure if this has any relevance to the matter.

Everything gets dropped except interface lo (loopback interface), port 22 and already established connections, because:

Only connections through the VPN are now allowed, you would need to deactivate the killswitch to allow local connections.

Or you add some rules to allow incomming traffic via eth0

So, how can I always allow LAN communication while preserving the WAN OUT kill switch (which I really want to)? Can I add persistent rules to the iptables that won’t be overridden?

Edit: I disabled the killswitch and the iptables remain the same. Do I need to reboot?

Hm not completely sure, but a reboot should clear it. But you can also do this, to reset everyting:

iptables -F
iptables -t nat -F
iptables -t mangle -F

To allow incoming traffic you can do

iptables -I INPUT 1 -s 192.168.0.0/16 -j ACCEPT

But dietpi-cpn will override the rules when it starts, so you would need to apply this into your ovpn config.

should I add that to to the post script?

edit: yes, it worked. Thanks.

1 Like

@Jappe bumping this because I’m seeking some help in allowing only a specific port from eth0 and not tun0.

I been trying a couple of things but without success. It seems that the killswitch script always somehow overrides it and it either don’t work or blocks everything.

So, TL;DR → I’d like a persistent way to use all traffic throughout the VPN (working right now as default) and allowing a specific user,port etc. to use the router gateway (no VPN), while keeping the kill switch for everything else.

Is this possible?

Edit: or the other way around if it’s easier (force only a specific service through the vpn).

Thank you.

This is possible, but you would need to create a new routing table (to route some traffic through eth0) and mark the specific traffic and add rules so that the marked traffic uses the new routing table. You can mark by various criteria, like ports or a specific user. You would also need to modify the kill switch.

it would also be a good idea to create a script for this, and to don’t use the kill switch of dietpi-vpn but integrate into your script.

YOu can load then this script with your ovpn config

script-security 2
up /etc/openvpn/vpn-policy.sh

Here’s an example how vpn-policy.sh could look like, modify it to fit your needs:

#!/bin/bash

### ---------- RESET old rules ----------
ip rule del fwmark 1 table novpn 2>/dev/null

### ---------- ROUTING ----------
ip rule add fwmark 1 table novpn

### ---------- LAN always allowed ----------
iptables -I INPUT 1 -s 192.168.0.0/16 -j ACCEPT
iptables -I OUTPUT 1 -d 192.168.0.0/16 -j ACCEPT
iptables -I INPUT 1 -s 10.0.0.0/8 -j ACCEPT
iptables -I OUTPUT 1 -d 10.0.0.0/8 -j ACCEPT

### ---------- MARKING: PORT ----------
# example: port 8080 not via VPN
iptables -t mangle -A OUTPUT -p tcp --dport 8080 -j MARK --set-mark 1

### ---------- MARKING: USER ----------
#example: user "novpnuser"
iptables -t mangle -A OUTPUT -m owner --uid-owner novpnuser -j MARK --set-mark 1

### ---------- KILL SWITCH ANPASSUNG ----------
# allow marked traffic via eth0
iptables -I OUTPUT 1 -m mark --mark 1 -o eth0 -j ACCEPT

Create the routing table:

echo "200 novpn" >> /etc/iproute2/rt_tables

Set a gateway for that route (modify gateway IP):

ip route add default via 192.168.2.1 dev eth0 table novpn

After applying you can monitor you traffic to check

tcpdump -i tun0 -n
tcpdump -i eth0 -n

Thank you @Jappe. I think you made it very clear, although with that script I got confused of where the killswitch itself is, since I don’t see any “drop” command in there.

Should I leave the killswitch of the dietpi-vpn enabled combined with these changes that you’ve made here? That’s the missing piece that I didn’t get.

Edit: Also, should I leave the openvpn config like this and add the ip route command to the static_up.sh?

script-security 2
up /etc/openvpn/vpn-policy.sh
up /var/lib/dietpi/dietpi-vpn/static_up.sh

Thanks once again.

Yes you are right, I forgot the rules for the switch.
But now that I think about it again, let the kill switch activated.
Every time you activate the VPN the iptables rules are getting updated, blocking everything except tun0.
Then the rules from the script are applied, they are inserted at the top of the rules (-I flag), so they do not get blocked by the kill switch rules.

So let the switch be activated and don’t include the static_up.sh

Sry for the confusion :smiley:

1 Like

Ok, perfect! Just a minor detail, this rule should be added where?

Edit: I am having real a bad time with this, sorry. I’m trying to mark plex port/traffic to use my WAN and not the VPN but no matter what I do, it seems that the user plex always become without internet access or works partially.

I’m applying the port rule to 32400 and user plex (using its UID in the rule).

Edit2: If it helps the other way around is also fine for me (use only transmission-daemon from dietpi-software using tunneled traffic and let the other services using default WAN). I feel like around this for 2 days without success and no matter what I try, it never works as intended. The use case is very simple: I need to make sure that torrenting is always tunneled (kill switch required) but I also need plex remote accessible out of LAN.

Ok if it’s only for tranmission we can use a simpler approach.
First remove the stuff we added earlier

# Remove MARK rules
sudo iptables -t mangle -F OUTPUT

# Remove policy routing rules (only the novpn table)
sudo ip rule del fwmark 1 table novpn 2>/dev/null
sudo ip route flush table novpn 2>/dev/null

# Remove the novpn entry from rt_tables
sudo ip route del default via 192.168.2.1 dev eth0 table novpn
sudo sed -i '/200 novpn/d' /etc/iproute2/rt_tables

Also remove the script from the ovpn config, we don’t need it anymore. We will create a permanent iptables rule to route everything send from transmission user through tun0.

sudo iptables -A OUTPUT -m owner --gid-owner debian-transmission ! -o tun0 -j REJECT
sudo netfilter-persistent save

You would also need to deactivate the kill switch in dietpi-vpn to let the other traffic route through eth0.

Either I’m doing something very wrong or the results are always the same.

Everytime I turn on the VPN, it routes all traffic (transmission or any other service). Everytime I turn it off, all traffic goes through the ISP (being whatever service/user it is). I’ve tried help with you and chatgpt but this seems like an impossible task, no matter what I try, it doesn’t work. At this point I have the killswitch from the dietpi-vpn off but even so, it either allows everything or blocks everything.

@Jappe this is my openvpn config:

dev tun
proto udp
auth-user-pass /var/lib/dietpi/dietpi-vpn/settings_ovpn.conf
resolv-retry infinite
#redirect-gateway def1
route 10.0.2.0 255.255.255.0 net_gateway
route 10.0.3.0 255.255.255.0 net_gateway
route 192.168.2.0 255.255.255.0 net_gateway
persist-key
persist-tun
nobind
ping 5
explicit-exit-notify 2
script-security 2
up /var/lib/dietpi/dietpi-vpn/static_up.sh
route-up /var/lib/dietpi/dietpi-vpn/up.sh
down /var/lib/dietpi/dietpi-vpn/static_down.sh
remote-cert-tls server
route-delay 5
verb 4

And I have ran every step you’ve provided in your last comment (and then rebooted).

Also, the `#redirect-gateway def1` doesn’t seem to make any difference, it’s like if the OpenVPN or something ignores it completely, because all traffic is routed through the VPN anyways.

Edit: @Jappe at this point I’m starting to think theres a bug conflicting with the dietpi-vpn and our configs. Can you please test on your machine and let me know if it works for you?

Can you share your /var/lib/dietpi/dietpi-vpn/up.sh
And also

ip route
ip rule show
iptables -L OUTPUT -v -n

I’m not able to test this, I don’t use an external VPN.

root@DietPi:/mnt/dietpi_userdata# cat /var/lib/dietpi/dietpi-vpn/up.sh
#!/bin/bash
root@DietPi:/mnt/dietpi_userdata# ip route
ip rule show
iptables -L OUTPUT -v -n
0.0.0.0/1 via 10.31.4.1 dev tun0 
default via 172.16.4.1 dev eth0 onlink 
10.0.2.0/24 via 172.16.4.1 dev eth0 
10.0.3.0/24 via 172.16.4.1 dev eth0 
10.31.4.0/24 dev tun0 proto kernel scope link src 10.31.4.103 
128.0.0.0/1 via 10.31.4.1 dev tun0 
172.16.4.0/28 dev eth0 proto kernel scope link src 172.16.4.2 
172.17.0.0/16 dev docker0 proto kernel scope link src 172.17.0.1 linkdown 
181.214.206.45 via 172.16.4.1 dev eth0 
192.168.2.0/24 via 172.16.4.1 dev eth0 
0:	from all lookup local
32766:	from all lookup main
32767:	from all lookup default
Chain OUTPUT (policy DROP 2205 packets, 318K bytes)
 pkts bytes target     prot opt in     out     source               destination         
95057   63M ACCEPT     all  --  *      lo      0.0.0.0/0            0.0.0.0/0           
 117K   18M ACCEPT     all  --  *      tun0    0.0.0.0/0            0.0.0.0/0           
    0     0 ACCEPT     all  --  *      *       0.0.0.0/0            192.168.0.0/16      
26058 1348K ACCEPT     all  --  *      *       0.0.0.0/0            172.16.0.0/12       
 1194  190K ACCEPT     all  --  *      *       0.0.0.0/0            10.0.0.0/8          
 121K   25M ACCEPT     udp  --  *      *       0.0.0.0/0            181.214.206.45       udp dpt:443
    0     0 ACCEPT     udp  --  *      *       0.0.0.0/0            181.214.206.7        udp dpt:443
    0     0 ACCEPT     udp  --  *      *       0.0.0.0/0            195.78.54.117        udp dpt:443
    0     0 ACCEPT     udp  --  *      *       0.0.0.0/0            191.96.168.141       udp dpt:443
    0     0 ACCEPT     udp  --  *      *       0.0.0.0/0            195.78.54.128        udp dpt:443
    0     0 ACCEPT     udp  --  *      *       0.0.0.0/0            191.96.168.44        udp dpt:443
    0     0 ACCEPT     udp  --  *      *       0.0.0.0/0            191.96.168.157       udp dpt:443
    0     0 ACCEPT     udp  --  *      *       0.0.0.0/0            195.78.54.147        udp dpt:443
    0     0 ACCEPT     udp  --  *      *       0.0.0.0/0            84.17.47.103         udp dpt:443
    0     0 ACCEPT     udp  --  *      *       0.0.0.0/0            195.78.54.118        udp dpt:443

This is with the dietpi-vpn running (With kill switch on).

I think in you case it’s better not not use dietpi-vpn, it sets default route to tun0, but you only want transmission to take that route.

0.0.0.0/1 via 10.31.4.1 dev tun0 
128.0.0.0/1 via 10.31.4.1 dev tun0

Bring up the VPN with you ovpn config, it should set the route for tun0, the default route via eth0 stays untouched.
And with iptables -A OUTPUT -m owner --gid-owner debian-transmission ! -o tun0 -j REJECT only transmission gets rejected on the default route and it will take tun0.

At this point with so many rules I got lost. Sorry. What should I add and where exactly? And how can I use the VPN without the dietpi-vpn? Sorry for asking.