Removing AWS NAT Gateways for fun and profit

Or, The State of IPv6 on AWS as of Summer 2026


If you use AWS and IPv4, you're forced into using NAT gateways because AWS services are hosted on publicly-routable IPs. Each NAT gateway plus its associated public IPv4 address costs a base of 5.7¢/hr ($41/mo). This adds up rapidly, especially if you are the prudent type who wants at least two NAT gateways. Then there is a transfer surcharge of 4.5¢/GB, because AWS is Ayn Rand's anarcho-capitalist dreamworld.

Although we here at the Equitable Society of Bit Plumbers pay our techno-serfish rents to Amazon that we may grow our crop of content in digital cyberspace, this does not mean that we like Amazon or want to remit our techno-serfish rents to Baronial Estate Amazon that we may grow our crop of content in digital cyberspace. Can we give Amazon fewer gold pieces for the same effect? Rebelliousness, after all, is the natural right of the toiling classes.

So. AWS has a facility called PrivateLink that lets you put AWS service endpoints in your private address space. It's billed at 1¢/hr per service per availability zone, plus an additional 1¢/GB transferred. You have to enumerate each service endpoint and many services have two or more endpoints. This isn't strictly better, because depending on the precise mix of AWS services you use and the amount of data you transfer, your costs could be less, more, or the same as with NAT gateways.

Even if PrivateLink is cheaper we're still paying money to Sir Geoffrey, Lord Bezos, First Baron Amazon. We do not want to pay money to Bezos. Perhaps we could try a different scheme. One that involves paying no money, because God created the Internet that information might be free. We are paying these exorbitant rents because IPv4 was a Disco-era experiment with limited address space and which got out of hand. There is an alternative. A better addressing scheme is possible. Let us stare into the blinding Sun of the future and take hold of IPv6.

I'm going to assume you have some passing notion of what IPv6 is, and I assume you already agree with me that NAT is not the most desirable feature that anyone has ever introduced in the history of the Internet. I am also, for the sake of the article, going to make the assumption that you've heretofore dismissed IPv6 as impractical propeller beanie shit.

IPv6 is good for us because IPv6 addresses are a pair of 64 bit words, one containing a subnet identifier and the other containing a station identifier. For every IPv4 address that exists, there exist 232 IPv6 subnets. Every IPv6 subnet can contain every Ethernet MAC address 65,536 times over. A move to IPv6 means we can stop this NAT foolishness entirely and return to unique global addresses like Vint Cerf intended.

Amazon provides a VPC with a /56, which is a block of 256 publicly-routable subnets. 256 subnets for zero dollars should provide adequate sustenance for our networking marathon.

Let's assume that we have a VPC with three kinds of subnets: public, private, and database:

Type Inbound Outbound Purpose
public yes yes to be touched by the internet
private no yes not to be touched by the internet
database no no pedestal for nature's harmonious data cube

This is the most basic expression of a non-trivial setup. We have the three kinds of subnet we should expect to see, one where hosts have bidirectional connectivity to the Internet; one where hosts have unidirectional connectivity to the Internet; and one where hosts have no connectivity to the Internet.

Can we go IPv6-only? Yes, subject to some constraints. First: many, but not all, AWS services support IPv6. Second: RDS's control plane depends on IPv4. Third: some services (*cough* github *cough*) don't support IPv6. If you need neither RDS nor an IPv4-only service, you can go full IPv6.

Anything that uses an AWS SDK needs the AWS_USE_DUALSTACK_ENDPOINT env var set to true, because the normal AWS endpoints only have IPv4 DNS records. If you use ECR to serve Docker images, you'll need to use <ACCT_ID>.dkr-ecr.us-west-2.on.aws instead of <ACCT_ID>.dkr.ecr.us-west-2.amazonaws.com. There, you're done.

What if you can't burn IPv4 to the ground and live in the glorious 128-bit future?

If you've got to talk to IPv4-only internet services, AWS supports NAT64 and DNS64. Guess what that requires? That's right, a NAT gateway at 5.7¢/hr and 4.5¢/GB! All hope is not lost. If you are able to, well, fck-nat supports NAT64 and the attitudes I've seen towards it have been generally positive.

But say you need RDS. That leaves you in dual-stack territory, where you run both IPv4 and IPv6 simultaneously.

In principle the setup is easy, every subnet gets a private IPv4 CIDR range, and a public IPv6 subnet (remember, the purpose of IPv6 is not to have private CIDR ranges). You set up your private IPv6 subnets using egress-only internet gateways so the outside world can't connect to them. Amazon provides those without extra charges.

Some of the consequences are obvious, like every security group will need two sets of rules, one for IPv4 and one for IPv6.

I have run into two and a half or three non-obvious issues, depending on how you count.

ECS has a quirk where it will choose IPv4 service endpoints if your tasks are placed on a dual-stack subnet. If you want to use ECS and IPv6 without NAT gateways, you must place your tasks on IPv6-only subnets. That took me about four hours to figure out, and you're welcome. But it gets better.

Subnets cannot be IPv6ified or de-IPv6ified in place. Instead they must destroyed and recreated. If you're bringing up new infrastructure this is honestly not a big deal. But if you're transitioning an existing system to IPv6 and it has to remain up during the process, you have some careful planning in your future, my friend.

It's less of a big deal, but Amazon SSM-based bastions (IYKYK) need IPv4 even though they support dual stack. They must have IPv4 addresses and those IPv4 addresses must be able to reach the public internet to talk to SSM. In practice that means you're going to have to spend a public IP address on them, for about $7.20/mo.

That's what I've run into. To prove I'm not just Mister Negativity, here's something that actually just works:

ALBs. I have an IPv6-only ECS cluster sitting behind a dual-stack public load balancer. My Kafka brokers are in public subnets and have both IPv4 and IPv6 addresses. And so I've gotten rid of my NAT gateways, which has cut my AWS bill literally in half.

There you have it. I would say there's a very good chance you may no longer need NAT gateways at all, and the amount of infrastructural complexity you have to add isn't all that high. It's worth it to try. Yeah, people complain about IPv6 addresses not being human readable. Neither are 64-bit pointers, but we got over that because five gigabytes of RAM. We'll get over this because 264 subnets. You know, it's really a shame nobody ever invented some kind of system that mapped host names to IP addresses, and IP addresses to host names.


If you've got questions, send them to info@bitplumbers.io. If you’re dealing with a more complex setup and want advice, send an email and we can discuss a consulting engagement.