How do I route everything except a few ports out a VPN?
March 20, 2014 7:59 PM   Subscribe

I've got a VPS. If I set up a VPN connection from it to a VPN provider in NL, everything goes through the VPN, but that means I can't SSH to the machine anymore. How do I set this up such that the VPS is listening at its regular IP on SSH, HTTP, and HTTPS, but everything else goes through the VPN?

Machine is currently running Ubuntu 12.04, but that's flexible. I have no control over the VPN endpoint.
posted by chazlarson to Computers & Internet (6 answers total) 4 users marked this as a favorite
I feel like this is something that should be possible with iptables, although I don't know it well enough to tell you how.
posted by ryanrs at 9:54 PM on March 20, 2014

A slightly less vague answer, your solution lies in virtual lan interfaces. You want to bind two to your physical interface(or really, the virtual one of your VPS, but you get what i mean). Assign one to the VPN connection, and one to those services.

The easiest way to do this will be to get whoever is hosting your VPS to just flop another virtual interface onto your VM. Buuuut if they won't without billing you more, or you don't to deal with that there are ways to do this. I don't remember exactly how, but it's the same thing that running an instance of something like virtualbox would do to bind it's virtual interface to the host operating systems "real" one.

I played around with this binding stuff in the past to do evil things like route all torrent traffic over open wifi, and everything else over my home connection.

this sort of thing will be the basis of your quest. From there, it's just the helicopter dicking of leaving the original "primary" one for the VPN stuff, then setting ssh, http(s), etc to go through the other one. Last time i dealt with this i think it took me less than an hour with lots of googling at every step i got confused at.
posted by emptythought at 10:35 PM on March 20, 2014

you don't need any extra virtual interfaces, the VPN is already doing all of that for you. the problem you're seeing is that the VPN becomes your default route, so when you talk to the server over ssh it replies out through the VPN which confuses everyone (not really but that's an easy simplification). you need to configure policy routing to say "when connections come in on the main interface, also reply out that interface".

the basic config is described in the LARTC (Linux Advanced Routing and Traffic Control) docs, particularly Routing for multiple uplinks/providers - this info isn't distribution specific, but covers the basic theory.

for Ubuntu I'd probably put the "ip rule ..." and "ip route ..." commands in /etc/network/interfaces as post-up config items on the VPN interface with matched pre-down commands to clean up when the VPN comes down. I don't have an example of this type of config handy but if you need a hand I can grab one tomorrow when I get back in to work.
posted by russm at 4:10 AM on March 21, 2014 [1 favorite]

I've never done this myself so I may be totally confused. But can't you just configure your SSH daemon and your web server to listen on both IP addresses? That way you can ssh in via the VPN address or the native address, your choice.

The sshd man page says its a simple matter of adding ListenAddress lines to /etc/ssh/sshd_config. "The default is to listen on all local addresses."; you may also see mentioned. Try just manually adding addresses, restarting sshd, and seeing if it works? (Note when restarting sshd you could lose access to the machine.) I think the process is similar for web servers.

The thing that complicates all this is if either IP address is dynamic you can't just hardcode it into the config file. I don't know how to solve that but I'd look at the docs for my VPN and DHCP clients. Also I'm a bit confused about why sshd isn't listening on the native interface already if you have the default configuration.
posted by Nelson at 8:43 AM on March 21, 2014

I've been meaning to figure this out for my own use... this advice appears to work. (It's a specific example of the instructions russm linked to.)
posted by Zed at 11:39 AM on March 21, 2014

Nelson - in general the problem with this sort of configuration isn't whether the target system is actually listening on the expected address (ie. what interfaces sshd is bound to) but rather how return packets are routed.

Bringing up a VPN link will usually set the default route to be over that VPN. If that's the case here, when chazlarson tries to ssh to his server (at address <VPS>), the return packet (with source address of <VPS>) will be sent over the VPN link instead of directly out the primary interface. When that packet reaches the VPN provider they see the source of <VPS> and notice it isn't part of their own address space and drop it on the floor as spoofed. The upshot is that connections from the outside world to the primary network interface of the server stop working.

You might wonder why the server isn't smart enough to know that a connection to a certain interface should be replied to from that same interface, and you'd be justified in asking that question. The answer is that IP routing and the association between interfaces and addresses isn't as simple as you might expect, and you need to tell the stupid computer how to do it right. That's what the policy routing stuff I linked up above is all about.
posted by russm at 7:12 PM on March 22, 2014 [1 favorite]

« Older BarBri v. Kaplan - 2014 Edition   |   Best Vietnam War documentaries? Newer »
This thread is closed to new comments.