Ssh – Can’t ssh into EC2 instance once VPN client connected

amazon ec2iptablesnetworkingsshvpn

I'm running Ubuntu 18.04.4 LTS server in a EC2 instance. I installed expressvpn client in this server (which I'm using regularly in my home servers without any issues).

Once the VPN connection starts on the server I am no longer able to connect to the server from my laptop. I also have an Apache server running on the server that also unreachable at this point.

Is there anyway to fix this.
I understand that this could happen due to a weird way of configuration in AWS. In that case, is there a way to force all traffic to port 22 to a specific non-VPN interface like eth0?

Output of ip rule , iptables -nvL and ip route

before connecting vpn

Tue Apr 21 21:51:01 UTC 2020
0:  from all lookup local
32766:  from all lookup main
32767:  from all lookup default
---------
Chain INPUT (policy ACCEPT 7536 packets, 1858K bytes)
 pkts bytes target     prot opt in     out     source               destination

Chain FORWARD (policy ACCEPT 0 packets, 0 bytes)
 pkts bytes target     prot opt in     out     source               destination

Chain OUTPUT (policy ACCEPT 7340 packets, 2732K bytes)
 pkts bytes target     prot opt in     out     source               destination
---------
default via 172.31.32.1 dev eth0 proto dhcp src 172.31.35.37 metric 100
172.31.32.0/20 dev eth0 proto kernel scope link src 172.31.35.37
172.31.32.1 dev eth0 proto dhcp scope link src 172.31.35.37 metric 100

After connecting to vpn

Tue Apr 21 21:53:01 UTC 2020
0:  from all lookup local
32766:  from all lookup main
32767:  from all lookup default
---------
Chain INPUT (policy ACCEPT 8168 packets, 2072K bytes)
 pkts bytes target     prot opt in     out     source               destination

Chain FORWARD (policy ACCEPT 0 packets, 0 bytes)
 pkts bytes target     prot opt in     out     source               destination

Chain OUTPUT (policy ACCEPT 7954 packets, 2896K bytes)
 pkts bytes target     prot opt in     out     source               destination
---------
0.0.0.0/1 via 10.150.0.21 dev tun0
default via 172.31.32.1 dev eth0 proto dhcp src 172.31.35.37 metric 100
10.0.0.0/8 via 172.31.32.1 dev eth0
10.150.0.1 via 10.150.0.21 dev tun0
10.150.0.21 dev tun0 proto kernel scope link src 10.150.0.22
43.241.61.245 via 172.31.32.1 dev eth0
128.0.0.0/1 via 10.150.0.21 dev tun0
172.16.0.0/12 via 172.31.32.1 dev eth0
172.31.32.0/20 dev eth0 proto kernel scope link src 172.31.35.37
172.31.32.1 dev eth0 proto dhcp scope link src 172.31.35.37 metric 100
192.168.0.0/16 via 172.31.32.1 dev eth0

Best Answer

Suppose the services that listens to the specific ports replies with the original destination port as the replying source port (or even any non-random specific ports), you can have ip rules like:

ip rule add iif lo ipproto tcp sport 22 table 123

and have the direct route to the LAN (gateway) and the default route in the table:

ip route add 172.31.32.1 dev eth0 table 123 / ip route add 172.31.32.0/20 dev eth0 table 123
ip route add default via 172.31.32.1 dev eth0 table 123

Or if you can and want to, you may avoid having the "de facto default route" that leads to the tunnel in the main table (e.g. by removing/ignoring redirect-gateway ... in the case of openvpn) and add one manually (e.g. with the up script directive) to a new table, then have the aforementioned ip rules look up the main table, but with another rule of lower priority than it (but higher than 32766) look up to the new one. This way you don't need to change your configurations when the LAN subnet changes because of DHCP (and gateway doesn't matter / isn't necessary for tun routes).