Back to posts
May 23, 2026
13 min read

NAT Instance vs NAT Gateway: Self-Managed or Let AWS Handle It?

You’re reviewing this month’s AWS bill. The NAT Gateway line item stands out — $0.045/hour plus $0.045/GB of data processed. With dev/staging environments running 24/7, NAT Gateway costs can reach hundreds of dollars per month just for EC2 instances in private subnets to download packages or call external APIs.

A colleague suggests: “Why not use a NAT Instance for dev? Run it on a t3.micro — costs just a few bucks.”

NAT Instance — sounds familiar but you’ve never set one up. It’s also NAT, but runs on EC2 instead of using a managed service. So how does it work? Why do you need to disable Source/Destination Check? And when should you use it instead of NAT Gateway?

This post assumes you already understand the basics of VPC, subnets, and route tables. If not, read AWS VPC: Understanding VPC Through a Packet’s Journey first.


1. What Is NAT? (Quick Recap)

In a VPC, resources in a private subnet only have private IPs. The internet doesn’t know how to route to private IPs (which belong to the RFC 1918 range — IP addresses reserved for internal networks), so these resources cannot communicate directly with the internet.

NAT solves this by placing a “proxy” in the public subnet: when an EC2 instance in a private subnet wants to reach the internet, the packet is sent to the NAT, which replaces the source IP with its own public IP and forwards the packet out. When the response comes back, the NAT looks up its mapping table and routes it back to the original EC2.

AWS provides 2 ways to do NAT:

  • NAT Gateway: a fully managed service by AWS — you create it, attach an Elastic IP, done. AWS handles everything else.
  • NAT Instance: an EC2 instance you configure yourself to act as NAT — you manage everything from A to Z.

This post focuses on NAT Instance — how it works internally, then compares it with NAT Gateway.


2. NAT Instance — How It Works

2.1. Under the Hood: An EC2 Acting as NAT

A NAT Instance is essentially an EC2 instance running an AMI configured with IP forwarding and iptables. When a packet arrives, instead of processing it at the application layer, the OS changes the source IP and forwards the packet out through another interface — just like a traditional NAT router.

To function, a NAT Instance requires 4 things:

  1. Placed in a public subnet — because it needs a route to the internet via the Internet Gateway (IGW)
  2. Elastic IP attached — so the internet can send responses back
  3. Source/Destination Check disabled — details in the next section
  4. Route table configured — the private subnet must have a route 0.0.0.0/0 → eni-xxx pointing to the NAT Instance’s ENI

AWS used to provide a pre-configured Amazon Linux AMI for NAT Instances, but this AMI reached the end of standard support on December 31, 2020. If you want to use a NAT Instance today, you have 2 options: find an alternative AMI on the AWS Marketplace (several community AMIs come pre-configured for NAT, such as fck-nat — an open-source alternative optimized for cost), or configure it yourself from a standard Linux AMI — enable IP forwarding in the kernel (net.ipv4.ip_forward = 1) and set up iptables NAT rules.

2.2. Source/Destination Check — Why Must It Be Disabled?

This is the most interesting part of understanding NAT Instance. Before understanding why it must be disabled, let’s understand why AWS enables it by default.

What Is Source/Destination Check?

By default, AWS enables Source/Destination Check on every EC2 instance. This feature checks: does the packet arriving at or leaving this instance have a source or destination IP that matches the instance’s own IP? If not — the packet is dropped immediately.

Why Does AWS Enable It by Default?

This is a defense in depth mechanism that works independently of Security Groups and NACLs — meaning even if your SG or NACL is misconfigured, this layer still prevents dangerous behavior:

1. Preventing IP SpoofingIP Spoofing is a technique where an attacker forges the source IP in a packet to deceive the target system. Attackers can use this in DDoS reflection attacks (spoofing the victim’s IP so servers send responses to the victim), or bypass firewalls by impersonating a trusted IP. Source/Dest Check ensures that outgoing packets must have the instance’s own IP as the source, preventing all forms of IP forgery.

2. Blocking Unauthorized Traffic Forwarding — Without this mechanism, a compromised EC2 instance could become a proxy to forward malicious traffic to other instances in the VPC, or perform lateral movement. By dropping all packets that don’t belong to the instance, AWS blocks this behavior at the infrastructure level.

3. Ensuring Routing Consistency — In a multi-tenant cloud environment, AWS needs to ensure traffic follows the defined route tables. If instances could freely forward traffic, any instance could “become a router” on its own and break the network topology, making troubleshooting and network auditing extremely difficult.

4. Secure by Default — AWS follows the Least Privilege principle: dangerous behaviors are blocked by default, and those who need them must explicitly opt in. Most workloads (web servers, app servers, databases) don’t need to forward traffic, so enabling Source/Dest Check by default makes sense.

PurposeProtects Against
Anti IP SpoofingIP forgery attacks, DDoS reflection
Block unauthorized forwardingCompromised instance as proxy, lateral movement
Ensure routing consistencyMisrouted traffic, audit difficulties
Secure by defaultAccidental vulnerabilities from misconfiguration

Why Must NAT Instance Disable It?

But NAT Instance is different — its entire job is to forward packets on behalf of others. Look at the packet it receives from an EC2 in a private subnet:

src: 10.0.2.20 ← IP of the EC2 in the private subnet dst: 3.5.6.7 ← IP of an external server

The NAT Instance has IP 10.0.1.30. Neither the source nor the destination matches the NAT Instance’s IP. With Source/Destination Check enabled, this packet gets dropped — the NAT Instance never even sees it.

Similarly, when the NAT Instance forwards a packet outbound, the original source IP (10.0.2.20) doesn’t match the NAT Instance’s IP → check fails → packet dropped again.

That’s why you must disable Source/Destination Check on the NAT Instance. Without this step, the NAT Instance is completely useless — it cannot forward a single packet. Besides NAT Instance, other use cases that require disabling this mechanism include: VPN instances, software firewalls, or any instance acting as a router.

With NAT Gateway, you don’t need to worry about this — AWS handles it automatically since it’s a managed service, not running on a regular EC2 instance.

2.3. Detailed Packet Flow

Let’s trace a packet from an EC2 in a private subnet to the internet via a NAT Instance:

EntityIP
EC2 (private subnet)10.0.2.20
NAT Instance (public subnet)Private: 10.0.1.30, EIP: 12.34.56.78
External server3.5.6.7

Outbound:

#LocationsrcdstAction
1EC210.0.2.203.5.6.7Create packet
2Route Table (private)10.0.2.203.5.6.7Match 0.0.0.0/0 → eni-xxx → forward to NAT Instance
3NAT Instance10.0.2.2010.0.1.303.5.6.7iptables replaces src IP, saves mapping in conntrack
4Route Table (public)10.0.1.303.5.6.7Match 0.0.0.0/0 → igw-xxx → forward to IGW
5IGW10.0.1.3012.34.56.783.5.6.71:1 NAT private → EIP
6Internet12.34.56.783.5.6.7Server receives request

Return:

#LocationsrcdstAction
1Server3.5.6.712.34.56.78Send response
2IGW3.5.6.712.34.56.7810.0.1.301:1 NAT EIP → private
3Route Table (public)3.5.6.710.0.1.30Match 10.0.0.0/16 → local
4NAT Instance3.5.6.710.0.1.3010.0.2.20Look up conntrack, replace dst IP
5Route Table (private)3.5.6.710.0.2.20Match 10.0.0.0/16 → local
6EC23.5.6.710.0.2.20Receive response

Just like NAT Gateway, there are 2 NAT translations on the outbound path:

  • NAT Instance (hop 3): many-to-1 — multiple EC2s share the NAT Instance’s private IP, differentiated by source port
  • IGW (hop 5): 1-to-1 — fixed EIP mapping

2.4. Security Group for NAT Instance

Since a NAT Instance is an EC2, you can (and must) attach a Security Group. This is both an advantage (granular traffic control) and a responsibility (misconfigure it and you lose connectivity).

Minimum Security Group rules for a NAT Instance:

Inbound Rules:

TypePortSourcePurpose
HTTP8010.0.2.0/24 (Private Subnet CIDR)Allow HTTP traffic from private subnet
HTTPS44310.0.2.0/24 (Private Subnet CIDR)Allow HTTPS traffic from private subnet
SSH22Your IPAdminister the NAT Instance (via IGW)

Outbound Rules:

TypePortDestinationPurpose
HTTP800.0.0.0/0Forward HTTP traffic to the internet
HTTPS4430.0.0.0/0Forward HTTPS traffic to the internet

For comparison: NAT Gateway does not support Security Groups — you can only control traffic using NACLs. With a NAT Instance, you get both layers of protection: Security Group (stateful, instance-level) + NACL (stateless, subnet-level).


3. Zonal NAT Gateway — Managed Service (Recap)

NAT Gateway is the option AWS recommends by default. Instead of managing your own EC2, you simply:

  1. Create a NAT Gateway in a public subnet
  2. Attach an Elastic IP
  3. Configure the route table: 0.0.0.0/0 → nat-xxx

AWS handles everything else: patching, monitoring, scaling, and high availability within the AZ. Bandwidth auto-scales from 5 Gbps up to 100 Gbps — no need to choose an instance type or worry about bottlenecks.

Note: EC2 instances in the same subnet as the NAT Gateway cannot use it — only EC2 instances from other subnets can route traffic through the NAT Gateway. This is why the NAT Gateway is always placed in a public subnet, while EC2 instances that need NAT reside in a private subnet.

For details on how NAT Gateway works (PAT, double NAT, connection tracking), see AWS VPC: Understanding VPC Through a Packet’s Journey — Flow 3: EC2 → Stripe.

Important note about High Availability: NAT Gateway has automatic HA within a single AZ. If that AZ goes down, the NAT Gateway goes down too. For region-wide HA, you need to deploy one NAT Gateway per AZ and configure route tables accordingly for each AZ’s private subnets. You don’t need to worry about cross-AZ failover — because when an AZ goes down, the EC2 instances in that AZ go down as well, so they no longer need NAT.

The section above describes Zonal NAT Gateway — the traditional type that operates within a single AZ. Since late 2025, AWS has launched Regional NAT Gateway with significant improvements — details in the next section.


4. Regional NAT Gateway — A Major Step Forward (2025)

In November 2025, AWS announced regional availability mode for NAT Gateway. With this feature, you can create a single NAT Gateway that automatically scales up and down across Availability Zones (AZs) in your VPC based on workload presence, maintaining high availability while simplifying setup and management.

This is a major step forward because previously, achieving region-wide HA required manually deploying a NAT Gateway in each AZ. Now AWS handles that for you.

4.1. Key Differences from Zonal NAT Gateway

1. No Public Subnet Required

Traditionally, NAT Gateway required a public subnet (a subnet with a direct route to the internet via IGW) for internet access. Security-conscious customers had to ensure no one created other resources in that public subnet. With Regional NAT Gateway, your VPC doesn’t need a public subnet — this is a major security improvement because VPCs can now be completely private while still having internet egress.

2. Automatic AZ Scaling

Regional NAT Gateway operates at the VPC level. When you expand your workload to a new AZ, you can reuse the same Regional NAT Gateway ID. Regional NAT Gateway automatically scales and maintains zonal affinity to ensure high availability.

3. Simplified Routing

With Zonal NAT Gateway, you need to create separate route tables for each AZ — each pointing to that AZ’s NAT Gateway. With Regional NAT Gateway, you only need a single route table with the entry 0.0.0.0/0 → rnat-xxx, shared across all private subnets in every AZ.

4. Two Operating Modes

Regional NAT Gateway operates in 2 modes:

  • Automatic mode: AWS manages IP addresses and handles AZ changes automatically — you don’t need to intervene when adding or removing AZs
  • Manual mode: you manage IP addresses yourself and are responsible for adjusting the gateway per AZ — suitable when you need tight control over egress IP addresses (e.g., for allowlisting)

4.2. Limitations

1. No Private NAT Support: Regional NAT Gateway requires an Internet Gateway (IGW) in the VPC — meaning it only supports public NAT (traffic to the internet). If you need private NAT (internal traffic between VPCs or to on-premise), you must still use Zonal Private NAT Gateway.

2. No Significant Cost Reduction: Regional NAT Gateway simplifies operations, but costs are comparable to deploying multi-AZ Zonal NAT Gateways. If your goal is to reduce costs, consider migrating to IPv6 instead of using NAT.

4.3. AWS Recommendation

AWS recommends migrating to Regional NAT Gateway for all use cases except those requiring private connectivity — a feature that Regional NAT Gateway does not yet support.


5. Detailed Comparison

CriteriaNAT InstanceZonal NAT GatewayRegional NAT Gateway
NatureEC2 instance running a NAT-configured AMIManaged service, operates in 1 AZManaged service, operates at region level
ManagementYou manage everything (patch, update, monitor)AWS manages everythingAWS manages everything
High AvailabilityNot built-in — must self-setup with ASG multi-AZAutomatic HA within 1 AZAutomatic HA across region (multi-AZ)
BandwidthDepends on instance typeAuto-scales 5–100 GbpsAuto-scales 5–100 Gbps
CostPay for EC2 instance (cheaper with small instances)$0.045/hr + $0.045/GBComparable to Zonal NAT Gateway
Security GroupCan attachNot supported (NACL only)Not supported (NACL only)
Use as Bastion hostPossibleNot possibleNot possible
Port forwardingSupportedNot supportedNot supported
Source/Destination CheckMust disable manuallyNot needed (AWS handles it)Not needed (AWS handles it)
Elastic IPCan use EIP or public IPEIP requiredSupported (depends on mode)
Public subnetRequiredRequiredNot required
Private NATCan be configuredSupportedNot yet supported
Routing for multi-AZSeparate route table per AZSeparate route table per AZSingle shared route table

6. When Should You Use Which?

Use Regional NAT Gateway when:

  • Production environments requiring multi-AZ HA without managing multiple NAT Gateways
  • You want to simplify routing — just 1 shared route table for all AZs
  • You want enhanced security — no public subnet needed in the VPC
  • When adding new AZs, you don’t want to create additional NAT Gateways and modify route tables
  • This is the new AWS recommendation, replacing Zonal NAT Gateway for most use cases

Use Zonal NAT Gateway when:

  • You need private NAT (internal traffic between VPCs or to on-premise) — Regional NAT Gateway doesn’t support this yet
  • You already have stable multi-AZ NAT Gateway infrastructure and don’t need to migrate yet

Use NAT Instance when:

  • You want to save costs for dev/test environments — a t3.micro costs only ~$7–8/month compared to ~$32/month for NAT Gateway (excluding data processing fees)
  • You need port forwarding — for example, forwarding port 3306 from the internet to an RDS in a private subnet (NAT Gateway doesn’t support this)
  • You want to also use it as a bastion host
  • You need granular traffic control via Security Groups instead of just NACLs
  • Internet traffic is low and predictable

SAA exam tip: Regional NAT Gateway is a new topic that will appear in exams. Remember the key concepts: Source/Destination Check (must be disabled for NAT Instance), Security Group (only NAT Instance supports it), Regional NAT Gateway (automatic multi-AZ HA, no public subnet needed, single shared route table), and Private NAT (only Zonal NAT Gateway supports it, Regional does not yet).


Conclusion

Back to the original question: your colleague suggested using a NAT Instance for the dev environment — this is a reasonable choice if you accept the trade-off of manual management and no built-in HA in exchange for lower costs.

Key takeaways:

  • NAT Instance is a self-managed EC2 that requires disabling Source/Destination Check because it forwards packets that don’t belong to it — neither the source nor destination IP matches its own
  • Zonal NAT Gateway is a managed service operating within a single AZ — AWS handles HA, scaling, and patching — but requires deployment in each AZ for region-wide HA
  • Regional NAT Gateway is a major step forward (2025) — automatic multi-AZ HA, no public subnet needed, and only 1 route table shared across all AZs
  • NAT Instance supports Security Groups, can serve as a bastion host, and enables port forwarding — capabilities that NAT Gateway lacks
  • Regional NAT Gateway is the new AWS recommendation for most use cases; NAT Instance is suitable for dev/test or when you need special features
  • Regional NAT Gateway does not yet support private NAT — if you need private connectivity, you must still use Zonal NAT Gateway

Related