Hermes Wiki

NAT Gateway vs. NAT Instance

Concept

A resource in a private subnet (see Public vs. Private Subnets) has no route to an Internet Gateway, so it cannot reach the public internet on its own — but "not inbound-reachable" and "can't make outbound calls at all" are different requirements, and most private-subnet workloads still need the latter (pulling package updates, calling a third-party API, reaching a SaaS endpoint). Network Address Translation (NAT) solves this: a NAT device sits in a public subnet, and the private subnet's route table sends its 0.0.0.0/0 traffic there. The NAT device rewrites the private resource's source IP to its own public IP for outbound packets, and reverses the translation for the matching return traffic — so the private resource gets a real path out, without ever becoming reachable from outside.

AWS offers two ways to run that NAT device:

  • NAT Gateway — a fully managed AWS service. You provision it, AWS handles patching, scaling, and availability within its Availability Zone.
  • NAT Instance — a plain EC2 instance running NAT software (or a purpose-built AMI like fck-nat), which you provision, patch, and scale yourself like any other EC2 instance.

Tradeoffs

NAT Gateway NAT Instance
Management Fully managed — no patching, no OS Self-managed EC2 instance — you own patching, monitoring, sizing
Throughput Up to 100 Gbps, scales automatically Bounded by instance type (e.g. a t3.micro tops out around 5 Gbps)
High availability Highly available within its AZ by default; a Regional/multi-AZ setup needs one NAT Gateway per AZ A single instance is a single point of failure unless you build your own failover (e.g. an Auto Scaling group with health checks)
Cost model Hourly charge (~$0.045/hr in us-east-1) plus ~$0.045/GB processed, on top of standard data transfer Just the EC2 instance cost (e.g. ~$7.50/mo for a t3.micro) plus normal data-transfer-out — no per-GB processing fee
Operational cost (unstated in the sticker price) Effectively zero — AWS operates it Monitoring, patching, and incident response for a self-managed box are real, recurring engineering cost

At low-to-moderate data volumes, a NAT instance is meaningfully cheaper on paper; the NAT Gateway's per-GB processing fee is what tends to dominate the bill on high-egress workloads, which has spawned an ecosystem of cost-optimization advice (VPC endpoints for AWS-service traffic that would otherwise transit the NAT Gateway, or self-hosted alternatives like fck-nat) aimed specifically at that fee.

When to use / when not to

  • Default to NAT Gateway for production workloads: the availability and throughput it provides out of the box is usually worth the premium once you account for the real cost of self-managing an instance's patching and failover.
  • Consider a NAT instance for dev/test environments, low-traffic accounts, or cost-sensitive batch workloads where an occasional outage or capacity ceiling is an acceptable tradeoff for a meaningfully smaller bill.
  • If NAT Gateway data-processing costs are the actual pain point (not availability), look at VPC endpoints first (see VPC Endpoints / PrivateLink) for AWS-service traffic (S3, DynamoDB, etc.) that doesn't need to transit a NAT device at all — that often closes more of the cost gap than switching to a NAT instance does, without giving up managed HA.
  • Don't run a single NAT instance (or a single NAT Gateway with no per-AZ redundancy) as the only egress path for a production multi-AZ deployment — that single device becomes a shared point of failure for every AZ's outbound traffic, undermining the AZ-level isolation the rest of the architecture is built on.

Common pitfall

Provisioning one NAT Gateway for an entire multi-AZ VPC instead of one per AZ. It works, and it's cheaper — but it silently reintroduces a cross-AZ dependency into a design that was otherwise isolated per-AZ: if that NAT Gateway's AZ has a problem, every private subnet's outbound traffic in every AZ is affected, not just the one collocated with the gateway. The fix (one NAT Gateway per AZ, with each AZ's private subnets routed to their own local one) costs more per month but restores the AZ-isolation the rest of the multi-AZ design assumed was already there.

Engineering Lens

NAT Gateway vs. NAT instance is a small, concrete instance of the build-vs-buy tradeoff that shows up everywhere in infrastructure: the managed option's sticker price looks worse in isolation, and only wins the comparison once you price in the self-managed option's real operational cost — patching, capacity planning, and being the one paged when it fails. The pitfall of sharing one NAT Gateway across AZs is the same failure-domain mistake as Slack's Whitecastle incident at a smaller scale (see the case study): a piece of shared infrastructure that was meant to be an implementation detail quietly becomes a single point of failure for everything depending on it, and nobody explicitly decided that — it just happened by taking the simpler, cheaper default.

Sources

Hermes Wiki