You’ll see CIDR notation everywhere in server work: 10.0.0.0/24 in a VPN config, 203.0.113.10/32 in a firewall rule, 0.0.0.0/0 meaning “everything”, /48 IPv6 allocations. Once you can read it, firewall rules, private networks and IP allocations make sense at a glance.

What CIDR means

An IPv4 address has 32 bits. A CIDR prefix like /24 says how many leading bits identify the network. The remaining bits identify hosts within it.

192.168.1.0/24
└── first 24 bits = network (192.168.1)
    last 8 bits   = hosts (0–255)

The same thing as a subnet mask: /24 = 255.255.255.0.

Cheat sheet

CIDR Subnet mask Addresses Usable hosts* Typical use
/32 255.255.255.255 1 1 (single host) One IP in firewall rules, a server’s own address
/31 255.255.255.254 2 2 Point-to-point links
/30 255.255.255.252 4 2 Small links
/29 255.255.255.248 8 6 Small IP blocks from providers
/28 255.255.255.240 16 14
/27 255.255.255.224 32 30
/26 255.255.255.192 64 62
/25 255.255.255.128 128 126
/24 255.255.255.0 256 254 Classic LAN, VPN subnet, smallest globally routed block
/23 255.255.254.0 512 510
/22 255.255.252.0 1,024 1,022
/20 255.255.240.0 4,096 4,094
/16 255.255.0.0 65,536 65,534 Large private networks, Docker defaults
/8 255.0.0.0 16,777,216 — 10.0.0.0/8 private range
/0 0.0.0.0 everything — “Any address” in firewalls and routes

*In a traditional subnet, the first address is the network address, and the last is the broadcast address, so usable hosts = addresses − 2.

Formula: addresses = 2^(32 − prefix). A /26 has 2^6 = 64.

Network, broadcast and range

For 192.168.10.77/26:

  • block size = 64, so networks start at .0, .64, .128, .192;
  • .77 falls in the .64 block;
  • network: 192.168.10.64, broadcast: 192.168.10.127, hosts: .65–.126.

Let a tool do it:

sudo apt install ipcalc
ipcalc 192.168.10.77/26

Python works too: python3 -c "import ipaddress as i; n=i.ip_network('192.168.10.77/26', strict=False); print(n, n.num_addresses, list(n.hosts())[0], list(n.hosts())[-1])".

Splitting a network

A /24 can be split into two /25s, four /26s, eight /27s, and so on. Each extra bit halves the size:

10.0.0.0/24
├── 10.0.0.0/25     (.0–.127)
└── 10.0.0.128/25   (.128–.255)

When planning private networks (VPNs, Docker networks, VPCs), choose ranges that don’t overlap with other networks you connect to. Overlapping subnets are the classic cause of “the VPN works but I can’t reach anything”. See private IP ranges.

CIDR in server configs

Firewall rules:

sudo ufw allow from 203.0.113.50/32 to any port 22   # one IP
sudo ufw allow from 10.0.0.0/24 to any port 5432     # whole private subnet

Nginx allow/deny:

allow 10.0.0.0/24;
allow 203.0.113.50;
deny all;

WireGuard AllowedIPs:

AllowedIPs = 10.8.0.2/32           # just this peer
AllowedIPs = 0.0.0.0/0, ::/0       # route everything through the tunnel

Interface addresses: ip addr add 10.0.0.5/24 dev eth1 sets the address and tells the kernel that 10.0.0.0/24 is directly reachable on eth1. See ip command.

Database access: PostgreSQL pg_hba.conf lines like host all all 10.0.0.0/24 scram-sha-256. See PostgreSQL remote connections.

IPv6 prefixes

Same idea, 128 bits:

Prefix Typical meaning
/128 Single address
/64 One network (LAN, or a VPS’s subnet). Required for SLAAC
/56 Typical home or small site allocation (256 /64s)
/48 Typical organisation allocation, and the smallest globally routed block

Providers often give a VPS a /64 or a single /128. See IPv4 vs IPv6.

Common mistakes

  • Writing a host address with a network prefix where a network is expected (10.0.0.5/24 vs 10.0.0.0/24). Some tools accept it, others reject it.
  • 0.0.0.0/0 in an allow rule when you meant one address.
  • Overlapping VPN, Docker and office subnets.
  • Forgetting IPv6 in firewall allow-lists.

Related: NAT explained and UFW.

  • Networking
  • IPv4
  • Basics