In this article, VPN (Virtual Private Network) refers to an encrypted point-to-point link that reroutes all of your Internet traffic, making it appear to come from a computer other than your own. Why would you want to do this? There are several reasons, the main one being to empower you "to choose" your ISP (Internet Service Provider).
Not that long ago, there were an estimated 7,000 ISPs in the United States and specialized review sites that helped consumers choose between them. If you wanted to chose an ISP that respected your privacy, the free market would effectively let you do that. Today that choice is gone.
Now the best you can do is to choose a "remote" ISP that meets your needs and tunnel your traffic to it through a VPN.
This article offers an opinionated, do-almost-everything-for-you script to set up a personal VPN. It assumes you're using macOS, DigitalOcean and IPv4.
This section enumerates some of the threats from which a VPN can protect you. They are only theoretical possibilities and may not actually be occurring.
Your ISP may be Altering Your Traffic
In 2007, Comcast [the second largest Internet Service Provider (ISP) in the United States] installed new software or equipment on its networks that began selectively interfering with ... TCP/IP connections.
Now that we lost network neutrality in 2018 I expect a lot more of this to happen.
Your Online Behavior may be Sold
In 2017, the United States' House of Representatives passed a resolution of disapproval to overturn the Broadband Consumer Privacy Proposal privacy law by the Federal Communications Commission (FCC). Internet Service Providers can now sell your browsing habits, app usage history, location data and Social Security numbers directly to marketers, financial firms and other companies that mine personal data without your consent.
Your DNS may be Spoofed
... vulnerabilities in the DNS were discovered that allow an attacker to hijack this process of looking some one up or looking a site up on the Internet using their name. The purpose of the attack is to take control of the session to, for example, send the user to the hijacker's own deceptive web site for account and password collection.
These vulnerabilities have increased interest in introducing a technology called DNS Security Extensions (DNSSEC) to secure this part of the Internet's infrastructure.
DNSSEC was supposed to save us, however:
The short answer is: pretty much everyone uses normal DNS, because the many show-stopping problems with DNSSEC includes the insane design decision not to protect the "last mile" between the stub resolver on your own machine and the "DNS server" (technically: recursive cache) that DHCP configures.
If you're using Google's DNS, it will (pretty much pointlessly) validate DNSSEC records for you --- but the link between your computer and Google's DNS servers are completely unprotected (any attacker could simply trick your browser into believing there was no such thing as DNSSEC).
This doesn't much matter because only a tiny, tiny fraction of all DNS records are DNSSEC-signed. The modal experience for companies that do take the trouble to sign their DNS records is "taken offline completely by DNSSEC configuration mistakes". There is virtually no upside to participating.
A VPN doesn't solve the problem (try DNS-over-TLS for that) but it lessens the risk.
Your Identity/Behavior may be Correlated with Your Location
If any of your Internet traffic can identify who you are, and your physical location can be inferred by your IP address and/or the owner of the wifi hotspot you're using, then the two can be correlated.
Classified documents published by Der Spiegel indicate the NSA is passively decrypting IPsec connections at significant scale, so that's out.
OpenVPN isn't as vulnerable to the weakness that's conjectured to be exploited by the NSA but it relies on OpenSSL (which doesn't have a good track record), has an enormous attack surface, and is slow.
WireGuard is a modern VPN with a relatively tiny attack surface that uses state-of-the-art cryptography and is fast. Its website reads, "It is currently under heavy development, but already it might be regarded as the most secure, easiest to use, and simplest VPN solution in the industry", a credible claim. It also comes with the warning, "WireGuard is not yet complete. You should not rely on this code. It has not undergone proper degrees of security auditing and the protocol is still subject to change" but I think it's already good enough for a personal VPN.
It's being considered for inclusion in the Linux kernel and here's what Linus Torvalds has to say about it:
Can I just once again state my love for it and hope it gets merged soon? Maybe the code isn't perfect, but I've skimmed it, and compared to the horrors that are OpenVPN and IPSec, it's a work of art.
The fewer lines of code, the better.
|Software||Lines of Code|
|IPSec (XFRM + StrongSwan)||400,000|
|OpenVPN (including OpenSSL)||600,000|
I wrote a simple monitoring tool that displays a colored circle in the menu bar to indicate whether or not the VPN is working. It functions by sending a request to Ipify once every hour to get your external IP address and to make sure it's the right one.
March 8, 2017
We have not ever, nor will we ever, sell customer information to anyone, anywhere, anytime.
Nor has this ever been considered or brought up by anyone at DigitalOcean. Ever.
Create the Droplet
- Create a droplet.
Ubuntu 18.04 x64.
- Choose the least expensive size.
- Choose the datacenter region closest to you.
- Select the
Enter the following where it reads
Enter user data here... to prevent a Man-in-the-Middle attack:
#!/bin/sh ssh-keygen -f /etc/ssh/ssh_host_ed25519_key.pub -l -v >> /etc/issue
Add your SSH key, give it a hostname like
vpn if you like, and click
Open Terminal and set the
ipv4 variable to the correct address for the droplet, e.g.,
$ export ipv4=192.0.2.1
Show the Fingerprint
This will come in useful later.
- Click the ellipsis menu to the right of the droplet name.
- Keep the console window open so that you can refer to it later.
First install Homebrew to make it easier to install various tools.
Create a directory on your Mac for this project.
$ mkdir ~/Documents/vpn $ cd ~/Documents/vpn
Rather than explain how you to do each one of the steps, I've put them all into a shell script for simplicity. Please scrutinize the script, make sure you understand what it's doing, and feel free to make changes to it or to perform each step manually.
Create a file named
setup.sh with the following contents:
#!/bin/sh if [ -z $ipv4 ]; then echo Please set the ipv4 variable like this first: export ipv4=192.0.2.1 exit 1 fi echo Using IP address $ipv4. set -o errexit set -o verbose ListenPort=51820 # Check the VPN status every hour. StartInterval=3600 # Install various tools we'll need (Git, Node.js, WireGuard, and Yarn). brew install git node wireguard-tools yarn # Generate cryptographic keys. PresharedKey=$(wg genpsk) clientPrivateKey=$(wg genkey) clientPublicKey=$(echo $clientPrivateKey | wg pubkey) serverPrivateKey=$(wg genkey) serverPublicKey=$(echo $serverPrivateKey | wg pubkey) # Create the client configuration file. cat > utun.conf << EOF [Interface] Address = 10.0.0.2/32 DNS = 18.104.22.168 PrivateKey = $clientPrivateKey [Peer] AllowedIPs = 0.0.0.0/0 Endpoint = $ipv4:$ListenPort PresharedKey = $PresharedKey PublicKey = $serverPublicKey EOF chmod go= utun.conf # Confirm that the key fingerprint matches the one in the DigitalOcean console # before proceeding. set +o verbose ssh [email protected]$ipv4 -o HostKeyAlgorithms=ssh-ed25519 -o VisualHostKey=yes << EOSSH set -o verbose # Configure the droplet. # Install WireGuard. # https://www.wireguard.com/install/ add-apt-repository ppa:wireguard/wireguard apt-get update apt-get install --yes wireguard # Set up the firewall. sed --in-place 's/#net\/ipv4\/ip_forward=1/net\/ipv4\/ip_forward=1/' /etc/ufw/sysctl.conf sysctl --write net.ipv4.ip_forward=1 ufw allow ssh ufw allow $ListenPort/udp ufw --force enable cd /etc/wireguard/ # Create the configuration file. cat > wg0.conf << "EOF" [Interface] Address = 10.0.0.1/32 ListenPort = $ListenPort PostUp = iptables --append FORWARD --in-interface wg0 --jump ACCEPT PostDown = iptables --delete FORWARD --in-interface wg0 --jump ACCEPT PostUp = iptables --table nat --append POSTROUTING --out-interface eth0 --jump MASQUERADE PostDown = iptables --table nat --delete POSTROUTING --out-interface eth0 --jump MASQUERADE PrivateKey = $serverPrivateKey [Peer] AllowedIPs = 10.0.0.0/24 PresharedKey = $PresharedKey PublicKey = $clientPublicKey EOF chmod go= wg0.conf # Tell WireGuard to start on boot. systemctl enable [email protected] # Bring up the VPN interface. wg-quick up wg0 EOSSH set -o verbose # Bring up the VPN connection on macOS. You will need to type your password to # allow this. sudo wg-quick up ./utun.conf # Install Homebrew Cask so that it's easy to install AnyBar. brew tap caskroom/cask # Install and start AnyBar. brew cask install anybar /Applications/AnyBar.app/Contents/MacOS/AnyBar & # Download my simple monitoring tool. git clone https://gitlab.com/NodeGuy/vpn-monitor (cd vpn-monitor; yarn install) # Tell macOS to launch the monitoring tool at login. cat > ~/Library/LaunchAgents/vpn.status.plist << EOF <?xml version="1.0" encoding="UTF-8"?> <!DOCTYPE plist PUBLIC "-//Apple Computer//DTD PLIST 1.0//EN" "http://www.apple.com/DTDs/PropertyList-1.0.dtd"> <plist version="1.0"> <dict> <key>Label</key> <string>vpn.status</string> <key>ProcessType</key> <integer>Background</integer> <key>ProgramArguments</key> <array> <string>$(which node)</string> <string>$(pwd)/vpn-monitor/lib/index</string> <string>--expected</string> <string>$ipv4</string> </array> <key>RunAtLoad</key> <true/> <key>StartInterval</key> <integer>$StartInterval</integer> </dict> </plist> EOF chmod go-w ~/Library/LaunchAgents/vpn.status.plist launchctl load ~/Library/LaunchAgents/vpn.status.plist # If all went well then you should see a green circle in your menu bar # indicating success. If something didn't work then please let me know in the # article comments.
Run the script. You will be shown the key fingerprint of the droplet and asked whether you want to continue connecting. Continue only if the fingerprint matches the one in the DigitalOcean console.
$ sh setup.sh
Once everything is set up, you can stop the VPN if you want to with the following command in Terminal:
$ wg-quick down ~/Documents/vpn/utun.conf
To bring it up again:
$ wg-quick up ~/Documents/vpn/utun.conf
I haven't figured out how to get the VPN to come back up automatically after a reboot. Please leave a comment below if you have a suggestion.