I Vibe Coded a VPN to Watch Football
Carabao Cup final. Man City vs Arsenal. I’m in Dubai, streaming matches on my Jio Hotstar subscription from India via ExpressVPN. It’s been a solid setup for years.
This match, though, was on FanCode. And for whatever reason, ExpressVPN just wasn’t working with it. I could’ve signed up for another VPN service, but instead I opened my terminal 😅
I’ve been using Tailscale for a while and knew I could spin up an EC2 instance in an AWS India region, set it up as a Tailscale exit node, and route my traffic through it. A fresh cloud IP from a standard AWS subnet isn’t on any VPN blocklist. It’s just regular cloud traffic.
It worked. I watched the match. But the whole process (launching an instance, installing Tailscale, configuring the exit node, tearing it all down after) was tedious enough that I wouldn’t want to repeat it. So I built Burrow to make the whole thing on-demand and repeatable.
What Burrow does
Burrow is a CLI that deploys self-hosted VPN infrastructure in one command. You pick a cloud provider and region, it provisions a Tailscale exit node there. When you’re done, you tear it down. That’s it.
$ burrow init
✓ Configuration saved. You're ready to deploy!
$ burrow add --region us-east-1
Deploying exit node in aws/us-east-1...
✓ Exit node deployed: aws/us-east-1
$ burrow add --region eu-west-1
Deploying exit node in aws/eu-west-1...
✓ Exit node deployed: aws/eu-west-1
It supports AWS, Hetzner, and GCP. No dashboards, no config files to edit, no cloud console clicking.
How it works
Terraform under the hood. Each burrow add generates and applies a Terraform plan that provisions a VM on your chosen provider (EC2 on AWS, a cloud server on Hetzner, or a Compute Engine instance on GCP), installs Tailscale, and registers it as an exit node on your tailnet. Terraform state is stored locally in ~/.burrow/, so you always own your infrastructure state.
Multi-provider support. AWS is the default, but deploying to Hetzner or GCP is just as easy with --provider hetzner or --provider gcp. Each provider resolves the right image and instance type for the region you pick.
Embedded templates. The Terraform HCL is generated programmatically in TypeScript rather than shipped as separate .tf files. This keeps the compiled binary fully self-contained, no template directory to worry about.
Single binary, zero dependencies. Built with Bun’s --compile flag, Burrow ships as a standalone executable for macOS and Linux. The install script bootstraps everything including Terraform and Tailscale if you don’t have them.
curl -fsSL https://raw.githubusercontent.com/dhruvparmar372/burrow/main/install.sh | sh
When would you use this over a regular VPN?
Commercial VPNs are great for everyday use. They’re convenient, fast, and cover most scenarios. Where self-hosted exit nodes shine is when your regular VPN just isn’t getting through. A fresh VM in the right cloud region gives you a clean IP that isn’t associated with any VPN provider.
The tradeoff is you’re paying cloud rates for the instance time, but for a couple hours of a football match, it’s pennies.
The stack
- TypeScript + Bun for the CLI
- Terraform for infrastructure provisioning
- Tailscale for the VPN mesh
- AWS EC2, Hetzner Cloud, GCP Compute Engine for the exit nodes
- GitHub Actions for automated binary builds on version tags
The entire project is open source: github.com/dhruvparmar372/burrow
Arsenal lost, by the way. But at least I got to watch it.

Stay Humble eh.