Why this matters
Two companies merge. Both use 10.0.0.0/16. Or a team builds a second VPC with the default 10.0.0.0/16 and later needs to reach the first one. The tunnel or peering link may come up, but routing fails because a router cannot tell which 10.0.1.10 you mean. How to connect networks with overlapping IP ranges is mostly the work of removing that ambiguity before you turn on traffic.
Most cloud peering products reject overlapping address spaces. AWS VPC peering and Azure VNet peering do not support it. Transit gateways and route servers still route by destination prefix, so two identical prefixes create a conflict. You need renumbering, address translation, separate routing tables, or a service front door that hides the target IPs.
The cost of getting it wrong is subtle. Some flows work, others go to the wrong host, and logs show addresses that exist in two places. Fix it in design, not after a cutover.
Before you start
Build an address inventory before you touch a gateway. List every subnet, its owner, its purpose, and the flows that cross the boundary. Include the direction that starts the connection and the port. Mark any system that stores IP addresses in config, certificates, DNS records, or application payloads.
Choose the smallest scope that solves the problem. Renumbering one small subnet is usually cleaner than translating a whole data center. If renumbering is impossible, pick a translation range that does not overlap any current or planned range. Write it down in one table: original address, mapped address, direction, owner.
Check what your platform supports. AWS PrivateLink, Azure Private Link, and Google Cloud Private Service Connect can expose a service across overlapping networks without routing the original address. VPN gateways and firewalls differ in NAT support. Confirm connection tracking limits, throughput, and high availability before you put production traffic behind the translator.
Agree on DNS ownership. Split-horizon DNS is common: each side resolves the same name to the address valid in its own view. If you cannot split DNS, use new names for mapped services. Do not rely on search domains to fix an address conflict.
How to do it
Treat each overlapping range as a separate namespace. On a firewall, that can mean separate virtual routers or VRFs, one per namespace. In the cloud, that can mean separate VPCs or VNets with no direct route between the duplicate ranges, plus a translator or private endpoint in the middle. The point is to make it impossible for a packet to choose the wrong 10.0.1.10.
Prefer destination NAT for inbound service access and source NAT for outbound calls, or a pair when both sides need to start connections. Keep the mapping symmetric so return traffic follows the same path. If you use a private endpoint, put the service behind a load balancer and let clients connect to an endpoint address in their own range. That avoids NAT for that flow.
Put DNS and application changes in the same change window as the network change. A route that works but resolves to the old address is still broken. Test one flow at a time, then widen the scope.
- Map every overlapping subnet and flow. List subnets, owners, ports, and the side that starts each connection. Mark any app, certificate, or DNS record that contains a raw IP address. This map is the source of truth for the rest of the work.
- Pick renumbering, translation, or a private endpoint. Renumber when the range is small and the owner can move. Use NAT when both sides must keep their addresses. Use a private endpoint when one side only needs to consume a service on the other side.
- Reserve a translation range. Pick a range that is not used today and is unlikely to be used later. Record one-to-one mappings for servers and pooled mappings for clients. Do not let two translation rules claim the same address.
- Separate the routing contexts. Put duplicate ranges in different VRFs, route tables, or VPCs. Attach the translator to both contexts. Remove any broad route that would send the duplicate prefix straight across.
- Write NAT and return routes. Configure source NAT, destination NAT, or both on the translator. Add return routes on both sides for the translated addresses, not only the original ones. Check that connection tracking and timeouts fit your longest session.
- Fix DNS and app config. Create split-horizon records or new names for mapped services. Update callbacks, allow lists, and any config that embeds an IP. Change DNS TTLs before cutover so clients pick up the new answer.
- Cut over flow by flow. Start with one low-risk flow and watch it end to end. Add the next flow only after the first passes. Keep the old path available until the mapped path is stable.
How to check it worked
Check the route tables first. Each side should have one active path for a given destination, and that path should point at the translator or endpoint you expect. Look for broad routes that cover both the original and translated ranges. Run a traceroute from each side and confirm it crosses the translator.
Test from the client, not from the firewall. Open the app, run the query, upload the file, or make the call. Check the translator session table and confirm bytes flow in both directions. Capture packets on both sides of the translator to see the address change and the return path.
Test the awkward protocols. FTP in active mode, SIP, LDAP referrals, and some database replication streams carry IP addresses inside the payload. If the app writes its own address into a response, NAT alone may not fix it. Check logs and audit trails too, because they will show translated addresses unless you preserve the original in a header or log field.
Run a failover test. Kill the active translator or firewall and confirm traffic moves to the standby. Check that DNS, NAT state, and return routes survive the move. If sessions reset, decide whether that is acceptable for each app.
Mistakes to avoid
Do not assume a tunnel or peering link solves overlap. The link can be up while the route is ambiguous. Do not add a static route for a duplicate prefix and hope the longest match saves you. It will not.
Do not translate addresses without fixing DNS. Clients will keep using the old address and fail. Do not choose a translation range that overlaps a remote site or a future cloud range. That creates the same problem one layer deeper.
Do not hide the mapping in one engineer's notes. Put it in the address plan and in monitoring. Do not send every flow through a single small firewall just because it can NAT. Size the translator for peak throughput and session counts.
Do not forget return traffic. A destination NAT rule without a matching route back is a one-way flow. Do not ignore apps that embed IPs. If you need a second opinion on the design, the Expert architecture session, a one-time $450 for 90 minutes, is one option.
Frequently asked questions
Can VPC peering work with overlapping CIDR ranges?
No. AWS VPC peering and Azure VNet peering reject overlapping address spaces. You need renumbering, a private endpoint, or a translator in front of the service. A transit gateway does not remove the conflict because it still routes by prefix.
Does NAT break applications?
It can. Most client-server traffic survives source NAT, but protocols that carry IP addresses in the payload may fail. Test FTP, SIP, LDAP referrals, and any custom protocol before cutover. Destination NAT also needs matching return routes and DNS.
Should I renumber or use NAT?
Renumber when the range is small, owned by one team, and cheap to change. Use NAT when the range is large, embedded in appliances, or owned by a partner you cannot change. Private endpoints are often better when you only need to expose one service.