Using SSH As A Full VPN

I’m always messing around with Virtual Private Networks (VPN). I can’t quite bring myself to use the internet without VPN protection; my world-view just doesn’t acknowledge that un-encrypted internet traffic should exist. But, as someone recently stated, “deal with the world as it is, not how you want it to be, so I run a VPN 100% of the time from all my devices. Let me assure you, that level of VPNess can be a pain to maintain, so I am always looking for more reliable and cheaper ways to keep that VPN running all the time.

Unlike many people, I don’t use a VPN to access geo-restricted content – AKA, “the Netflix reason”. I use a VPN for a two different reasons:

  1. To ensure my internet traffic is encrypted even when I am using services or sites that do not provide encryption natively,.

  2. To deny my ISP and their “partners” access to my internet traffic.

In short, I use a VPN to provide privacy, but I do not care about anonymity. If you’re not steeped in privacy terminology, the difference between anonymity and privacy is this:

Anonymity means I can see what you’re doing, but I don’t know who you are. Privacy means I can’t see what you’re doing, but I know who you are. All VPNs provide some level of privacy because they all encrypt traffic between your device and the VPN server. Most VPNs also provide anonymity incidentally because many VPN customers use the same VPN server and therefore traffic between those users is intermingled, and it’s not possible to determine which customer belongs to which traffic.

Note: many free or unethical VPN providers observe your traffic on their server but that is a business decision and not a shortcoming in the VPN architecture itself. When considering a VPN provider, read their privacy policy and terms of service. Look for words like “we do not capture logs” and stuff like that.

The recurring problems I have with VPN providers are:

I’ve used a lot of different VPN services over the years while trying to find one that doesn’t have any of those problems and I’ve never been able to find one. They all have one or more of those problems.

Once I realized that I was tilting at windmills, I turned my attention inward to the things I know. I know how to use Secure SHell (SSH) – as a Linux sysadmin it is my main tool to connect to remote systems. I also know how to make SSH run as a proxy so I can tunnel internet traffic through it. I also have many servers out on the internet which I can use. However, the problem with using SSH as a proxy is that you have to configure your operating system to use the proxy. Or, at least, individual applications need to support proxy configuration. Spoiler: most do not.

Configuring an OS to use a proxy is easy. All the major OSes can be configured to use a proxy somewhere in their network settings. But dislike that option because there are some sites I use that will block connections from commercial IP addresses, or have some other objection when I try to log into my account from a distant IP address. Because of that, I need to shut off the proxy temporarily sometimes and digging through my OS innards to do that is a pain.

Setting up individual apps to use an SSH is a hit-and-miss because not all applications have proxy settings. FoxyProxy is a plugin for both Chrome and Firefox that makes SSH proxying through a browser trivial, but there’s just a truckload of internet traffic on our computers that has nothing to do with any visible app we’re running and it’s not possible to track it all down to its respective app and then see if that app can be configured to use the SSH proxy. That’s a losing battle and running a VPN that tunnels all network traffic, regardless of origin, through the VPN is the best solution.

During my journey to find the perfect VPN I never took my eyes off SSH. I wanted to find a solution that uses SSH because it is reliable, mature, and widely available but I had discarded it as impractical for the reasons I mentioned in the previous paragraph. Then, out of the blue, I ran across sshuttle.

What is sshuttle?

I was very pleased to find the sshuttle project which does exactly what want. It uses SSH as a full-blown VPN and routes all my traffic through the SSH tunnel just as a VPN would, but without all the crappy things about an actual VPN. The sshuttle maintainers totally get me as shown by this list of reasons why sshuttle is better than a VPN.

As far as I know, sshuttle is the only program that solves the following common case:

  • Your client machine (or router) is Linux, FreeBSD, or MacOS.

  • You have access to a remote network via ssh.

  • You don't necessarily have admin access on the remote network.

  • The remote network has no VPN, or only stupid/complex VPN protocols (IPsec, PPTP, etc). Or maybe you are the admin and you just got frustrated with the awful state of VPN tools.

  • You don't want to create an ssh port forward for every single host/port on the remote network.

  • You hate openssh's port forwarding because it's randomly slow and/or stupid.

  • You can't use openssh's PermitTunnel feature because it's disabled by default on openssh servers; plus it does TCP-over-TCP, which has terrible performance.

How do I use sshuttle?

First, install it! It is in most repositories I’ve checked. You can install it on Debian strains like so:

sudo apt install sshuttle

The only other thing you need is access to a shell account on some remote server, usually a Linux server. Assuming you have that, you can use this quick one-liner to get the tunnel running:

sudo sshuttle -r $USER@$SERVER -x $SERVER 0/0

That’s it. Once you log in, the tunnel is set up and you’re now tunneling all your traffic through the remote server. Try this to see how your IP has changed:

curl ipinfo.io

How do I use sshuttle better?

I wanted a little more than the basics. I do not like to use SSH password authentication so I needed sshuttle to take a keypair to log in. Thankfully, you can send sshuttle standard ssh options by using the sshcmd switch. I use the sshcmd switch to tell sshuttle to use a key to authenticate to my remote server like this:

sudo sshuttle -r $USER@$SERVER:$PORT -x $SERVER 0/0 —ssh-cmd 'ssh -i /$PATH/$SSH_KEY'

Pro tip: If you automate the connection via systemd (more on that later) then you do not want a passphrase on your private key. I most definitely do have a passphrase on my privileged user key and I do not want to remove it. To get around this, I created a non-priveleged user that cannot sudo on my system and created a passwordphrase-less keypair to it. I use that account/keypair for my sshuttle use.

Next, I wanted to send my DNS requests through the SSH tunnel in addition to my traffic. Many people forget this step when setting up privacy tools. You may know that DNS is the Domain Name System, and it is responsible for converting domain names like jonwatson.ca to IP addresses like 192.124.249.64. Armed with that knowledge, you can see how allowing your ISP to resolve your DNS requests provides your ISP with a nice list of every site you’ve ever visited. Pushing those DNS requests through the tunnel to your remote server eliminates your ISP’s ability to observe those requests. To add this protection to my sshuttle, I add the --dns switch:

sudo sshuttle -r $USER@$SERVER:$PORT -x $SERVER 0/0 —dns —ssh-cmd 'ssh -i /$PATH/$SSH_KEY'

You can confirm your DNS is being pushed through your remote server by using a DNS Leak test site like this one. For example, my remote server is configured to use OpenDNS in the /etc/resolv.conf file, and that is what I see when I run a DNS Leak test, not my ISP’s or local network resolvers.

The final thing I wanted out of sshuttle was to resume the tunnel after my laptop comes out from suspend. It is my experience that this does not work well with any VPN providers. However, in those cases, I could usually track it down to a bug in OpenVPN. Most VPN providers are running OpenVPN under the hood, and when my laptop comes back from suspend, the OpenVPN manager is not responsive and therefore the VPN cannot restart without manual intervention. No such problem with sshuttle because it doesn’t use OpenVPN.

There are a few other options that may interest you, such as the --daemon option which tells sshuttle to fall to the background once it starts. I prefer to see all my juicy debug in the terminal as it runs so I do not use that option, but you may like it. Try the sshuttle —help command to see more options.

If you’re using a Linux distribution that uses systemd, this should work for you (replace the variables with your server and user, obviously):

$ cat /usr/lib/systemd/system-sleep/sshuttle #!/bin/sh case $1 in post) /usr/bin/sshuttle -r $USER@$SERVER:$PORT -x $SERVER 0/0 —dns —ssh-cmd 'ssh -i /$PATH/$SSH_KEY' ;; esac

If you’re using a SysV system, use your startup files in /etc/init.d to control the sshuttle startup

That solves my laptop and desktop VPN problem. It still does not solve my Android or iOS problem, but I can continue using a conventional VPN until I find a similarly elegant solution for those devices.

Questions or comments?

As a paid subscriber, you can comment and “like” my posts. Just click the “Like and Comment” button below.

my shorter content on the fediverse: https://the.mayhem.academy/@jdw