Is your AWS bill higher than it should be?Free 32-point self-audit checklist.
Get the checklist

Home/Articles

AWSCost

Your NAT Gateway Is Billing You for Traffic That Should Be Free

By Al Bunch · · 7 min read

If you’re running ECS Fargate in private subnets with a NAT Gateway, you’re almost certainly paying AWS to route traffic between two AWS services. That traffic could be free. You just need to know where to look.

The Default Architecture Everyone Uses

Every AWS tutorial, reference architecture, and “getting started” guide for ECS Fargate recommends the same setup:

  1. Put your containers in private subnets (good — they shouldn’t be directly on the internet)
  2. Add a NAT Gateway for outbound traffic (makes sense — containers need to reach external APIs)
  3. Done

This works. It’s secure. It’s also quietly expensive.

In us-east-1 and us-west-2, a NAT Gateway costs $0.045 per hour (about $33/month just to exist) plus $0.045 per GB processed. That per-GB charge applies to ALL traffic — including traffic between your containers and other AWS services like CloudWatch Logs, Secrets Manager, ECR, and S3.

Your containers aren’t reaching across the internet to talk to CloudWatch. They’re talking to a service running in the same region, possibly the same data center. But without a VPC endpoint, that traffic has to leave your VPC through the NAT Gateway, traverse AWS’s network, and come back in. And you pay for every byte.

What’s Actually Going Through Your NAT Gateway

For a typical ECS Fargate deployment, the NAT Gateway handles:

Constant traffic (24/7):

  • CloudWatch Logs — every stdout/stderr line from every container streams through the NAT Gateway. This is usually the biggest offender.
  • ECS Agent — the Fargate platform agent polls the ECS API regularly to check for deployments, configuration changes, and task health.
  • SSM Agent — if you have ECS Exec enabled (for aws ecs execute-command), the SSM agent maintains a persistent connection.

Periodic traffic:

  • ECR image pulls — every time a container starts, it pulls the Docker image through the NAT Gateway. A 500 MB image across 10 containers = 5 GB of NAT data transfer.
  • Secrets Manager — containers fetch secrets on startup. Each call is small, but at $0.045/GB it adds up.
  • S3 — if your app reads or writes files to S3, every byte goes through NAT.

Traffic that actually needs NAT:

  • Calls to external APIs (Stripe, Supabase, SendGrid, etc.)
  • Anything outside of AWS

That last category is usually the smallest. Most of your NAT bill is AWS talking to AWS.

VPC Endpoints: The Fix

A VPC endpoint creates a private connection between your VPC and an AWS service. Traffic stays on AWS’s backbone network and never touches the NAT Gateway.

There are two types:

Gateway Endpoints (Free)

ServiceCostNotes
S3FreeNo per-hour or per-GB charge. No reason not to add this.
DynamoDBFreeSame — free and eliminates NAT charges for DynamoDB traffic.

These are route-table level. You add them, update your route tables, and S3/DynamoDB traffic bypasses the NAT Gateway automatically. No application changes. No DNS changes. No downtime.

If you use S3 at all — even just for Terraform state — add this endpoint. It’s free money.

Interface Endpoints (~$7.30/month per AZ, plus $0.01/GB)

ServiceCost (2 AZs)Worth it when…
CloudWatch Logs~$14/moYou have more than ~$14/mo in log-related NAT transfer (common)
ECR (ecr.api + ecr.dkr)~$28/moYou do frequent deployments or run many containers that restart often
Secrets Manager~$14/moYou have many secrets fetched frequently (usually not worth it alone)
STS~$14/moRarely worth it — very low traffic
SSM~$14/moOnly if ECS Exec generates significant traffic

Interface endpoints cost $0.01 per hour per AZ (about $7.30/month) plus $0.01 per GB processed. In a 2-AZ setup, that’s roughly $14.60/month per service before data. The per-GB charge is less than a quarter of the NAT Gateway’s. They work by creating an ENI in your subnet with a private IP, and AWS’s private DNS routes service calls to that ENI instead of the public endpoint.

Which Ones Actually Save Money?

This depends on your workload, but for most ECS deployments:

Almost always worth it:

  • S3 Gateway Endpoint — free, no reason to skip
  • DynamoDB Gateway Endpoint — free, add it if you use DynamoDB
  • CloudWatch Logs — usually the single biggest NAT cost driver

Sometimes worth it:

  • ECR — worth it if you have frequent deployments or many container restarts. Fargate image pulls need ecr.api and ecr.dkr, and the image layers come from S3, so the free S3 gateway endpoint matters here too
  • Secrets Manager — worth it if you have dozens of secrets across many containers

Rarely worth it:

  • STS, SSM, KMS — traffic is too low to justify $14/mo each

The key is to check your NAT Gateway metrics before adding endpoints. Don’t guess — measure.

How to Measure What Your NAT Gateway Is Doing

Step 1: Check total data transfer

Look at the BytesInFromDestination metric in CloudWatch for your NAT Gateway. If it’s constant 24/7 with no correlation to your actual user traffic, it’s internal AWS service calls.

Step 2: Enable VPC Flow Logs temporarily

Create a flow log on the NAT Gateway’s ENI, let it run for an hour, then check the destination IPs:

# Create the flow log (you'll need an IAM role and log group)
aws ec2 create-flow-logs \
  --resource-type NetworkInterface \
  --resource-ids eni-your-nat-eni \
  --traffic-type ALL \
  --log-destination-type cloud-watch-logs \
  --log-group-name /vpc/nat-debug \
  --deliver-logs-permission-arn arn:aws:iam::ACCOUNT:role/vpc-flow-logs \
  --max-aggregation-interval 60 \
  --region us-west-2

After an hour, query the logs and aggregate bytes by destination IP. Reverse DNS usually won’t name the service, so match the IPs against AWS’s published ranges instead. https://ip-ranges.amazonaws.com/ip-ranges.json lists every range with its service and region. S3 has its own entries; most other services (CloudWatch Logs, ECR, Secrets Manager) fall under the general AMAZON ranges, so combine the flow logs with timing: traffic that’s steady 24/7 is almost always log shipping.

Step 3: Do the math

If CloudWatch Logs traffic through NAT costs you $20/month and the endpoint costs about $15/month plus a quarter of the data charge, it roughly breaks even. If NAT log traffic costs you $50/month, the endpoint saves around $25–30/month.

Don’t forget to delete the flow log when you’re done — it also generates CloudWatch Logs charges.

Adding Endpoints: Will It Cause Downtime?

No. Adding a VPC endpoint does not cause downtime. Here’s what happens:

  1. Gateway endpoints (S3, DynamoDB): Terraform adds a route to your route table. Existing connections continue working. New connections use the endpoint. Zero interruption.

  2. Interface endpoints: Terraform creates an ENI in your subnet and updates private DNS. Existing connections may continue through NAT until they’re recycled. New connections use the endpoint. Zero interruption.

Your containers don’t need to restart. Your services don’t need to redeploy. There’s no configuration change in the application code. The DNS resolution changes under the hood and traffic starts flowing through the endpoint automatically.

The only thing that can go wrong is a security group misconfiguration — the endpoint’s security group needs to allow inbound HTTPS (port 443) from your private subnets. Terraform handles this if you configure it correctly.

Terraform Example

Here’s a minimal setup for the most common endpoints:

# Free — always add this
resource "aws_vpc_endpoint" "s3" {
  vpc_id       = aws_vpc.main.id
  service_name = "com.amazonaws.${var.region}.s3"
  vpc_endpoint_type = "Gateway"
  route_table_ids   = [aws_route_table.private.id]
}

# Interface endpoint — add if CloudWatch Logs NAT costs > $14/mo
resource "aws_vpc_endpoint" "cloudwatch_logs" {
  vpc_id              = aws_vpc.main.id
  service_name        = "com.amazonaws.${var.region}.logs"
  vpc_endpoint_type   = "Interface"
  subnet_ids          = var.private_subnet_ids
  security_group_ids  = [aws_security_group.vpc_endpoints.id]
  private_dns_enabled = true
}

resource "aws_security_group" "vpc_endpoints" {
  name   = "vpc-endpoints"
  vpc_id = aws_vpc.main.id

  ingress {
    from_port   = 443
    to_port     = 443
    protocol    = "tcp"
    cidr_blocks = [var.vpc_cidr]
  }
}

The Bigger Picture

The NAT Gateway is a “set it and forget it” service that quietly accumulates cost. It’s one of the most common sources of surprise on AWS bills, and it’s almost always fixable without downtime or application changes.

The pattern is always the same:

  1. Check your NAT Gateway data transfer metrics
  2. Enable flow logs to identify which services are generating traffic
  3. Add the appropriate VPC endpoints
  4. Delete the flow logs
  5. Watch the NAT data transfer drop

For small deployments, the S3 gateway endpoint (free) and suppressing health check logs might be all you need. For larger deployments, a CloudWatch Logs endpoint pays for itself almost immediately.

Either way — measure first, then decide. The data is all there in CloudWatch. You just have to look.


Want someone to find these charges for you? Our AWS cost audit is fixed-price, priced by your spend, and comes with a refund guarantee.

FAQ

Frequently Asked Questions

Do VPC endpoints reduce NAT Gateway costs?

Yes, for traffic to AWS services. A gateway endpoint for S3 or DynamoDB is free and removes that traffic from the NAT Gateway entirely. Interface endpoints cost about $7.30 per AZ per month plus $0.01/GB, so they pay off when a service sends enough traffic through NAT.

Does adding a VPC endpoint cause downtime?

No. Gateway endpoints add a route and interface endpoints update private DNS. New connections use the endpoint, existing ones finish normally, and nothing needs to redeploy. The usual mistake is an endpoint security group that doesn't allow HTTPS from your subnets.

Which VPC endpoints should I add first?

The S3 gateway endpoint, because it's free. Then measure: CloudWatch Logs is usually the biggest NAT cost for container workloads, followed by ECR on teams that deploy often.

Free download

The AWS Bill Self-Audit Checklist

32 places AWS quietly charges you, where to find each one in Cost Explorer, and what to do about it.

Get the free PDF

Ready to Get Your Systems Connected?

Tell us what tools you're using and what's not working.