GeekCoding101 make your way to geek

Private IP Address Ranges

The private IP address ranges are 10.0.0.0/8, 172.16.0.0/12 and 192.168.0.0/16 (RFC 1918). Paste any IPv4 or IPv6 address below to see whether it is private, reserved or public.

Try:

RFC 1918 private IP ranges

The table below is the whole story for most people. If an address falls in one of these three blocks, it is private.

CIDRFirst addressLast addressAddressesOld class
10.0.0.0/810.0.0.010.255.255.25516,777,216one class A
172.16.0.0/12172.16.0.0172.31.255.2551,048,57616 class B networks
192.168.0.0/16192.168.0.0192.168.255.25565,536256 class C networks

Add them up and you get 17,891,328 private addresses, about 0.4% of the IPv4 space. I computed these with Python’s ipaddress module rather than by hand, because the 172 range is the one people get wrong (more on that below).

Python printing the first address, last address and size of each RFC 1918 block

If you need to split one of these blocks into smaller networks, use the subnet calculator, and keep the subnet cheat sheet handy for the mask table.

All special-purpose IPv4 ranges

Private space is only one slice of what the IANA IPv4 Special-Purpose Address Registry (RFC 6890) sets aside. The checker above matches against all of these.

CIDRNameRFCRoutable on internet
0.0.0.0/8”This network”RFC 791No
10.0.0.0/8Private-useRFC 1918No
100.64.0.0/10Shared address space (CGNAT)RFC 6598No
127.0.0.0/8LoopbackRFC 1122No
169.254.0.0/16Link-localRFC 3927No
172.16.0.0/12Private-useRFC 1918No
192.0.0.0/24IETF protocol assignmentsRFC 6890No (two /32 exceptions)
192.0.2.0/24Documentation (TEST-NET-1)RFC 5737No
192.88.99.0/246to4 relay anycast, deprecatedRFC 3068, RFC 7526Deprecated
192.168.0.0/16Private-useRFC 1918No
198.18.0.0/15BenchmarkingRFC 2544No
198.51.100.0/24Documentation (TEST-NET-2)RFC 5737No
203.0.113.0/24Documentation (TEST-NET-3)RFC 5737No
224.0.0.0/4Multicast (class D)RFC 5771n/a
240.0.0.0/4Reserved (class E)RFC 1112No
255.255.255.255/32Limited broadcastRFC 8190No

The two exceptions in 192.0.0.0/24 are 192.0.0.9 (Port Control Protocol anycast) and 192.0.0.10 (TURN anycast). Both are globally reachable on purpose.

IPv6 special-purpose ranges

PrefixNameRFC
::1/128LoopbackRFC 4291
::/128Unspecified addressRFC 4291
::ffff:0:0/96IPv4-mapped addressRFC 4291
64:ff9b::/96NAT64 translationRFC 6052
2001:db8::/32DocumentationRFC 3849
fc00::/7Unique local address (ULA)RFC 4193
fe80::/10Link-local unicastRFC 4291
ff00::/8MulticastRFC 4291

ULA is the IPv6 answer to RFC 1918. In practice you generate a random prefix inside fd00::/8, for example fd12:3456:789a::/48, and use it for internal networks.

IP address classes (A, B, C, D, E)

Before 1993 the first bits of an address decided its network size. That scheme is called classful addressing.

ClassFirst octetLeading bitsDefault maskNetworksHosts per network
A0 to 1270255.0.0.0 (/8)128 (126 usable)16,777,214
B128 to 19110255.255.0.0 (/16)16,38465,534
C192 to 223110255.255.255.0 (/24)2,097,152254
D224 to 2391110nonen/amulticast groups
E240 to 2551111nonen/areserved

The two Class A networks that are not usable are 0.0.0.0/8 and 127.0.0.0/8. Hosts per network is 2^n minus 2, because the all-zeros address names the network and the all-ones address is the broadcast: 2^24 - 2 = 16,777,214 and 2^16 - 2 = 65,534.

Why private ranges exist

By the early 1990s it was clear that 4.3 billion addresses would not last. RFC 1918 (1996) set aside three blocks that any organization can use internally without asking a registry. Because the same addresses are reused in millions of networks, they must never be routed across the public internet. Routers on the internet drop them.

To reach the outside, a device with a private address goes through NAT. The router rewrites the source address to its own public one and keeps a table so replies come back to the right device. That is the reason your laptop and a stranger’s laptop can both be 192.168.1.20 at the same time. It is also the main reason IPv4 survived this long.

How to remember the three ranges

  • 10.x.x.x: the whole first octet is 10. Easy.
  • 192.168.x.x: the whole second octet range is free. It is what your home router uses.
  • 172.16.x.x to 172.31.x.x: the awkward one. The mask is /12, so the second octet runs from 16 to 31. Sixteen values, because 12 minus 8 leaves 4 bits.

A quick test for 172: the second octet must be 16 through 31. 172.15.255.255 and 172.32.0.0 are public.

Python is_private for 172.15.255.255, 172.16.0.0, 172.31.255.255 and 172.32.0.0

The same trick applies everywhere: the last private address in a block is one below the first public address after it. That is why the tests for this page check exactly those boundaries: 9.255.255.255, 10.0.0.0, 10.255.255.255 and 11.0.0.0 for the 10 block, and the same four edges for the others.

CGNAT: 100.64.0.0/10 is not private

Most tutorials list three private ranges. A fourth block behaves like one but is not, and it causes many “why can’t I reach my home server” tickets.

RFC 6598 reserves 100.64.0.0/10 (4,194,304 addresses) as Shared Address Space. ISPs use it for carrier-grade NAT: when they run out of public addresses, they put customers behind a second NAT layer and give the customer’s router an address from this block on its WAN side. It was carved out of the public space so that it would not collide with the private ranges a customer already uses at home.

So it is not RFC 1918 private, but it is not public either: it is not globally reachable. Python agrees, and says so with two False values.

Python reporting is_private False and is_global False for 100.64.1.1

Practical consequences:

  • If your router’s WAN address starts with 100.64 to 100.127, port forwarding will not work, because your ISP owns the NAT in front of you.
  • Tailscale also hands out addresses from 100.64.0.0/10. If your office or lab already uses that range for something else, you will see overlaps.
  • 127.0.0.0/8 loopback. Every address in it points at your own machine, not just 127.0.0.1. The traffic never touches a network card.
  • 169.254.0.0/16 link-local. If your machine has an address here, DHCP failed. Your OS picked a random one so that it can still talk to neighbors on the same cable or Wi-Fi. Check the DHCP server, the cable or the VLAN. Do not try to fix it by hand-configuring a route.
  • 192.0.2.0/24, 198.51.100.0/24, 203.0.113.0/24. The three documentation ranges, also called TEST-NET-1, 2 and 3. Use them in examples, as this site does, so nobody ever sends traffic to a stranger’s real host.
  • 198.18.0.0/15. Reserved for benchmarking network equipment. Seeing it in production usually means a testing tool or a DNS-based filter handing out fake answers.
  • 224.0.0.0/4 and 240.0.0.0/4. Multicast and reserved. Neither is valid as an ordinary host address.

Python is_private and is_global are not the RFC 1918 test

ipaddress is a convenient cross-check, but its notion of “private” is wider than RFC 1918. is_private is true for most special-purpose blocks that are not globally reachable, including loopback, link-local, TEST-NET, 198.18.0.0/15 and 240.0.0.0/4. CGNAT is the notable exception. So ip_address('127.0.0.1').is_private is True, even though 127.0.0.1 is not an RFC 1918 address.

AddressBlockPython is_privatePython is_global
10.1.2.3RFC 1918TrueFalse
100.64.1.1CGNATFalseFalse
127.0.0.1LoopbackTrueFalse
169.254.1.1Link-localTrueFalse
192.0.2.1TEST-NET-1TrueFalse
198.18.0.1BenchmarkingTrueFalse
240.0.0.1ReservedTrueFalse
8.8.8.8PublicFalseTrue
224.0.0.1MulticastFalseTrue

Two rows stand out. 100.64.1.1 is the only one with both flags False, so it is neither private nor global. And 224.0.0.1 shows is_global True in Python 3.12, although multicast is not a routable unicast address. For a strict RFC 1918 test, compare against the three networks yourself, or use the checker at the top of this page, which reports the RFC and the matching block.

How to pick a private range for a home lab, Docker or Kubernetes

The question is never “which range is allowed”, it is “which range will not collide”. Collisions happen when you connect a network to another one that picked the same range, usually through a VPN. Two networks both using 192.168.1.0/24 cannot route to each other without NAT.

Rules that work:

  1. Do not use 192.168.0.0/24 or 192.168.1.0/24 for anything that VPN clients will reach. Every consumer router defaults to one of them.
  2. Use 10.0.0.0/8 for anything serious and choose an odd slice such as 10.77.0.0/16, so it is unlikely to match an employer’s or customer’s choice.
  3. Know what your tools already take. Docker’s default bridge (docker0) is 172.17.0.0/16. In my Kubernetes tutorial, Part 4, the ip addr output on a node shows docker0 at 172.17.0.1/16 next to the Flannel interface on 10.244.x.x. Both are private, on different blocks, and they coexist because they do not overlap.
  4. Give each Kubernetes range its own block. In Part 3 of that series I initialize the cluster with --pod-network-cidr=10.244.0.0/16 (what Flannel expects) and --service-cidr=10.96.0.0/12. The pod and service ranges must not overlap each other, the node network or anything you reach over a VPN. Python can verify that in one line.
Python overlaps checks: Docker bridge inside 172.16.0.0/12, not 10.0.0.0/8, and Flannel pod CIDR against the service CIDR

The first value is True because 172.17.0.0/16 sits inside 172.16.0.0/12. The second is False. The third is False because 10.96.0.0/12 spans 10.96.0.0 to 10.111.255.255, so the pod range 10.244.0.0/16 is clear of it. If you later join this lab to a network that uses 10.96.x.x, you would have a collision on the service side, and you would have to rebuild the cluster to change it.

Checking your own address from the command line

You do not need to print your address to learn whether it is private. This asks the OS which source address it would pick to reach a documentation address (a UDP connect sends no packet) and prints only the verdict.

Python printing True for the machine's own outgoing address

True means the machine sits behind NAT with an RFC 1918 or similar address. To see the address itself, use ipconfig getifaddr en0 on macOS or ip -4 addr on Linux (neither shown here, to keep my own address out of the page). To see the address the internet sees, you need an external service, and if it differs from the local one, you are behind NAT. If the public address starts with 100.64 to 100.127, you are behind CGNAT too.

Common mistakes

  • Treating all of 172.x as private. Only 172.16.0.0 through 172.31.255.255 is. 172.32.0.0 and above is public, and so is 172.15.255.255 and below.
  • Calling 100.64.0.0/10 private. It is shared address space. Firewalls and tools that match “RFC 1918” will not match it.
  • Assuming 169.254.x.x is fine. It means DHCP failed.
  • Overlapping VPN and LAN ranges. The classic: home 192.168.1.0/24 and office 192.168.1.0/24. Renumber one side.
  • Forgetting Docker. A Docker network created on 172.17 to 172.31 can collide with a corporate 172.16.0.0/12 network and silently swallow traffic to it.
  • Using class names as sizes. Calling a /24 “a Class C” works as slang, but a 10.1.2.0/24 is a /24 carved from a class A block. Since CIDR, the prefix length is what counts.

Why CIDR replaced classes

Classful addressing wasted space. A company needing 2,000 addresses was too big for one class C (254 hosts) and got a class B (65,534), leaving over 63,000 addresses unused. Class B ran out quickly. In 1993 CIDR (RFC 4632 describes the current form) dropped the fixed boundaries: a prefix length such as /21 (2,046 hosts) can be any value, so allocations match demand and routes aggregate.

The classes still show up in exams, in the default masks some old tools assume, and in the 224.0.0.0/4 multicast and 240.0.0.0/4 reserved blocks. For anything real, write the prefix explicitly. The subnet calculator takes any address and prefix, and the subnet cheat sheet lists every mask from /8 to /32.

Frequently asked questions

What are the private IP address ranges?

RFC 1918 defines three: 10.0.0.0/8 (10.0.0.0 to 10.255.255.255), 172.16.0.0/12 (172.16.0.0 to 172.31.255.255) and 192.168.0.0/16 (192.168.0.0 to 192.168.255.255). Together they hold 17,891,328 addresses. IPv6 has the fc00::/7 unique local range instead.

Is 172.32.0.1 a private IP address?

No. The private block is 172.16.0.0/12, which ends at 172.31.255.255. 172.15.x.x and 172.32.x.x are both public addresses. Only the second octet range 16 to 31 is private.

Is 100.64.0.0/10 a private IP range?

Not in the RFC 1918 sense. RFC 6598 reserves it as Shared Address Space for carrier-grade NAT. It is not globally routable either, so it is neither private nor public. Python's ipaddress module reports is_private False and is_global False for it.

Why does my computer have a 169.254.x.x address?

169.254.0.0/16 is the IPv4 link-local range (RFC 3927). Your OS assigns itself an address from it when it asks for DHCP and gets no answer. It means the DHCP server or the link is down.

Can I use private IP addresses on the internet?

No. Routers on the public internet drop them, so a packet with a private source or destination address does not get far. Devices with private addresses reach the internet through NAT, where a router rewrites the source to its own public address.

Which private range should I use for a home lab, Docker or Kubernetes?

Pick a range that does not overlap with anything you will ever connect to by VPN. 10.0.0.0/8 has the most room, so carve something unusual out of it such as 10.77.0.0/16. Avoid 192.168.0.0/24 and 192.168.1.0/24, which almost every home router uses, and avoid 172.17.0.0/16, which Docker takes by default.

What are the IP address classes A, B, C, D and E?

Classful addressing split IPv4 by the first bits: A starts with 0 (1 to 126, mask /8), B with 10 (128 to 191, /16), C with 110 (192 to 223, /24), D with 1110 (224 to 239, multicast) and E with 1111 (240 to 255, reserved). CIDR replaced classes in 1993, but the names survive in textbooks and exams.

What does 0.0.0.0 mean?

It is in the 0.0.0.0/8 block, "this network". As a source it means a host has no address yet (a DHCP client uses it). As a listen address it means all interfaces, and in a routing table 0.0.0.0/0 is the default route.