Skip to content

Adding IPv6 to an existing VPC: the practical steps and the gotchas

Enabling IPv6 on an existing VPC is non-disruptive by itself, but the follow-through matters: per-subnet /64s, egress-only internet gateway, separate security group rules, and OS configuration. The full sequence.

You can add IPv6 to a running VPC without downtime: associate an Amazon-provided /56 with the VPC, hand a /64 to each subnet, add IPv6 routes, extend security groups, and let instances pick up addresses. The result is dual-stack — IPv4 keeps working exactly as before. The gotchas are all in the second half of that list: IPv6 has no NAT on AWS, every address is globally unique, “private” now depends entirely on routing and security groups, and half your security group rules silently do not apply to the new address family.

What’s happening

AWS IPv6 differs from the IPv4 mental model in three ways that drive the whole migration.

First, addresses are global unicast. The /56 you associate is publicly routable space; there is no RFC1918 equivalent in normal use. An instance’s IPv6 address is “public” in the sense that it is unique on the internet — whether anyone can reach it is decided purely by route tables and security groups. Privacy therefore becomes an explicit design act, not an addressing default.

Second, there is no NAT for IPv6. The NAT Gateway does not translate IPv6 (it can do NAT64 for reaching IPv4-only destinations from IPv6-only subnets, a different problem). The private-subnet pattern is the egress-only internet gateway (EIGW): stateful like NAT in effect — instances can initiate outbound IPv6, nothing can initiate inbound — but with no hourly or per-GB charge. Public subnets route ::/0 to the regular internet gateway instead.

Third, everything is opt-in per layer. The VPC association does nothing until subnets get /64s; subnets do nothing until route tables carry IPv6 routes; packets still die until security groups (and NACLs, if customized) have IPv6 rules — IPv4 rules do not cover IPv6, ever. Then the OS needs to actually configure the address (DHCPv6 or RA, handled automatically by recent Amazon Linux/Ubuntu AMIs, manual on older or hardened images), and your load balancers need dualstack address type plus AAAA records before any user traffic arrives.

What to check first

  • Free /64 slots per subnet plan — each subnet gets exactly one /64 from the /56 (256 available), so map subnets to hex slots deliberately.
  • Custom NACLs in use? They will need explicit IPv6 rules including ephemeral return ports.
  • Security groups referencing 0.0.0.0/0 — decide, rule by rule, whether the IPv6 twin ::/0 is appropriate; do not blanket-copy.
  • AMI and OS behaviour — confirm your images configure IPv6 automatically or plan the cloud-init change.
  • Anything that logs, allowlists, or rate-limits by IP — WAF rules, application allowlists, geo-blocks, fraud tooling — all need IPv6 awareness before clients start arriving over it.

How to verify

# Associate an Amazon-provided /56 with the VPC
aws ec2 associate-vpc-cidr-block --vpc-id vpc-0abc123 \
  --amazon-provided-ipv6-cidr-block

# Confirm the allocation
aws ec2 describe-vpcs --vpc-ids vpc-0abc123 \
  --query 'Vpcs[].Ipv6CidrBlockAssociationSet'

# Give a subnet its /64 (choose the hex slot: 00, 01, 02...)
aws ec2 associate-subnet-cidr-block --subnet-id subnet-0abc123 \
  --ipv6-cidr-block 2600:1f11:abc:de00::/64

On an instance, confirm the address and the path:

ip -6 addr show dev ens5
# Global connectivity (public subnet via IGW, private via EIGW)
curl -6 -m 5 https://checkip.amazonaws.com
ping6 -c 3 ipv6.google.com

Console paths: VPC > Your VPCs > Actions > Edit CIDRs for the /56, Subnets > Actions > Edit IPv6 CIDRs per subnet, and EC2 > Load Balancers > Edit IP address type for dualstack. The address-planning details are in the Amazon VPC documentation.

The runbook

  1. Associate the /56 and map your /64 plan. Use the same tier-and-AZ logic as your IPv4 layout — the discipline from multi-AZ subnet design applies unchanged; only the arithmetic got easier.
  2. Assign /64s to subnets and enable auto-assign. aws ec2 modify-subnet-attribute --subnet-id subnet-0abc123 --assign-ipv6-address-on-creation so new ENIs get addresses; existing instances need an address assigned to their ENI or a stop/start of the workload’s launch template cycle.
  3. Add routes by tier. Public subnets: ::/0 -> igw-.... Private subnets: create an egress-only internet gateway (aws ec2 create-egress-only-internet-gateway --vpc-id vpc-0abc123) and route ::/0 -> eigw-.... Never point private subnets’ ::/0 at the IGW — that single route makes every addressed instance reachable from the internet, gated only by security groups.
  4. Extend security groups and NACLs deliberately. Add IPv6 rules mirroring the intent, not the text, of IPv4 rules: internal-only rules get your /56, not ::/0. Custom NACLs need inbound and outbound IPv6 entries, including ephemeral ports.
  5. Turn on the edges last. Switch ALB/NLB to dualstack, publish AAAA records with a low TTL, and watch error rates and logs — this is the moment real users start arriving over IPv6, so keep the rollback (delete AAAA) one command away.
  6. Verify both families end to end. curl -4 and curl -6 against the public hostname from outside; inside, confirm apps bind :: (which accepts both) or explicitly to both families.

When this is the wrong move

If the goal is only to stop paying NAT processing for AWS-bound traffic, VPC endpoints get you there without touching address families. If your dependencies include IPv4-only third parties and your instances would go IPv6-only, you are signing up for NAT64/DNS64 complexity that dual-stack avoids — stay dual-stack. And a compliance environment with IP-based controls scattered through applications should treat IPv6 as a project with an inventory phase, not a weekend enablement.

Common mistakes

  • Routing private subnets’ ::/0 to the internet gateway, instantly exposing anything with an address and an open security group.
  • Copying every 0.0.0.0/0 rule to ::/0 mechanically, including the SSH rule that was supposed to be temporary.
  • Publishing AAAA records before the security group and NACL work, so IPv6-preferring clients (most mobile networks) hit timeouts while IPv4 users see nothing wrong.
  • Forgetting interface endpoints, RDS, and older services may not answer over IPv6 — check each dependency’s dual-stack support rather than assuming.

Prevention

  • Encode the /64 slot map in IaC next to the IPv4 CIDR plan, with tier and AZ in the naming.
  • Add IPv6 cases to your reachability tests and monitoring probes the day you enable it, not the day it breaks.
  • Alarm on new ::/0 routes and on security group rules containing ::/0, same as you do for IPv4.
  • Roll out AAAA records service by service with short TTLs, watching per-family error metrics.
  • Document which dependencies are IPv4-only so nobody schedules an IPv6-only migration around them.

Dual-stack on an existing VPC is a sequence of small, individually safe steps — the risk concentrates entirely in routing and security group intent, which is where your review time should go. If nobody on your team truly owns the AWS environment end to end, that is the root of most of these problems — Stack Harbor runs AWS accounts daily under AWS Operations, and you can book an AWS review.