Sep 17, 2024
Sep 17, 2024
Whether you’re migrating from on-premises to the cloud or deploying services inside your customers’ networks, you’ll quickly hit the same question: how do you get two systems talking securely without routing traffic through the public internet?
AWS gives you three native answers — PrivateLink, VPC peering, and VPC Lattice — and ngrok offers a fourth that works differently from all of them. Each solves a real problem. Each has real costs. Here’s how to tell them apart.
PrivateLink establishes private connections between VPCs, AWS services, and on-premises networks by provisioning Interface VPC Endpoints — elastic network interfaces with private IP addresses — inside the consumer’s VPC. Traffic flows through AWS’s backbone without touching the public internet.
The primary use case is private access to a specific application or service, particularly where compliance or security requirements rule out public exposure. A financial institution accessing a banking application, or a team sharing a central database across development, staging, and production VPCs, are classic fits. It also works for hybrid setups: connect an on-premises ERP system to an AWS service via PrivateLink and they behave as though colocated.
What works well: traffic never leaves AWS, high availability across multiple Availability Zones, shareable across accounts, no CIDR overlap constraints. TCP and UDP are both supported — UDP via dual-stack NLBs. Up to 100 VPC endpoints per VPC by default, scaling to as many as you need via support.
What doesn’t: the NLB requirement is the most common friction point — PrivateLink only supports NLBs (not ALBs) as the endpoint service frontend, so if your service runs behind an ALB you need an NLB in front of it. There’s no service discovery; consumers need the endpoint DNS name and must request access per service. Cost layers accumulate quickly: per-AZ ENI-hour, NLB usage, and per-GB data processing all run simultaneously. And the endpoint MTU is capped at 8,500 bytes with no Path MTU Discovery, which can silently drop oversized packets.
1AWS PrivateLink2────────────────3 Consumer VPC Producer VPC4 ┌──────────────┐ ┌──────────────┐5 │ │ │ │6 │ EC2 │ │ Service │7 │ │ │ │ │ │8 │ ENI ◄──────────────────── NLB │9 │ (local IP) │ │ │10 └──────────────┘ └──────────────┘11 Consumer sees a local IP only — no network adjacency to the producer VPC.12 Traffic stays on the AWS backbone. NLB handles load balancing on the producer side.VPC peering creates a direct link between two VPCs so they communicate as if they’re on the same network, using private IPv4 or IPv6 addresses with no internet gateway or VPN required. AWS updates route tables on both sides automatically. You get TCP, UDP, and ICMP support, cross-region capability, and no bandwidth limits — and intra-AZ traffic within the same region is free.
What works well: low cost with no data-processing fees, no bandwidth limits, security group referencing across peered VPCs.
What doesn’t: peering is strictly point-to-point. If VPC A peers with B and C, traffic can’t flow from B to C through A — no transitive routing. Connecting N VPCs in a full mesh requires N(N−1)/2 connections: 10 for 5 VPCs, 45 for 10. The default limit is 50 active peering connections per VPC, with a hard maximum of 125. CIDR overlap between any two VPCs blocks you entirely.
Transit Gateway is the fix for the scale problem. Attach each VPC to a central hub — up to 5,000 VPCs — and the gateway handles routing between all of them, including VPNs and Direct Connect. Cost: $0.05/hr per VPC attachment (~$36.50/month) plus $0.02/GB processed. For five or more VPCs it’s usually worth it; for two or three, peering is simpler and cheaper.
1VPC peering (point-to-point mesh) Transit Gateway (hub-and-spoke)2────────────────────────────────── ────────────────────────────────3 ┌───────┐ ┌───────┐ ┌───────┐ ┌───────┐ ┌───────┐4 │ VPC A │─────│ VPC B │ │ VPC A │ │ VPC B │ │ VPC C │5 └───┬───┘ └───┬───┘ └───┬───┘ └───┬───┘ └───┬───┘6 │ │ └──────────┼──────────┘7 └────┬────────┘ ┌────┴────┐8 ┌─┴─────┐ │Transit │──── VPN/DX9 │ VPC C │ │Gateway │10 └───────┘ └─────────┘11 3 VPCs = 3 connections. One attachment per VPC.12 5 VPCs = 10. No transitive routing. Centralized routing. Still L3.VPC Lattice went GA in mid-2023 and is the option AWS is pushing hardest today. It operates at Layer 7, above the network layer, and introduces a managed service-connectivity plane: register services into a service network, associate your VPCs to that network, and any VPC can reach any service — across accounts, without per-pair configuration.
Unlike PrivateLink and peering, Lattice handles service discovery automatically, enforces IAM-based authorization at the service level, and provides built-in access logging. It natively supports overlapping CIDRs. Because it’s L7, it supports path-based routing, weighted traffic splitting for canary deployments, and request-level auth policies that PrivateLink and peering simply can’t do.
One deadline worth flagging: AWS App Mesh reaches end-of-life on September 30, 2026. VPC Lattice is its replacement — if you’re on App Mesh, plan your migration now.
Where it gets complicated: a VPC can only be associated with one service network, which limits certain “shared services with network isolation” patterns. Cross-region requires combining Lattice with cross-region PrivateLink interface endpoints. Lattice is designed for AWS workloads — multi-cloud or on-premises connectivity requires additional tooling. And while Lattice added TCP resource support for databases and IP targets, the data plane is HTTP/HTTPS/gRPC/TLS; raw arbitrary TCP protocols go through a resource gateway, not native Lattice routing.
Pricing: $0.025/hr per provisioned service (~$18.25/month each), plus $0.025/GB and $0.10 per million HTTP requests (first 200k/hr free).
1VPC Lattice (service network)2──────────────────────────────3 ┌───────┐ ┌───────┐ ┌───────┐4 │ VPC A │ │ VPC B │ │ VPC C │5 └───┬───┘ └───┬───┘ └───┬───┘6 └───────────┼───────────┘7 ┌──────┴──────┐8 │ Service │──── Service A (EC2/ECS/Lambda)9 │ Network │──── Service B10 └─────────────┘──── Service C11 L7 routing, IAM auth, service discovery — no per-pair config.12 HTTP/HTTPS/gRPC/TLS only.AWS-native options get cheaper per-GB at high volume. ngrok’s data transfer rate is higher ($0.10/GB) but its setup cost is near-zero.
ngrok takes a different approach from all three AWS options. Rather than connecting networks or provisioning endpoints inside VPCs, it splits the problem into two pieces: a lightweight agent that runs inside your private network and makes an outbound TLS connection to ngrok’s cloud, and a cloud endpoint that sits in front and controls what traffic is allowed through.
The agent-side config is minimal — it registers the internal service with a .internal hostname that isn’t publicly addressable:
1# ngrok.yaml — runs inside the private network2version: 33agent:4 authtoken: <YOUR_AUTHTOKEN>5 6endpoints:7 - name: payments-api8 url: https://payments.internal9 upstream:10 url: http://10.0.1.45:8080The cloud endpoint is where access control lives. Its Traffic Policy decides who can reach the internal service, then forwards matching traffic through:
1# Cloud endpoint Traffic Policy — configured in the ngrok dashboard2on_http_request:3 - name: RestrictAndForward4 actions:5 - type: restrict-ips6 config:7 enforce: true8 allow:9 - "10.0.0.0/8"10 - type: forward-internal11 config:12 url: https://payments.internalNothing in the private network changes — no inbound firewall rules, no route table updates, no NLB to provision. The agent initiates the connection outbound, so it works through NAT, across clouds, and from on-premises without any network reconfiguration on either side. Traffic Policy runs at the cloud endpoint and can layer on JWT validation, rate limiting, or header-based routing without touching application code.
1ngrok: cloud endpoint + internal endpoint2──────────────────────────────────────────3 ngrok cloud4 ┌─────────────────────┐5 │ Cloud endpoint │6 client ────────────────────────► │ (payments.ngrok.app)│7 │ │ │8 │ Traffic Policy │9 │ restrict-ips ✓ │10 │ forward-internal ──────────────┐11 └─────────────────────┘ │12 │ (persistent13 Private network / any cloud │ outbound TLS)14 ┌──────────────────────────────────┐ │15 │ Service ngrok agent ◄──────────────────────────────────┘16 │ (10.0.1.45:8080) │ │17 │ ▲ │ │18 │ └───────────────┘ │19 │ payments.internal │20 └──────────────────────────────────┘21 No inbound rules. No route table changes. No NLB.This is the pattern behind ngrok’s site-to-site connectivity model, and the closest analog to PrivateLink’s service-level isolation — consumers can only reach the specific service exposed through the cloud endpoint, not anything else in the network behind the agent. The difference is that it works whether that network is an AWS VPC, an Azure VNET, a customer’s on-premises data center, or a Raspberry Pi behind a home router.
ngrok isn’t the right fit for every situation, and it’s worth being direct about that. If you’re moving terabytes of east-west traffic between VPCs in the same region, PrivateLink or VPC Lattice will be cheaper per-GB and keep traffic on the AWS backbone. If your compliance requirements prohibit traffic transiting an external network path, native AWS options are the safer choice.
Where ngrok consistently wins: connecting infrastructure that lives outside AWS, reaching into customer networks without requiring them to configure anything, and replacing permanent AWS infrastructure with something you can spin up in minutes and pay for only while you use it. The pay-as-you-go model means you’re not carrying the cost of idle endpoints or over-provisioned NLBs — you pay for what you actually use.
For teams that need both — high-volume internal traffic and flexible external connectivity — the pattern that works well is keeping heavy east-west traffic on PrivateLink or Lattice, and routing edge connectivity (on-prem systems, third-party integrations, developer access) through ngrok.
Use VPC peering for two or three VPCs with non-overlapping CIDRs and no expectation of significant growth.
Add Transit Gateway when you have more than roughly five VPCs, need hub-and-spoke routing, or want to bridge VPNs or Direct Connect.
Use PrivateLink when you need strict service-level network isolation, have overlapping CIDRs, or are exposing a service to external customers or partners.
Use VPC Lattice when you’re building a microservice architecture on AWS, want L7 routing and IAM auth built in, or are migrating off App Mesh before September 2026.
Use ngrok when your services aren’t all in AWS, you need cross-cloud or on-prem connectivity without a VPN, or you want Traffic Policy without running a separate load balancer.
Choosing the right connectivity solution is genuinely hard — the options have changed a lot, and the right answer depends on where your services actually live.
AWS PrivateLink gives you airtight service-level isolation but bills you for the privilege at every layer. VPC peering is cheap and simple until it isn’t, at which point you’re staring down a mesh of route tables. Transit Gateway tames the mesh but adds its own cost and operational surface. VPC Lattice is the most capable native option, but it’s L7-only and cross-region still requires workarounds.
ngrok sidesteps all of that. One agent, running wherever your service lives, gives you private connectivity across clouds, accounts, and networks — without touching a route table, provisioning an NLB, or filing a ticket to update security groups. Traffic Policy handles auth, rate limiting, and routing in the same config. And because ngrok is pay-as-you-go, you’re not carrying the cost of infrastructure you provisioned six months ago for a use case that changed.
Create a free ngrok account and have your first endpoint running in minutes with the quickstart. If you’re evaluating ngrok for a production migration or want to talk through your architecture, join ngrok’s monthly Office Hours — live sessions with the DevRel and Product teams where you can see real patterns in action and get your questions answered. Find the next session at ngrok.com/resources/office-hours.