I would like to run OpenVPN in client mode on my cloud VM (EC2 instance), so that traffic that exits the VM in general goes through the VPN. But I would still like the existing IP Address to be available for SSH connections (so it doesn't break the SSH connection that I'm currently connected to the machine on).

Here are the current .ovpn settings file that I'm using:

client
dev tun
proto udp
remote xxx.yyy.com 1198
resolv-retry infinite
nobind
persist-key
persist-tun
cipher aes-128-cbc
auth sha1
tls-client
remote-cert-tls server
auth-user-pass
comp-lzo
verb 1
reneg-sec 0
crl-verify crl.rsa.2048.pem
ca ca.rsa.2048.crt
disable-occ

Edit: This question may be a duplicate of Prevent SSH connection lost after logging into VPN on server machine ... but there is no accepted answer over there either.

You can use advanced routing to route packages incoming on your primary interface through the same interface. This way any traffic originating from the server will get routed through VPN, but the primary interface of your server will remain available for connections. The idea here is that if a packet comes through the primary interface, it will use a different routing table named "vpn", so it won't be affected by the routing settings of the VPN client.

In order to achieve this, do the following:

Edit the /etc/iproute2/rt_tables file. It should contain something like this:

#
# reserved values
#
255     local
254     main
253     default
0       unspec
#
# local 
#

Add this line to the end of the file:

1        vpn

To the /etc/network/interfaces file, under the settings of your main interface (or to the appropriate file in /etc/network/interfaces.d/), add the following lines:

up ip route add 0.0.0.0/0 via def.ault.gw table vpn
up ip rule add from the.primary.ip.addr table vpn
down ip route del 0.0.0.0/0 table vpn
down ip rule del from the.primary.ip.addr

Replace the.primary.ip.addr with the IP address of your primary interface (that is, the IP you want your server to be available through), and def.ault.gw with the default gateway address.

  • I just tried this, and after reboot it caused my VM to be inaccessible. – GavinR Aug 15 '17 at 13:37
  • Does your VM have more interfaces, or only one? – Lacek Aug 15 '17 at 14:02
  • Just one (eth0) – GavinR Aug 15 '17 at 14:17
  • Strange, I could not reproduce the behavior you experienced in a virtual environment. The "vpn" table contains the default route only, so if the VPN isn't active, it should behave as it wasn't there at all. Note that if you have more routes beside the default one, all of them should be inserted into the "vpn" table (except for link-local ones, of course). – Lacek Aug 16 '17 at 12:59

I would suggest using the '--up' and '--down' options to run shell scripts that manipulate the firewall and routing table on your VM as you need. This would allow you to tunnel traffic through your VPN (if openvpn isn't doing it already) and make an exception for ssh traffic. Remember that iptables rules are applied in top-down fashion so make sure your exception rule is applied before the tunneling rule. There are other questions that you can use as examples on how to manage the routing tables and firewall rules.

iptables - Target to route packet to specific interface?

I think the problem you are facing is that the default route is on VPN and there are some routes that are filtering out packets that are comming from an interface where it has no route towards source. This is called RP filter.

You have 2 solutions to have different default route for sshd than the rest of processes. You can use network namespaces or you can use cgroups. I do not know much about those, but you can read more in the answers for:
https://superuser.com/questions/271915/route-the-traffic-over-specific-interface-for-a-process-in-linux

You can do it by advanced routing as suggested, but it's not that simple.

The simplest solution to achieve your goal is to route packages addressing your (home) IP address differently. It's always good idea to restrict ssh access to several safe IP addresses. For example you can do:

ip route add 1.1.1.1 via 9.9.9.9

Here 1.1.1.1 is your home ip address, and 9.9.9.9 is some default gateway already reachable in the routing table. Now all packages from your machine to the external IP will come back the same way. You can route everything else over the VPN as normal. You can even add this route in the openvpn config file. Everything is super.

However it's not so super if your home IP is changing (aka dynamic address) or you have to reach your machine from random addresses (multiple users, traveling). That case you must go on the hard way.

Please notice if you don't do anything, the ssh packages will arrive at your external interface (and ip), but they can not find the way back if you route them over the VPN (actually they could depending on your VPN settings, but the source IP will be different and the package will be dropped). Your goal is to redirect some outgoing packages to the external interface and some to the VPN. This is the problem.

Create an alternative routing table :

echo "100 secure" >> /etc/iproute2/rt_tables

Populate and control routing:

# route ssh over external iface eth0 to router 9.9.9.9 
ip route add default via 9.9.9.9 dev eth0 table secure

# send all packages with fwmark 1 to the secondary routing table
ip rule add fwmark 0x1 table secure

# Mark outgoing ssh packages with the mark 1
iptables -t mangle -A OUTPUT -p tcp --sport 22 -j MARK --set-mark 1

Here we will mark all outgoing ssh packages, then redirect all marked packages over the alternative routing. Of course, now you won't to be able to ssh over your vpn because all answer would be redirected to an another interface. The point is, you can create arbitrarily complex iptables rules and route them differently by using set-mark.

Fortunately we have a thing called CONNMARK which (utilizing the connection tracking feature of the kernel) can mark entire connections back and forth (you will need the xt_connmark module).

# mark incoming ssh *connection* with 1. Here eth0 is your external interface
iptables -A INPUT -m state --state NEW -i eth0 -p tcp --dport 22 -t mangle -j CONNMARK --set-mark 1

# restore connection mark (e.g. mark the packages) 
iptables -A OUTPUT -t mangle -j CONNMARK --restore-mark 

# send all packages with fwmark 1 to the secondary routing table as before..
ip rule add fwmark 0x1 table secure

Please use the above according to your current setup after understanding the concepts and do not just copy paste.


Edit: From the client's perspective

If you are using your VPN from the same machine where your are made the ssh connection from, an additional problem emerges.

By default the VPN peer is made the default gateway. It can easily break your existing connection, since your ssh packages will be routed over the VPN channel (the server will get them from the tun or tap interface and not from the physical eth interface). Easy solution is not including the default-gateway option in the client side configuration (or don't push it). Push only the preferred subnets' route. Warning: if you made the VPN to hide your (home) public address, this may not be what you want!

  • I ran this all before running openvpn 'my-vpn-config.ovpn' but still same thing - as soon as I connect to VPN my SSH connection drops. – GavinR Aug 25 '17 at 4:59
  • You have to adapt the whole thing to your own network! And there are multiple (incompatible) solutions above. Just running the commands may not work. The main takeaway here is you have to mark the incoming connection to identify related packages, then mark the very packages (based on the conmark), then drive the marked packages through the alternate routing. BTW, you are trying to connect to the VPN from the same machine you are using for the ssh? That case, you may not use your vpn as default gateway! (I make edit in the answer) – goteguru Aug 26 '17 at 10:26

Your Answer

 

By clicking "Post Your Answer", you acknowledge that you have read our updated terms of service, privacy policy and cookie policy, and that your continued use of the website is subject to these policies.

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