I originally created this project to solve a complex engineering problem: how to deploy a hardened, hybrid VPN (modern WireGuardĀ® for users, classic IPsec for partners) on GCP, all managed as code. It’s got a load balancer, health checks, a cost-saving scheduler, and zero secrets in git. It’s built for production.
You can read the original, more corporate-focused article here.
But then I realized… a secure, high-performance VPN with a deploy-anywhere-in-the-world capability, managed by Terraform, is also the perfect tool for solving common “power user” problems.
Forget the slow, blacklisted servers of commercial VPNs. When you control the metal (or in this case, the VM), you control everything.
In this tutorial, I’ll walk you through how to deploy my terraform-gcp-vpn project. I’ll cover the core setup, and then I’ll show you how to leverage this “enterprise-grade” stack for two of the most popular VPN use cases: geo-unblocking content and saving money on subscriptions.
š What We’re Building
This isn’t just a single VM running a script. This Terraform setup deploys a complete, resilient architecture:
- Firezone (WireGuard): A fantastic open-source UI and management portal for WireGuard. This is for your personal devices (phone, laptop).
- strongSwan (IPsec): (Optional) The classic, battle-tested IPsec server for site-to-site tunnels. You can probably ignore this for personal use, but it’s there.
- GCP Load Balancer: Provides a stable, static IP and automatic health checks.
- GCP Cloud Scheduler: This is a key component. It automatically starts and stops your VM on a schedule, so you’re not paying for it 24/7.
-
GCP Secret Manager: All credentials (like IPsec PSKs) are stored securely, not in
.tfvarsfiles. - Hardened Security: Follows OpenSSF Scorecard recommendations, uses least-privilege IAM, and has a strict firewall.
ā
Prerequisites
This is a tutorial for a technical audience. You’ll need:
- A GCP Project with billing enabled.
- Terraform v1.9+ installed locally.
- gcloud CLI authenticated (
gcloud auth application-default login). - A Service Account with the necessary roles (e.g.,
roles/compute.instanceAdmin.v1,roles/cloudscheduler.admin). - A domain name (e.g.,
vpn.yourdomain.com) you can point to the new IP.
š ļø The Tutorial: Deploying Your Personal VPN Hub
Step 1: Clone and Configure
First, get the code and create your configuration file.
git clone [https://github.com/dieguezz/terraform-gcp-vpn.git](https://github.com/dieguezz/terraform-gcp-vpn.git)
cd terraform-gcp-vpn
cp terraform.tfvars.example terraform.tfvars
Now, open terraform.tfvars in your editor. This is where the magic happens. Let’s look at the key variables.
# terraform.tfvars
project_id = "your-gcp-project-id"
region = "us-central1"
zone = "us-central1-a"
# --- Network ---
network_name = "vpn-network"
subnet_name = "vpn-subnet"
subnet_cidr = "10.128.0.0/20"
# --- Firezone ---
firezone_hostname = "vpn.yourdomain.com"
# ... other firezone vars like admin email
# --- Scheduling ---
enable_scheduling = true
start_schedule = "0 6 * * 1-5" # 6am Mon-Fri
stop_schedule = "0 23 * * 1-5" # 11pm Mon-Fri
timezone = "America/New_York"
Step 2: The “Hacks” Are Just Variables
This is where this project gets powerful.
š For Geo-Unblocking (e.g., US Netflix)
Commercial VPNs get their IPs blocked by streaming services constantly. Your personal, fresh IP from GCP? Much less likely.
Want to access the US Netflix or Hulu library? Just set your region to a US-based one:
region = "us-central1" # or us-east1, us-west1, etc.
zone = "us-central1-a"
Want to access BBC iPlayer?
region = "europe-west2" # London
zone = "europe-west2-a"
You get the idea. You can deploy your VPN endpoint anywhere GCP has a presence.
š For Subscription Savings (e.g., YouTube Premium)
Services like YouTube Premium or Spotify often have different pricing based on your country. (Disclaimer: This may be against their ToS, so proceed at your own risk).
Want to see if you can get a better price from another country? Just deploy your VPN there. For example, some users report savings by connecting from regions in South America or Asia.
The power of Terraform means you can terraform destroy this instance and spin one up in us-central1 30 seconds later. You have a global fleet of personal VPNs at your fingertips.
š For Saving Money (The Scheduler)
A production-grade setup like this isn’t free (see cost breakdown below). The e2-medium instance and the Load Balancer are the main costs.
But do you really need your streaming VPN running at 3 AM on a Tuesday?
By setting enable_scheduling = true, you can configure the VM to only run when you’ll actually use it. For example, to only run it on evenings and weekends:
enable_scheduling = true
start_schedule = "0 18 * * 1-5" # 6 PM on Weekdays
stop_schedule = "0 23 * * 1-5" # 11 PM on Weekdays
# Note: You'd need more rules for weekends, or just run it manually.
timezone = "Europe/Madrid"
This single variable can cut your VM costs by 50-80%, turning an expensive setup into something that’s a few bucks a month.
Or, my favorite method:
enable_scheduling = false
…and I just manually run terraform apply when I want to stream, and terraform destroy when I’m done. The entire deployment takes about 5 minutes.
Step 3: Deploy!
Once your terraform.tfvars file is saved, the rest is standard Terraform.
# Initialize the modules
terraform init
# See what's about to be built
terraform plan
# Deploy the infrastructure
terraform apply
Type yes when prompted. Go grab a coffee. In about 5 minutes, Terraform will finish and spit out the outputs.
Outputs:
firezone_url = "[https://vpn.yourdomain.com](https://vpn.yourdomain.com)"
load_balancer_ip = "35.xxx.xxx.xxx"
vpn_instance_name = "firezone-vpn-instance"
Step 4: Access Your VPN Hub
-
Point Your DNS: Go to your DNS provider and create an A record for vpn.yourdomain.com (or whatever you set as firezone_hostname) pointing to the load_balancer_ip.
-
Wait: Give Firezone 2-3 minutes to initialize on the first boot. You can check the logs with gcloud compute instances get-serial-port-output firezone-vpn-instance.
-
Login: Open https://vpn.yourdomain.com in your browser.
-
Enroll Devices: Use the Firezone UI to add your users (just you, probably) and enroll your devices. You can download the WireGuard config or scan a QR code with the mobile app.
That’s it. You are now connected to the internet through your own private, secure, high-speed server.
š A Note on Security and Privacy
The #1 reason to do this is privacy.
Zero Logs: Is your commercial VPN really “zero-log”? You have to trust them. Here, you own the server. You know there are no logs because you’d have to be the one to set them up.
Hardened: This deployment follows OpenSSF Scorecard recommendations. No secrets in code, pinned dependencies, encrypted boot disk, and least-privilege IAM.
Public Wi-Fi: Using this on a coffee shop or airport Wi-Fi means your traffic is encrypted inside a WireGuard tunnel to your server. No one on the local network can snoop on you.
Conclusion
Building your own VPN used to be a pain. With tools like Terraform and Firezone, it’s now a 5-minute process.
While I built this repo for corporate use, its real power comes from its flexibility. You get an enterprise-grade stack that you can use to stream Netflix, save money on YouTube, or simply secure your traffic at a coffee shopāall with a few changes to a .tfvars file.
You’re a developer. Stop renting your infrastructure. Own it.
If this helped you, I’d appreciate a ā on the GitHub repo!
GitHub Repo: dieguezz/terraform-gcp-vpn
