{"id":15635726,"url":"https://github.com/passy/raspbian-vpn-router","last_synced_at":"2026-04-01T20:43:27.838Z","repository":{"id":66088566,"uuid":"56445903","full_name":"passy/raspbian-vpn-router","owner":"passy","description":"Setting up a Raspberry Pi 3 as a VPN Gateway","archived":false,"fork":false,"pushed_at":"2019-04-23T20:08:10.000Z","size":30,"stargazers_count":33,"open_issues_count":0,"forks_count":5,"subscribers_count":2,"default_branch":"master","last_synced_at":"2025-10-12T00:44:12.876Z","etag":null,"topics":["ansible","raspberry-pi"],"latest_commit_sha":null,"homepage":"","language":"Shell","has_issues":true,"has_wiki":null,"has_pages":null,"mirror_url":null,"source_name":null,"license":null,"status":null,"scm":"git","pull_requests_enabled":true,"icon_url":"https://github.com/passy.png","metadata":{"files":{"readme":"README.markdown","changelog":null,"contributing":null,"funding":null,"license":null,"code_of_conduct":null,"threat_model":null,"audit":null,"citation":null,"codeowners":null,"security":null,"support":null,"governance":null,"roadmap":null,"authors":null,"dei":null,"publiccode":null,"codemeta":null}},"created_at":"2016-04-17T16:13:22.000Z","updated_at":"2024-11-21T21:57:42.000Z","dependencies_parsed_at":"2023-02-23T06:30:25.265Z","dependency_job_id":null,"html_url":"https://github.com/passy/raspbian-vpn-router","commit_stats":{"total_commits":32,"total_committers":1,"mean_commits":32.0,"dds":0.0,"last_synced_commit":"1c39744c0e414e31aaee4c0087e5f31b6c5fdcc7"},"previous_names":[],"tags_count":0,"template":false,"template_full_name":null,"purl":"pkg:github/passy/raspbian-vpn-router","repository_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repositories/passy%2Fraspbian-vpn-router","tags_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repositories/passy%2Fraspbian-vpn-router/tags","releases_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repositories/passy%2Fraspbian-vpn-router/releases","manifests_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repositories/passy%2Fraspbian-vpn-router/manifests","owner_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/owners/passy","download_url":"https://codeload.github.com/passy/raspbian-vpn-router/tar.gz/refs/heads/master","sbom_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repositories/passy%2Fraspbian-vpn-router/sbom","scorecard":null,"host":{"name":"GitHub","url":"https://github.com","kind":"github","repositories_count":286080680,"owners_count":31291778,"icon_url":"https://github.com/github.png","version":null,"created_at":"2022-05-30T11:31:42.601Z","updated_at":"2026-04-01T13:12:26.723Z","status":"ssl_error","status_checked_at":"2026-04-01T13:12:25.102Z","response_time":53,"last_error":"SSL_read: unexpected eof while reading","robots_txt_status":"success","robots_txt_updated_at":"2025-07-24T06:49:26.215Z","robots_txt_url":"https://github.com/robots.txt","online":false,"can_crawl_api":true,"host_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub","repositories_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repositories","repository_names_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repository_names","owners_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/owners"}},"keywords":["ansible","raspberry-pi"],"created_at":"2024-10-03T11:00:56.617Z","updated_at":"2026-04-01T20:43:27.809Z","avatar_url":"https://github.com/passy.png","language":"Shell","funding_links":[],"categories":[],"sub_categories":[],"readme":"# Passy's Raspberry PI VPN Router\n\n\u003cimg src=\"https://www.raspberrypi.org/wp-content/uploads/2015/08/raspberry-pi-logo.png\" width=150 align=left\u003e\n\nI've got myself a Raspberry Pi 3 and want to use it as my home router and VPN\ngateway.\nAt some point, I'll probably accidentally step on it or pour a flat white on it\nand then wonder how I set it up to do what it's supposed to do.\n\nTo avoid this, here are some notes and scripts to make it less painful when that\nhappens. Don't confuse this with a tutorial. I'm writing this first and foremost\nfor myself. However, if you have any suggestions, feel free to send PRs my way.\n\n## Goal\n\nHave a WiFi access point that I can connect my phone and ChromeCast to and\ntransparently get routed through an OpenVPN.\n\nTo set up the other side of this, I can whole-heartedly recommend\nthe [docker-openvpn](https://github.com/kylemanna/docker-openvpn)\nsuite which makes the server-side setup a breeze.\n\n## Status\n\n**It's working!**\n\nYou get a WiFi hotspot that tunnels all requests through `tun0` which is\nbacked by an OpenVPN connection. I'm not sure if this is stable enough for\nuse and there's no good way from the outside to enable/disable VPNs.\n\n## Preparing the SD Card\n\n- [Get Raspbian Jessie Lite](https://downloads.raspberrypi.org/raspbian_latest.torrent).\n  I used `2016-03-18` for this. Also, don't be a jerk, and use the Torrent\n  option.\n- I use Lite because I don't even want to connect a monitor to the Pi and\n  updating Xorg takes ages.\n- Copy it onto an SD card. I'll leave it to you to figure out which device\n  you're writing to, but keep in mind that this image is intended to partition\n  the entire card, so don't specify a partition (i.e. `sdb` not `sdb1`):\n  `dd bs=4M if=2016-03-18-raspbian-jessie.img of=/dev/sdb`\n- Follow [this guide](https://medium.com/@zw3rk/quick-headless-raspberry-pi-setup-52ad6dd312c4)\n  to get SSH enabled on first boot. TL;DR: `touch /media/$USER/boot/ssh`\n\n## Initial setup\n\n- Plug the Pi in and connect it to a DHCP-enabled router via ethernet.\n- My old DD-WRT had the `.lan` domain, so I could directly connect to\n  `raspberrypi.lan`. Obviously, take care of conflicts if you have more than\n  one. `nmap` is your friend.\n- `ssh pi@raspberrypi.lan`, password is `raspberry`.\n- This could potentially be part of the ansible script, but I prefer pushing the\n  SSH key over manually to minimize the chance of locking myself out.\n- `ssh pi@raspberrypi.lan \"mkdir -p ~/.ssh/\"; scp ~/.ssh/id_rsa.pub pi@raspberrypi.lan:/home/pi/.ssh/authorized_keys`\n- *Dont forget this one:* Resize your partition or you're gonna have a bad time.\n  Raspbian only leaves you with a few hundred megabytes left, so run\n  `sudo raspi-config` and select option 1: \"Expand Filesystem\".\n\n## Ansible\n\nCopy `playbook.yml.example` to `playbook.yml` and make the necessary adjustments,\nnotably add your premiumize.me credentials to it. Afterwards, you can run it\nlike:\n\n```\nansible-playbook -i hosts playbook.yml\n```\n\nThis assumes that the hostname in `hosts` can be resolved and you can log in\npassword-less via the `pi` user. It also expects the Pi to already have a\nworking internet connection.\n\n## Using the WiFi\n\nEverything should automatically start up, but Linux boxes are painfully\nstateful so if the VPN or something else didn't come up, just reboot that thing.\n\nAfterwards, you should be able to connect to the device via WiFi. The defaults\nare SSID \"passy-pi\" and password \"raspberrypi\". Afterwards, your connected\ndevice should be transparently routed through the VPN. Sorry, Netflix.\n\n\u003cimg src=\"https://i.imgur.com/f5V3BnV.jpg\" width=500\u003e\n\nI now have a second ChromeCast that only connects to this AP and hence thinks\nit's in whatever country I tell it to. Neat.\n\n## Testing the Router manually\n\nIn case something is wrong with the WiFi and you just want to verify if\nthe routing works, you can add a route manually.\n\nOn your target device, assuming it's IPv4:\n\n```\n# Figure out your current default route:\n$ route -n | grep 0.0.0.0\n# Delete the default GW\n$ route del default gw \u003cip_address_from_above\u003e\n# Add the new route to the Pi\n$ route add default gw \u003cpi_ip_addr\u003e\n```\n\n## Updating parts of the config\n\nSomething 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.\n\nIf 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:\n\n```\nansible-playbook -i hosts playbook.yml --tags openvpn\n```\n\nMultiple tags can be comma-separated.\n\n## DNS Rerouting\n\nCertain 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.\n\nBut 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.\n\nI'm currently testing [ViperDNS](https://www.viperdns.com) for just that, which even offers a 7 day free trial.\n\nIn 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/`.\n\nCheck out [`playbook.yml.dnsexample`](./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: \"185.51.194.194\"` which overrides all incoming DNS requests (or anything really talking to port 53) to the given IP address.\n\nAfterwards, just replay the playbook and reboot the device.\n\nIf you've updated just the DNS redirect and want to skip the other tasks, the\ntag you want to use is `firewall`, i.e.\n\n\n```\nansible-playbook -i hosts playbook.yml --tags firewall\n```\n","project_url":"https://awesome.ecosyste.ms/api/v1/projects/github.com%2Fpassy%2Fraspbian-vpn-router","html_url":"https://awesome.ecosyste.ms/projects/github.com%2Fpassy%2Fraspbian-vpn-router","lists_url":"https://awesome.ecosyste.ms/api/v1/projects/github.com%2Fpassy%2Fraspbian-vpn-router/lists"}