Awesome Open Source
Awesome Open Source

Passy's Raspberry PI VPN Router

I've got myself a Raspberry Pi 3 and want to use it as my home router and VPN gateway. At some point, I'll probably accidentally step on it or pour a flat white on it and then wonder how I set it up to do what it's supposed to do.

To avoid this, here are some notes and scripts to make it less painful when that happens. Don't confuse this with a tutorial. I'm writing this first and foremost for myself. However, if you have any suggestions, feel free to send PRs my way.


Have a WiFi access point that I can connect my phone and ChromeCast to and transparently get routed through an OpenVPN.

To set up the other side of this, I can whole-heartedly recommend the docker-openvpn suite which makes the server-side setup a breeze.


It's working!

You get a WiFi hotspot that tunnels all requests through tun0 which is backed by an OpenVPN connection. I'm not sure if this is stable enough for use and there's no good way from the outside to enable/disable VPNs.

Preparing the SD Card

  • Get Raspbian Jessie Lite. I used 2016-03-18 for this. Also, don't be a jerk, and use the Torrent option.
  • I use Lite because I don't even want to connect a monitor to the Pi and updating Xorg takes ages.
  • Copy it onto an SD card. I'll leave it to you to figure out which device you're writing to, but keep in mind that this image is intended to partition the entire card, so don't specify a partition (i.e. sdb not sdb1): dd bs=4M if=2016-03-18-raspbian-jessie.img of=/dev/sdb
  • Follow this guide to get SSH enabled on first boot. TL;DR: touch /media/$USER/boot/ssh

Initial setup

  • Plug the Pi in and connect it to a DHCP-enabled router via ethernet.
  • My old DD-WRT had the .lan domain, so I could directly connect to raspberrypi.lan. Obviously, take care of conflicts if you have more than one. nmap is your friend.
  • ssh [email protected], password is raspberry.
  • This could potentially be part of the ansible script, but I prefer pushing the SSH key over manually to minimize the chance of locking myself out.
  • ssh [email protected] "mkdir -p ~/.ssh/"; scp ~/.ssh/ [email protected]:/home/pi/.ssh/authorized_keys
  • Dont forget this one: Resize your partition or you're gonna have a bad time. Raspbian only leaves you with a few hundred megabytes left, so run sudo raspi-config and select option 1: "Expand Filesystem".


Copy playbook.yml.example to playbook.yml and make the necessary adjustments, notably add your credentials to it. Afterwards, you can run it like:

ansible-playbook -i hosts playbook.yml

This assumes that the hostname in hosts can be resolved and you can log in password-less via the pi user. It also expects the Pi to already have a working internet connection.

Using the WiFi

Everything should automatically start up, but Linux boxes are painfully stateful so if the VPN or something else didn't come up, just reboot that thing.

Afterwards, you should be able to connect to the device via WiFi. The defaults are SSID "passy-pi" and password "raspberrypi". Afterwards, your connected device should be transparently routed through the VPN. Sorry, Netflix.

I now have a second ChromeCast that only connects to this AP and hence thinks it's in whatever country I tell it to. Neat.

Testing the Router manually

In case something is wrong with the WiFi and you just want to verify if the routing works, you can add a route manually.

On your target device, assuming it's IPv4:

# Figure out your current default route:
$ route -n | grep
# Delete the default GW
$ route del default gw <ip_address_from_above>
# Add the new route to the Pi
$ route add default gw <pi_ip_addr>

Updating parts of the config

Something I only found out about when working on this that I should have really known before is that you can selectively run ansible tasks by specifying tags.

If you, for instance, change your VPN settings but don't want to also run an apt-get upgrade you can use the openvpn tag like so:

ansible-playbook -i hosts playbook.yml --tags openvpn

Multiple tags can be comma-separated.

DNS Rerouting

Certain movie streaming services has gotten a lot more aggressive lately and not only block the usual suspects, but entire fucking IP ranges (both IPv4 and IPv6) for hosting providers like DigitalOcean, AWS and Linode. I wish they had done this a couple of weeks earlier so I could have avoided all the previous work.

But anyway, one so far unaddressed attack vector is using a custom DNS. This even comes with a bunch of benefits like better performance and no traffic limits. And all it takes is a couple of iptables rules to rewrite all DNS requests to those custom servers.

I'm currently testing ViperDNS for just that, which even offers a 7 day free trial.

In order to prepare your Pi for the service, you need to change your playbook.yml ever so slightly. You can either leave the openvpn part out entirely if you've never provisioned your device before or (damn you statefulness) make sure to set openvpn.autostart to none to avoid unnecessarily spinning up instances. Be aware that an empty string here means running daemons for all *.conf files in /etc/openvpn/.

Check out playbook.yml.dnsexample for an example. The interesting bits here are firewall.mode: "dns" rather than "tunnel" which is the default and the force_dns: "" which overrides all incoming DNS requests (or anything really talking to port 53) to the given IP address.

Afterwards, just replay the playbook and reboot the device.

If you've updated just the DNS redirect and want to skip the other tasks, the tag you want to use is firewall, i.e.

ansible-playbook -i hosts playbook.yml --tags firewall

Alternative Project Comparisons
Related Awesome Lists
Top Programming Languages
Top Projects

Get A Weekly Email With Trending Projects For These Topics
No Spam. Unsubscribe easily at any time.
Shell (173,092
Raspberry Pi (22,371
Raspberry (22,365
Ansible (21,321
Router (13,778
Dns (10,204
Wifi (8,735
Vpn (3,899
Openvpn (1,828