Most private subnets reach the internet through a NAT gateway. It is metered per gigabyte, and it keeps no record of where those gigabytes went. Both of those facts carry a price, and there are two other ways to route the same traffic.
The problem
Most private-subnet workloads reach the internet through a NAT gateway. It is one click in the console and it works, so it is rarely revisited after the day the VPC was built.
A NAT gateway charges two ways. It costs $0.045 an hour just to exist, about $33 a month per gateway. It then costs another $0.045 for every gigabyte it processes (us-east-1, AWS VPC pricing, checked July 2026). The hourly charge is small. The data processing charge scales with traffic, and it applies to all outbound traffic, including traffic to AWS services that never needed to leave the AWS network at all.
It also keeps no record of its own. A NAT gateway does not log which destinations your workloads reached, and it does not filter them. For a security or compliance review, the questions "what is this environment allowed to reach" and "what did it actually reach" have to be answered somewhere else.
The finding
Two separate costs come from the same property: everything leaves through one unfiltered, metered pipe.
The first is that a large share of "internet" traffic is not internet traffic. Container image pulls, S3 reads, CloudWatch Logs, Secrets Manager calls: all of it is AWS traffic routed out through the NAT gateway and billed at $0.045 per gigabyte. Container platforms concentrate this. Every task launch and every scale-out pulls image layers, and on a busy cluster that is gigabytes an hour.
Here is the math on a platform moving 2 TB of egress a month, split 1.4 TB of AWS-service traffic and 0.6 TB of genuine internet traffic. Through a single NAT gateway that is about $33 for the hourly charge, $90 for data processing on the full 2 TB, and $54 of data transfer out for the 0.6 TB that actually reaches the internet ($0.09 per gigabyte, first 10 TB, checked July 2026). Roughly $177 a month, of which $63 is processing charges on traffic that stayed inside AWS. At 20 TB of egress, the processing charge alone is $900 a month.
The second cost is visibility, and it arrives as a separate bill. VPC Flow Logs capture IP addresses and byte counts. Route 53 Resolver query logs capture the domains that were looked up. Both are metered: log delivery is billed per gigabyte of logs, $0.50 to CloudWatch Logs or $0.25 to Amazon S3, plus storage (CloudWatch vended-logs pricing, checked July 2026). Adding GuardDuty to flag suspicious egress is another $1.00 per gigabyte analyzed for the first 500 GB a month (Amazon GuardDuty pricing, checked July 2026). What that buys is a record of IP addresses after the fact. Against destinations behind a CDN, where many services share rotating addresses, that record often does not identify who the workload talked to, and none of it blocks anything.
The options
Three ways to route outbound traffic, and what each one costs.
The NAT gateway on its own
Managed, highly available within an Availability Zone, and it handles any protocol. Nothing to patch, nothing to scale, no failure mode you own. It costs $0.045 an hour plus $0.045 per gigabyte processed, applied to every byte regardless of destination, and it provides no destination logging or filtering of its own.
VPC endpoints for AWS-service traffic
A gateway endpoint for S3 costs nothing: no hourly charge, no data processing (AWS VPC pricing, checked July 2026). Because container image layers are stored in S3, it carries the heaviest AWS-bound flow most platforms have. Interface endpoints, including the two ECR endpoints (ecr.api and ecr.dkr) that complete a fully private image pull, cost $0.01 per hour per endpoint per Availability Zone plus $0.01 per gigabyte (AWS PrivateLink pricing, checked July 2026), under a quarter of the NAT processing rate (Amazon ECR docs, "Amazon ECR interface VPC endpoints").
Endpoints only move AWS-service traffic. They do nothing for third-party APIs or package registries, and each interface endpoint adds a fixed hourly cost per Availability Zone whether or not it is busy. On the 2 TB example, moving AWS traffic onto endpoints takes the $90 processing charge down to a few dollars, against the endpoint hours added.
A self-managed egress proxy
A forward proxy such as Squid on a small instance in a public subnet, with the private subnets given no default route to the internet at all. Applications reach outside only through the proxy via HTTPS_PROXY, which makes the proxy the single path out. A t3.small runs about $15 a month.
On cost, this takes the $0.045 per gigabyte NAT processing charge off internet-bound traffic. It does not touch data transfer out, which stays at $0.09 per gigabyte because those bytes genuinely leave AWS.
On visibility, the proxy brokered the connection, so its log already carries the hostname and the allow or deny decision, and domains can be allow-listed. That is a different kind of record from flow logs, and it does not need a separate log-delivery and threat-detection pipeline to turn IP addresses back into names.
What it costs elsewhere: it is infrastructure you own, keep available, patch and scale. It handles HTTP and HTTPS well and gets awkward with arbitrary TCP or UDP, which needs a transparent-proxy setup or a NAT gateway retained for those flows. It filters by domain on the TLS handshake and does not inspect inside encrypted connections without full interception, which carries its own risks and obligations.
Where each one fits
The NAT gateway's economics turn on volume. Below a few hundred gigabytes a month the processing charge is a rounding error and the hourly charge dominates, so the managed option is cheap in both money and attention. The crossover arrives when per-gigabyte processing outgrows the fixed cost of the alternatives: interface endpoint hours, or a proxy instance somebody maintains.
The AWS-service share is the second variable. A workload that pulls container images constantly sends most of its "egress" to S3 and ECR, where a free gateway endpoint applies. A workload that mostly calls third-party APIs sees little from endpoints, and whatever it saves comes from the proxy path or from nowhere.
Visibility moves independently of cost. If nothing needs to prove what the environment can reach, flow logs enabled on demand may be all the record required, and their per-gigabyte charge applies only while they run. If an auditor, a customer security review, or a data-residency obligation calls for a stated allow list and evidence of what actually left, that is not something a NAT gateway produces at any price, and the comparison stops being about dollars.
Operational appetite is a real cost, not a soft one. A proxy is a component with an on-call story attached. A team without the capacity to own one is weighing an operational risk against a line on the bill, and which way that lands depends on the team, not on the architecture.
Want us to look for issues like this in your account? We offer a free AWS audit: upstood.com