IP Services

NAT on Cisco IOS XE: Static, Dynamic, and PAT Configuration

NAT on Cisco IOS XE feature image with real show ip nat translations output
In: IP Services, Fundamentals, CCNA

NAT is the reason your private 10.x network can talk to the internet, and it is also one of the CCNA topics where the terminology trips up more people than the configuration. Cisco IOS XE gives you three flavors: static NAT (one-to-one, permanent), dynamic NAT (one-to-one from a pool, on demand), and PAT (many-to-one with port rewriting, the one your home router uses). This article configures all three on a real router and reads the translation table after each one, as part of the IP Services complete guide.

Everything below was captured live from a Cisco IOS XE lab in CML: R1 is the NAT boundary router, the 10.0.20.0/24 LAN behind it is the "inside," and a Linux host at 192.168.99.100 plays the internet on the "outside." If you want the ASA version of this story, the Cisco ASA cluster covers NAT on that platform (where the logic is object-based and quite different).

The Four Address Terms That Explain Everything

Every NAT translation entry has four columns, and once you can read them, every show ip nat translations output makes sense. Here is a real entry from the static NAT demo later in this article:

R1#show ip nat translations
Pro Inside global         Inside local          Outside local         Outside global
icmp 192.168.99.50:45     10.0.20.10:45         192.168.99.100:45     192.168.99.100:45
--- 192.168.99.50         10.0.20.10            ---                   ---
Inside local

The real address of the inside host, as seen on the inside. Here: 10.0.20.10. This is what the host actually has configured.

Inside global

The translated address of the inside host, as seen from the outside. Here: 192.168.99.50. This is what the internet thinks the host is.

Outside local

The address of the outside host, as seen from the inside. Unless you are doing destination NAT, it matches outside global.

Outside global

The real address of the outside host on the outside network. Here: 192.168.99.100, the Linux host we pinged.

The mnemonic that works: "inside/outside" is where the host lives, "local/global" is where you are standing when you look at it. Local is the inside view, global is the outside view.

The Common Foundation: Interface Roles and the ACL

All three NAT types share two pieces of configuration. First, you tell IOS which interfaces face which realm:

interface Ethernet0/0
 description TO-OUTSIDE
 ip nat outside
!
interface Ethernet0/1
 description TO-INSIDE
 ip nat inside

Second, for dynamic NAT and PAT, a standard ACL defines which source addresses are allowed to be translated (the ACL here is a matching tool, not a security filter):

ip access-list standard NAT-INSIDE
 permit 10.0.20.0 0.0.0.255

Scope this ACL tightly. In this lab we learned that the hard way: with a broader ACL, even the switch management traffic got translated and replies started arriving from the wrong address (the session to the switch just died). Only match the subnets that genuinely need translation.

Static NAT: One-to-One, Both Directions

Static NAT maps one inside address to one outside address, permanently. One command:

R1(config)#ip nat inside source static 10.0.20.10 192.168.99.50

The killer feature of static NAT is that it works in both directions. Because the mapping always exists, an outside host can initiate a connection to the inside host through its global address. Here is the outside Linux host pinging 192.168.99.50 (an address that exists only in R1's NAT table):

j@llmbits:~$ ping -c 3 192.168.99.50
3 packets transmitted, 3 received, 0% packet loss, time 2003ms
rtt min/avg/max/mdev = 4.397/5.236/6.237/0.759 ms

And the translation table on R1 as those pings flow:

R1#show ip nat translations
Pro Inside global         Inside local          Outside local         Outside global
icmp 192.168.99.50:45     10.0.20.10:45         192.168.99.100:45     192.168.99.100:45
--- 192.168.99.50         10.0.20.10            ---                   ---

Two entries: the bottom one (with --- in the outside columns) is the permanent static mapping, and the top one is the live ICMP flow riding on it. This is the pattern you use for servers that must be reachable from outside (a web server in a DMZ, a mail relay, anything with a published address).

Dynamic NAT: A Pool of One-to-One Leases

Dynamic NAT keeps the one-to-one idea but assigns global addresses from a pool, on demand, only while traffic is flowing:

R1(config)#ip nat pool PUBLIC-POOL 192.168.99.60 192.168.99.69 netmask 255.255.255.0
R1(config)#ip nat inside source list NAT-INSIDE pool PUBLIC-POOL

Now an inside host (10.0.20.1 in this test) sends traffic outward:

R2#ping 192.168.99.100 source Ethernet0/0 repeat 10
Sending 10, 100-byte ICMP Echos to 192.168.99.100, timeout is 2 seconds:
Packet sent with a source address of 10.0.20.1
!!!!!!!!!!
Success rate is 100 percent (10/10), round-trip min/avg/max = 2/2/4 ms

R1 grabs the first free pool address (.60) and builds the mapping:

R1#show ip nat translations
Pro Inside global         Inside local          Outside local         Outside global
icmp 192.168.99.60:1      10.0.20.1:1           192.168.99.100:1      192.168.99.100:1
--- 192.168.99.60         10.0.20.1             ---                   ---

show ip nat statistics is where dynamic NAT gets operationally interesting, because it shows pool utilization:

R1#show ip nat statistics
Total active translations: 2 (0 static, 2 dynamic; 1 extended)
Outside interfaces:
  Ethernet0/0
Inside interfaces:
  Ethernet0/1, Ethernet0/2
Hits: 46  Misses: 0
Dynamic mappings:
-- Inside Source
[Id: 2] access-list NAT-INSIDE pool PUBLIC-POOL refcount 2
 pool PUBLIC-POOL: id 1, netmask 255.255.255.0
        start 192.168.99.60 end 192.168.99.69
        type generic, total addresses 10, allocated 1 (10%), misses 0

Watch two numbers in production: allocated (percentage of the pool in use) and misses. A miss means a host wanted a translation and the pool was empty, which means its traffic went nowhere. That is dynamic NAT's structural weakness: ten pool addresses means ten concurrent inside hosts, full stop. It is why pure dynamic NAT is rare today and PAT does the real work.

PAT: The Whole Network Behind One Address

PAT (Port Address Translation, also called NAT overload) multiplexes many inside hosts onto one global address by rewriting source ports. The typical form borrows the outside interface's own address, so you do not even need a pool:

R1(config)#ip nat inside source list NAT-INSIDE interface Ethernet0/0 overload

Here is the translation table with an ICMP flow and an SSH session (TCP 22) from the same inside host active at once:

R1#show ip nat translations
Pro Inside global         Inside local          Outside local         Outside global
icmp 192.168.99.1:1024    10.0.20.1:2           192.168.99.100:2      192.168.99.100:1024
tcp 192.168.99.1:4790     10.0.20.1:28674       192.168.99.100:22     192.168.99.100:22

Read the TCP line: the inside host's random source port 28674 became 4790 on the global address, headed to port 22 on the destination. The ICMP line shows the same trick applied to the ICMP identifier (rewritten to 1024). The port (or identifier) is what lets R1 demultiplex return traffic to thousands of inside hosts sharing a single address. Note there is no --- permanent entry this time: PAT entries exist only while flows are alive, and ICMP entries in particular age out within about a minute (run your ping and your show command close together when you lab this).

Static PAT: Port Forwarding, Cisco Style

There is a fourth variant hiding between static NAT and PAT that answers a very common requirement: publish one service on an inside host without spending a whole global address on it. Static PAT (port forwarding) maps protocol + port instead of the entire address:

R1(config)#ip nat inside source static tcp 10.0.20.10 443 192.168.99.1 8443

That says: anything arriving at the outside interface's own address on TCP 8443 gets handed to 10.0.20.10 on TCP 443. The router's address keeps doing PAT for everyone's outbound traffic at the same time; only that one inbound port is claimed. This is exactly what "port forwarding" on a home router does, and on the exam it shows up as static NAT "with the protocol keyword." Stack as many of these as you have services, all sharing one global address.

Where NAT Happens in the Packet Path

One fact explains most weird NAT symptoms: on the inside-to-outside path, IOS routes first, then translates; outside-to-inside, it translates first, then routes. Two practical consequences. First, the router needs a route for the untranslated destination before NAT ever gets a look, so broken routing shows up as "NAT not working." Second, inbound ACLs on the outside interface are evaluated against the global (pre-untranslation) addresses, so you write them in terms of the public addresses, not the inside hosts. When a translation mystery survives the show commands, debug ip nat plus a test ping shows each rewrite as it happens.

Verification, Cleanup, and a Gotcha

show ip nat translationsthe live translation table, the first thing you check
show ip nat statisticsinterface roles, hit/miss counters, pool utilization
clear ip nat translation *flush all dynamic entries (static mappings stay)
debug ip natper-packet translation events; use with care on busy boxes

The gotcha: if you try to remove a NAT rule while translations built from it are still active, IOS refuses with %Dynamic mapping in use, do you want to delete all entries? and waits for confirmation. The clean sequence is always clear ip nat translation * first, then remove the rule. If you are doing this through an automation tool that cannot answer interactive prompts, that confirmation will hang your job.

Which NAT When

Static NAT

Servers that outside hosts must reach. One-to-one, permanent, bidirectional. Costs one global address per server.

Dynamic NAT

Legacy or compliance cases needing one-to-one without fixed mappings. Limited by pool size; mostly historical.

PAT / overload

Everything else. Whole networks behind one address, outbound-initiated traffic. The default answer.

In real networks the usual combination is PAT for general outbound traffic plus a handful of static entries (full or port-level) for published services. And remember why any of this exists: the inside addresses are RFC 1918 private space, which is not routable on the internet, so something at the edge has to swap it for an address that is.

Also know what NAT costs you. It breaks true end-to-end reachability (two hosts behind different PATs cannot open connections to each other without a rendezvous service), it complicates protocols that embed addresses in their payload (classic offenders: active-mode FTP, SIP), and every translation is state the router must hold. None of that is a reason to avoid it; it is the reason IPv6 was designed to make it unnecessary, and why the IPv6 guide reads so differently on this topic.

Key Takeaways

NAT on IOS XE is three commands deep once the interface roles (ip nat inside / ip nat outside) and the match ACL are in place. Static NAT is one-to-one and works for outside-initiated connections; dynamic NAT leases one-to-one mappings from a finite pool; PAT rewrites ports to share one address and is what production networks actually run. Read translation tables with the local/global mindset (local = inside view, global = outside view), scope the NAT ACL tightly so management traffic does not get swallowed, and clear translations before you remove rules. For the rest of the day-2 services stack (DHCP, NTP, SNMP, syslog), continue with the IP Services complete guide.

Written by
More from Ping Labz
Great! You’ve successfully signed up.
Welcome back! You've successfully signed in.
You've successfully subscribed to Ping Labz.
Your link has expired.
Success! Check your email for magic link to sign-in.
Success! Your billing info has been updated.
Your billing was not updated.