You set up an Application Load Balancer. You point your domain at it. Everything works. Then someone reports they’re hitting the wrong site, or a webhook fails because the receiving end has your old IP allowlisted, or a client on a corporate network gets a certificate error on a domain they’ve used for months.

The load balancer didn’t break. DNS did what DNS does. And the ALB’s floating IP address was the root cause you didn’t see coming.

Why ALBs Don’t Have Static IPs

An Application Load Balancer isn’t a single machine with a single IP. It’s a managed fleet that AWS scales up and down behind the scenes. When traffic spikes, AWS brings in more capacity. When it drops, capacity is reclaimed. The IP addresses assigned to your load balancer change as that fleet scales.

AWS gives you a DNS name for your ALB, something like my-alb-1234567890.us-east-1.elb.amazonaws.com. That name stays constant. The IPs it resolves to do not. AWS sets the TTL on that record low (typically 60 seconds) so that well-behaved clients pick up changes quickly. “Well-behaved” is doing a lot of work in that sentence.

The DNS Cache Problem

Here’s the scenario that causes real pain.

You migrate to AWS. Your domain api.yourcompany.com now points at an ALB. Everything looks fine. A few days later, a client reports they can’t reach your API. They’re getting a certificate error, or hitting a completely different site.

What happened: somewhere between their browser and your server, a DNS resolver cached the IP of your old server. Maybe it was their ISP’s resolver with a broken TTL implementation. Maybe it was their corporate proxy. Maybe the client application resolved DNS once at startup and never did it again (Java applications are notorious for this).

That cached IP now points somewhere else entirely. When AWS recycles IP addresses, they can be reassigned to other customers. A client with a stale cache might land on a completely unrelated AWS workload, get a connection refused, or get a TLS handshake failure because the certificate doesn’t match.

This isn’t a rare edge case. Aggressive DNS caching happens constantly:

  • Corporate networks often run internal DNS resolvers that cache aggressively or override TTLs
  • Mobile clients on low-bandwidth networks cache DNS to avoid repeated lookups
  • Custom DNS setups, split-horizon DNS, local /etc/hosts overrides, VPN clients, all create situations where the DNS your user sees isn’t the DNS you expect
  • Long-running processes that resolve once at startup and never re-resolve

The worst part: these failures are intermittent and hard to reproduce. They show up in support tickets as “the site is down” when the site is completely fine for everyone else.

DNS cache pointing to recycled IP instead of your ALB

Why It’s Worse Than It Sounds

The IP recycling issue isn’t just about “your IP changed.” When AWS reclaims an IP and reassigns it, someone else’s workload gets your old address. A client with a stale cache will make a TLS connection to that new workload and get a certificate mismatch. Or if the other workload is also HTTP, they might get a completely different site’s content with no visible error.

For APIs, this means requests your clients think they’re sending to you are going somewhere else. Those requests might contain auth tokens, sensitive payloads, or confidential data. The other workload receiving them almost certainly ignores them, but the data left your client’s machine headed to the wrong destination.

Two Solutions

Option 1: AWS Global Accelerator

Global Accelerator gives you two static Anycast IP addresses that never change. You point them at your ALB as an endpoint, and traffic flows through AWS’s global backbone network to your load balancer.

The IPs are truly static. They don’t move, they don’t get recycled, they’re yours for as long as you keep the accelerator running. You can put them directly in DNS A records. Clients that cache the IP aggressively will continue reaching your infrastructure correctly even if the underlying ALB changes completely.

Global Accelerator also has performance benefits for global traffic. Anycast means users connect to the nearest AWS edge point of presence, and traffic rides the AWS backbone from there instead of the public internet.

The catch is cost. Global Accelerator charges a fixed hourly rate (around $0.025/hour, roughly $18/month) plus a premium on data transfer. For a high-traffic global application, the routing benefits might justify it. For a regional application where you just want stable IPs, you’re paying a premium for something you don’t need.

Option 2: VPC IPAM

AWS recently added native IPAM support directly to ALBs. You don’t need an NLB in front, you don’t need any extra infrastructure layer. You create an IPAM pool, provision a contiguous block of public IPs to it, and reference the pool when you create (or modify) your ALB. The ALB allocates its node IPs from that pool instead of from AWS’s shared regional pool.

The result: your ALB’s IPs come from a predictable CIDR block that belongs to your account. Instead of telling a client “allowlist these individual IPs,” you say “allowlist 18.97.0.40/30” and you’re done. As the ALB scales and new nodes come up, they pull from the same pool and stay in the same prefix. No firewall rule updates, no support tickets.

IPAM pool allocating contiguous IPs to ALB, client allowlisting one CIDR

There is a cost. Amazon-provided public IPv4 addresses in an IPAM pool are billed hourly. Check the Amazon VPC pricing page for current rates. If you have your own IP space you can bring it via BYOIP, which eliminates the per-IP charge and gives you addresses that travel with you if you ever move providers.

Why IPAM Wins

One CIDR to rule them all. This is the big one for enterprise and B2B customers. A single /30 or /29 covering all your ALB IPs means firewall management is a one-time operation. Global Accelerator gives you two static but unrelated addresses. IPAM gives you a contiguous block.

No extra hops. Global Accelerator routes traffic through AWS edge locations before it reaches your region. For users already geographically close, this adds unnecessary latency. IPAM changes nothing about the traffic path.

You control the address space. The IPs live in your IPAM pool, in your account. You can track them, monitor usage via CloudWatch, and alarm if something gets accidentally released. Global Accelerator IPs are opaque.

Existing ALBs can be migrated. You can attach an IPAM pool to a running ALB with modify-ip-pools. New ENIs are provisioned with IPs from the pool, Route 53 updates the ALB’s DNS to reflect the new addresses, and old IPs drain gracefully as HTTP keepalives expire.

Setting It Up

Step 1: Create an IPAM

aws ec2 create-ipam --region us-east-1

The response includes a PublicDefaultScopeId. You’ll need it in the next step.

Step 2: Create a Pool and Provision a CIDR

aws ec2 create-ipam-pool \
  --region us-east-1 \
  --ipam-scope-id ipam-scope-01bc7290e4a9202f9 \
  --address-family ipv4 \
  --locale us-east-1 \
  --aws-service ec2 \
  --public-ip-source amazon

Provision a contiguous block to the pool. A /30 gives you 4 IPs, a /29 gives you 8:

aws ec2 provision-ipam-pool-cidr \
  --region us-east-1 \
  --ipam-pool-id ipam-pool-07ccc86aa41bef7ce \
  --netmask-length 30

Wait for it to reach provisioned state:

aws ec2 get-ipam-pool-cidrs \
  --region us-east-1 \
  --ipam-pool-id ipam-pool-07ccc86aa41bef7ce

Step 3: Attach the Pool to Your ALB

For a new ALB:

aws elbv2 create-load-balancer \
  --type application \
  --name my-alb \
  --ip-address-type ipv4 \
  --subnets subnet-aaa subnet-bbb \
  --scheme internet-facing \
  --ipam-pools Ipv4IpamPoolId=ipam-pool-07ccc86aa41bef7ce

For an existing ALB:

aws elbv2 modify-ip-pools \
  --load-balancer-arn <ALB ARN> \
  --ipam-pools Ipv4IpamPoolId=ipam-pool-07ccc86aa41bef7ce

That’s it. Route 53 updates the ALB’s DNS records to the new IPs automatically. Verify the association in the ALB’s Network mapping tab, or check via CLI:

aws elbv2 describe-load-balancers \
  --load-balancer-arns <ALB ARN>

Step 4: Update DNS (or Don’t)

Your ALB’s DNS name still works as before. The difference now is that the IPs behind it come from your pool. If clients have been resolving the DNS name correctly, nothing changes for them.

If you want to give clients a stable CIDR to allowlist directly, point your A records at the IPs from the pool and hand them 18.97.0.40/30.

Monitoring

Check what’s been allocated from your pool:

aws ec2 get-ipam-pool-allocations \
  --region us-east-1 \
  --ipam-pool-id ipam-pool-07ccc86aa41bef7ce

IPAM publishes CloudWatch metrics for pool usage. Set an alarm if you’re approaching the limit so you don’t hit the fallback behavior (if the pool runs out of addresses, AWS falls back to the shared regional pool for new nodes, which defeats the whole point).

What to Do Right Now

If you’re running an internet-facing ALB, the DNS caching problem is already present. It surfaces when a client’s resolver caches an IP that AWS later recycles and gives to someone else.

The fix is a few CLI commands. Create an IPAM pool, provision a small CIDR to it, run modify-ip-pools against your ALB. Your load balancer now draws IPs from a predictable block, your clients get a single CIDR to allowlist, and the next time someone asks for your IP range you have a clean answer instead of a list.