NAT Gateway

A NAT gateway is a managed device that lets instances in a private subnet start outbound connections to the internet while accepting none from it.

A NAT gateway is a managed network device that lets instances in a private subnet start outbound connections to the internet while accepting no connections initiated from the internet. It performs network address translation: the private source address on every outgoing packet is rewritten to the gateway's own public address, and replies are translated back and delivered to the instance that asked for them.

The name comes from the translation function, and the word gateway signals that a route table points at it. Every major cloud provider sells a managed version, and the shape repeats in each one: a device with a public address, a default route from the private subnet pointing at it, and a bill with an hourly component and a per gigabyte component.

Definition

Three pieces have to line up before a NAT gateway does anything.

A private subnet is an address range whose route table carries no route to an internet gateway. Instances in it hold addresses from the RFC 1918 private ranges (10.0.0.0/8, 172.16.0.0/12, 192.168.0.0/16), which are not routable on the public internet.

A public subnet is an address range whose route table sends 0.0.0.0/0 to an internet gateway. The NAT gateway lives here and holds a public address of its own.

A default route in the private subnet's route table sends 0.0.0.0/0 to the NAT gateway rather than to the internet gateway. That one line is what turns a subnet from isolated into outbound only.

The translation itself is port address translation. The gateway holds a table entry per flow: source address, source port, destination address, destination port. On the way out it rewrites the source pair to its own address and a port it allocates. On the way back it looks the reply up in the same table and rewrites the destination back to the instance. A packet arriving from the internet is dropped unless it matches an entry the gateway created on the way out. That asymmetry is the security property people buy a NAT gateway for, and it is why a machine behind one needs no inbound firewall rule at all.

Three devices can carry traffic out of a subnet, and they differ on direction and on price.

DeviceDirection allowedWho can start a connectionPer gigabyte processing charge
Internet gatewayInbound and outboundEither sideNo
NAT gatewayOutbound onlyThe instanceYes
Gateway VPC endpoint (S3, DynamoDB)To that one serviceThe instanceNo

A NAT gateway on AWS is a zonal resource. It lives in one availability zone, so instances in another zone that route through it pay cross zone data transfer and lose their path entirely when that zone fails. The usual arrangement is one gateway per availability zone with a route table per zone. AWS documents each gateway as supporting up to 55,000 simultaneous connections to each unique destination and as scaling from 5 Gbps up to 100 Gbps of bandwidth (AWS NAT gateway documentation, checked on 2026-08-13). Exhausting the port range against a single destination surfaces as an ErrorPortAllocation metric rather than as a slow connection, which is why heavy fan out to one host is worth watching.

Two variants exist. A public NAT gateway carries IPv4 traffic to the internet. IPv6 uses a separate device, the egress only internet gateway, with the same outbound only behavior and no per gigabyte charge. A private NAT gateway translates between networks with overlapping address ranges and reaches no internet at all.

The bill has two parts. In US East (N. Virginia) AWS charges $0.045 per hour for each NAT gateway plus $0.045 per GB of data processed in either direction (Amazon VPC pricing, checked on 2026-08-13). The hourly part accrues whether or not a packet moves: 730 hours in a 30 day month is $32.85 per gateway, so a three zone layout costs $98.55 a month before any traffic. Google Cloud and Azure sell the same function as Cloud NAT and NAT Gateway, and both bill on the same two axes.

Example

A team moves its GitHub Actions runners into a private subnet so that outbound traffic leaves from a fixed set of addresses and nothing on the internet can reach the machines. The workflow file does not change, because network placement is a property of the machine rather than of the job:

name: build
on:
  push:
    branches: [main]

jobs:
  package:
    runs-on: [self-hosted, linux, x64]
    steps:
      - uses: actions/checkout@v4
      - uses: actions/setup-node@v4
        with:
          node-version: 22
      - run: npm ci
      - run: docker build -t app:${{ github.sha }} .

Every step in that job talks to something outside the VPC, and the route table decides which of those conversations passes through the meter.

TrafficDestinationPath outPer gigabyte charge
Action downloads and actions/checkoutgithub.comNAT gatewayYes
npm ci dependency tarballsPublic package registryNAT gatewayYes
Base image layers pulled by docker buildPublic container registryNAT gatewayYes
Log and status streaming from the runner agentgithub.comNAT gatewayYes
Cache and artifact writes to object storage in the same regionS3Gateway VPC endpointNo

Put numbers on the top four rows. A fleet running 1,000 jobs a month, each pulling 1.5 GB of actions, packages, and image layers, moves 1,500 GB through the gateway. At the US East (N. Virginia) rate that is 1,500 times $0.045, which is $67.50 in data processing. Three gateways across three availability zones add 3 times 730 hours times $0.045, which is $98.55 in hourly charges. The network bill for that fleet is $166.05 a month, and none of it lands on the compute line where anyone is looking.

Two levers move that number. The first is the last row of the table. Gateway VPC endpoints for S3 and DynamoDB carry no hourly charge and no per gigabyte charge (Amazon VPC pricing, checked on 2026-08-13), so cache and artifact traffic routed through one leaves the metered path. The AWS setup checklist for runners in your own cloud account states both halves of this: private subnets must have a NAT gateway, and an S3 gateway endpoint should be configured for the VPC so that runners reach the bucket without data transfer charges.

The second lever is placement. A runner in a public subnet with its own public address skips the gateway and its meter. The trade is the stable outbound address, because only traffic leaving through a NAT gateway carries the gateway's address, and that address is what a partner allowlist or a database firewall rule is written against.

One distinction is worth keeping straight. A private subnet is about how a machine reaches the internet, and a NAT gateway serves that case. Reaching an internal service that has no public address at all is a different problem, solved by a peered network or an overlay joined when the job starts, as covered in the networking documentation.

FAQ

What is a NAT gateway in simple terms?

A NAT gateway is a managed device that sits between a private subnet and the internet. Instances behind it can start outbound connections, and the gateway rewrites the private source address on each packet to its own public address so replies find their way back. Nothing on the internet can start a connection inward, because the gateway drops any packet that fails to match an entry it created on the way out.

What is the difference between a NAT gateway and an internet gateway?

An internet gateway allows connections in both directions, so an instance behind one can be reached from the internet if it holds a public address and a security group permits it. A NAT gateway allows outbound connections only and carries a per gigabyte data processing charge that an internet gateway does not. A subnet becomes private by routing 0.0.0.0/0 to a NAT gateway instead of to an internet gateway.

Why does a NAT gateway show up on the cloud bill?

Because it bills on two axes. In US East (N. Virginia) AWS charges $0.045 per hour for each gateway plus $0.045 per GB of data processed in either direction (Amazon VPC pricing, checked on 2026-08-13). The hourly charge accrues while the gateway is idle, and the per gigabyte charge applies to downloads that are otherwise free, such as package tarballs and container image layers.

Start with $10 in free credits

Change the runner label in your workflow and keep the rest of your GitHub Actions setup. Runner time is billed per minute.