I've been working with my Pi running Raspbian lately, and I almost have everything set up as I would like. However, I've been stuck for a bit on my next plan - incorporating a VPN connection.

I have transmission-daemon running, the transmission remote gui running, and a nginx webserver running. I have my VPN running (interface ppp0) and routing all traffic over it, while the remote gui and nginx traffic go over eth0, not to the VPN. Can someone help talk me through the routes I need to add to my routing tables to do that? Here are my route -n outputs:

Before VPN:

Kernel IP routing table
Destination     Gateway         Genmask         Flags Metric Ref    Use Iface         UG    0      0        0 eth0   U     0      0        0 eth0

After VPN connected:

Kernel IP routing table
Destination     Gateway         Genmask         Flags Metric Ref    Use Iface         U     0      0        0 ppp0 UH    0      0        0 ppp0 UGH   0      0        0 eth0 UGH   0      0        0 eth0   U     0      0        0 eth0
  • What exactly do you want to do? What type of traffic you don't want to go through the VPN?
    – Cha0s
    Jan 3, 2015 at 17:24
  • I currently don't want my webserver traffic to go through the VPN Jan 3, 2015 at 17:37

2 Answers 2


One way to have your webserver get routed outside of the VPN is by using the owner match capabilities of iptables.


This module attempts to match various characteristics of the packet creator, for locally generated packets. This match is only valid in the OUTPUT and POSTROUTING chains. Forwarded packets do not have any socket associated with them. Packets from kernel threads do have a socket, but usually no owner.

[!] --uid-owner username
[!] --uid-owner userid[-userid]
    Matches if the packet socket's file structure (if it has one) is owned by the given user. You may also specify a numerical UID, or an UID range. 
[!] --gid-owner groupname
[!] --gid-owner groupid[-groupid]
    Matches if the packet socket's file structure is owned by the given group. You may also specify a numerical GID, or a GID range. 
[!] --socket-exists
    Matches if the packet is associated with a socket. 

So the general idea is that you use iptables mangle to match the packets originating from the nginx UID and mark them.

Then you add a default gateway on a different routing table and use that to route the marked packets.

That new default gateway will use the gateway instead of the VPN gateway.

Of course this is not the only way to accomplish this. You could do this based on the source port of the outgoing packets to match the http traffic of nginx or any other way that suits you. Either way you will need to do packet/connection marking and routing marking to route specific packets via a different gateway.

On MikroTik RouterOS this is a matter of a view clicks. Unfortunately I haven't done this on plain linux before so I haven't got hands on example to provide you with at the moment.

I hope that steers you in the right direction though :)

  • This makes sense! I think I may have found out the main issue - the pi responds to incoming traffic on the eth0 interface on the ppp0 interface. Is there a way to make the pi respond to traffic on the same interface it received it? Jan 3, 2015 at 18:16
  • Yeap, it's pretty much the same concept. Instead of marking nginx's outgoing packets you mark the incoming packets (connection marking) from eth0 and based on those marks you then route the replies (via a separate routing table) back via eth0.
    – Cha0s
    Jan 3, 2015 at 18:52

I once set up vpnc on a RPi to allow for a so called client side split tunnel doing the following. The system is archlinux 3.12.33-1 with vpnc 0.5.3 but I do not see why it should not be working on raspbian. Find a full description (that I followed to the letter) here.

  1. List all the hosts to be accessed via VPN and resolve their IP addresses. This is necessesary as name resolving using DNS might not work properly when establishing the tunnel. Write those IP's and hostnames in /etc/hosts. Keep the list short and include only the hosts that are really needed.
  2. Assuming you have a working vpnc config file, copy it: cp /etc/vpnc/corp.conf /etc/vpnc/split.conf
  3. Edit split.conf to add the line Script /etc/vpnc/vpnc-script-split. This will later on call another script during execution of the config file.
  4. Create the script file /etc/vpnc/vpnc-script-split containing the following (include the IP's gathered in step 1). Note that this needs numeric IP's and does not resolve hostnames:


# Add one IP to the list of split tunnel
add_ip ()
    export CISCO_SPLIT_INC=$(($CISCO_SPLIT_INC + 1))
# Initialize empty split tunnel list

# Delete DNS info provided by VPN server to use internet DNS
# Comment following line to use DNS beyond VPN tunnel

# List of IPs beyond VPN tunnel
add_ip   # your IP's go here

# Execute default script
. /etc/vpnc/vpnc-script

# End of script
  1. Give the script executable permission chmod 755 /etc/vpnc/vpnc-script-split
  2. Henceforth establish VPN tunnel by calling vpnc split.conf otherwise the standard configuration is used and the split tunnel is not set up.

Credits for the Howto go to Antonio Borneo (see link above). Note that this question could also be asked at Unix.SE as it is not entirely RaspberryPi specific.

Your Answer

By clicking “Post Your Answer”, you agree to our terms of service and acknowledge you have read our privacy policy.

Not the answer you're looking for? Browse other questions tagged or ask your own question.