Stop Writing VPC Resources by Hand in 2026
I still see people writing raw aws_vpc, aws_subnet, and aws_route_table resources in 2026. Each environment gets a copy-paste with different CIDR blocks. This was barely acceptable in 2020. Now? It’s asking for trouble.
Last month our team inherited a project with 800+ lines of Terraform just for the VPC. Want to add a new NAT gateway? You had to manually edit three files and pray you didn’t miswire a route table. Someone did. Production subnet routed traffic to the wrong NAT gateway at 3 AM. I got the call.
So this isn’t “how to create a VPC with Terraform.” This is how to build a production-grade VPC in 2026 without shooting yourself in the foot.
The 2026 Answer: Use the Community Module
If you’re still writing aws_vpc resources by hand, stop. The terraform-aws-modules/vpc/aws module has been battle-tested for over 5 years. The community has already fixed the edge cases you haven’t hit yet.
module "vpc" {
source = "terraform-aws-modules/vpc/aws"
version = "~> 5.0"
name = "production-vpc"
cidr = "10.0.0.0/16"
azs = ["us-east-1a", "us-east-1b", "us-east-1c"]
private_subnets = ["10.0.1.0/24", "10.0.2.0/24", "10.0.3.0/24"]
public_subnets = ["10.0.101.0/24", "10.0.102.0/24", "10.0.103.0/24"]
enable_nat_gateway = true
single_nat_gateway = false
}
30 lines of config replaces 150+ lines of raw resources. One VPC, six subnets, three NAT gateways, three route tables, an Internet Gateway, and all the associations.
NAT Gateway Choices: Don’t Cheap Out
The module supports three NAT gateway modes. Here’s what I learned the hard way:
| Mode | Config | Monthly Cost | Reliability | Use Case |
|---|---|---|---|---|
| Single NAT | single_nat_gateway = true | ~$35 | ⚠️ Single point of failure | Dev/Test |
| Per-AZ | one_nat_gateway_per_az = true | ~$105 | ✅ High availability | Production |
| Zero NAT | enable_nat_gateway = false | $0 | ❌ No outbound from private | Internal only |
We ran single NAT on staging. That AZ went down. Our entire staging environment lost outbound connectivity for two hours. CI/CD pipeline stalled. The extra $70/month for per-AZ NAT gateways is cheaper than your weekend.
2026’s New Normal: Zero Trust VPC Access
A recent Reddit thread caught my eye — someone documented a full Zero Trust setup for AWS private VPC access using Cloudflare WARP + Tunnel. This is where things are heading in 2026. VPNs are dying.
Traditional OpenVPN or WireGuard setups require managing client certificates, IP allocation, and route pushing. Change your VPC CIDR? Every client needs a config update. And security-wise, one leaked private key gives attackers a highway into your network.
The Cloudflare approach: WARP client on every device, cloudflared tunnel deployed inside the VPC (ECS Fargate works great), split tunnels configured for VPC CIDR ranges, and Gateway policies tied to IdP groups.
# cloudflared config.yaml
tunnel: your-tunnel-id
credentials-file: /etc/cloudflared/credentials.json
ingress:
- hostname: "*.internal.example.com"
service: https://10.0.1.100:443
- hostname: "db.internal.example.com"
service: tcp://10.0.2.50:5432
- service: http_status:404
The killer feature: zero inbound ports. cloudflared only makes outbound connections to Cloudflare’s edge. Your VPC security groups don’t need any inbound SSH or VPN ports. Attackers can’t even scan your VPC entry points.
Don’t Forget State Management
Here’s another common faceplant. You build the VPC, but where’s the Terraform state? On your laptop?
No. 2026. Remote backend with S3 + DynamoDB locking. No exceptions.
terraform {
backend "s3" {
bucket = "my-org-terraform-state"
key = "network/vpc/terraform.tfstate"
region = "us-east-1"
dynamodb_table = "terraform-state-lock"
encrypt = true
}
}
That DynamoDB lock table prevents two people from running terraform apply simultaneously and corrupting the state. I’ve seen teams skip this. Two engineers applied at the same time. The state file got corrupted. Terraform forgot which resources it created. Infrastructure amnesia.
Best Practices Cheat Sheet
| Practice | Recommended | Don’t Do This |
|---|---|---|
| VPC creation | Community module v5.x | Raw resources |
| Subnet planning | Public + private per AZ | Single AZ |
| NAT gateways | Per-AZ for production | Single NAT to save money |
| Network ingress | Cloudflare Tunnel / Zero Trust | Open SSH ports |
| State storage | S3 + DynamoDB lock | Local files |
| Module version | Pin ~> 5.0 | Use latest |
| Tagging | Module tags parameter | Tag resources manually |
FAQ
Why use Terraform modules instead of writing resources manually?
Modules encapsulate best practices and edge cases. The VPC module automatically handles route table associations, subnet CIDR calculations, and NAT gateway dependencies. Manual resources easily miss a route entry or get dependency ordering wrong.
Is single NAT gateway incompatible with production?
Compatible but risky. A single NAT gateway lives in one AZ. If that AZ fails, all private subnet outbound traffic dies. Production should use per-AZ NAT gateways or NAT instances with auto-recovery.
How does Cloudflare Tunnel compare to traditional VPN?
Zero inbound ports, granular access control, IdP integration, no client certificate management. The downside is dependency on Cloudflare’s network and limited non-HTTP protocol support (TCP tunneling works, UDP doesn’t).
Why is Terraform state locking necessary?
Prevents concurrent operations from corrupting the state file. Without locking, two simultaneous terraform apply runs will have the last write overwrite the first, causing resource state inconsistency.
What’s new in VPC design for 2026?
IPv6 dual-stack support is more mature. VPC Lattice is gaining traction for service mesh. Zero Trust network access (Cloudflare Tunnel, AWS PrivateLink + Client VPN) is replacing traditional VPN solutions.
✅ All agents reported back! ├─ 🟠 Reddit: 12 threads └─ 🗣️ Top voices: r/aws, r/Empulse, r/CloudFlare
References & Community Insights
The following authoritative resources were referenced for architectural best practices and specifications: