Pakkit.net
← Back to blog

Infrastructure

How a Machine Gets an IPv6 Address

IPv6 hosts can configure themselves off a router's hints, ask a DHCPv6 server, or take a static address — and if you don't know which mechanism is in play, you'll be baffled the day a machine grabs an address you never assigned it.

  • Infrastructure
  • Networking
  • IPv6
  • Debugging

IPv4 spoiled us: a machine either had a static address you set, or it asked DHCP, and that was basically the whole story. IPv6 has three ways a host can get an address, they can be active at the same time, and the default behavior is different enough that a box will happily configure an address you never handed it. If you’ve ever deployed a server with a specific IPv6 address and found it running on a completely different one, this is the note that explains why — and how to make it take the address you actually wanted.

Before anything else, an IPv6 interface gives itself a link-local address (the fe80:: range) with no help from anyone. It’s only usable on the local link and it’s always there. Most of the time you don’t think about it, but it’s worth knowing it exists, because “the interface has an fe80:: address and nothing else” is a clear sign the global addressing step hasn’t succeeded.

The router sets the tone with Router Advertisements

The key player in IPv6 addressing is the Router Advertisement (RA) — a message the local router broadcasts saying “here’s the network prefix, here’s how to configure yourselves.” Hosts listen for RAs and act on the flags inside them. Those flags decide which of the mechanisms below a host uses, which is why the router’s configuration, not just the host’s, shapes what address a machine ends up with. That indirection is the source of a lot of surprise.

The three mechanisms

  • SLAAC (Stateless Address Autoconfiguration). The host hears the RA’s prefix and builds its own address from it — no server involved. Classically it derived the host part from the interface’s MAC (EUI-64), though modern systems generate randomized privacy addresses instead. This is the default, self-service path: give a host a network with a router advertising a prefix and it’ll configure a working global address on its own.
  • DHCPv6. The stateful, IPv4-DHCP-like path: a server hands out addresses from a pool and tracks who has what. Used when you want central control over exactly which host gets which address. Notably, a host generally only uses DHCPv6 if the RA’s flags tell it to — so DHCPv6 and the router are a package deal.
  • Static. You configure the address by hand (or via provisioning tooling), the same as IPv4. This is what you want for servers that need a known, stable address — but, crucially, a static config often has to also say “and don’t accept the router’s autoconfiguration,” or the host will take a static address and a SLAAC address at once.

The mental model: SLAAC is the host configuring itself off the router’s hint; DHCPv6 is the host asking a server; static is you deciding. And unlike IPv4, more than one of these can be in effect on the same interface simultaneously.

The failure that trips everyone: silent SLAAC fallback

Here’s the gotcha that motivated me to write this down. You deploy a server with a static IPv6 address baked into its config, and it comes up with a totally different address — a SLAAC one, derived off the router’s prefix. The static address you specified is nowhere to be seen.

What’s usually happening: the static network config failed to apply for some reason, and IPv6’s default helpfulness kicked in — the interface heard the router’s advertisement and autoconfigured itself via SLAAC as a fallback. In IPv4, a failed static config leaves you with no address and an obvious problem. In IPv6, a failed static config can leave you with a working address you never chose, which is far more confusing, because the machine is reachable — just not where you told it to be. It’s a textbook silent fallback: the system quietly did something reasonable instead of failing loudly, and hid the real problem.

If you provision machines automatically, this bites at first boot, because the network config is racing to apply while the interface is already hearing RAs — a close cousin of how first-boot automation races the network.

How to get the address you actually want

For a server that needs a specific, stable IPv6 address:

  • Set the static address and disable autoconfiguration on that interface (turn off accepting RAs / SLAAC for it), so the host can’t also pick up a prefix-derived address behind your back.
  • Verify what the interface actually has, not what you configured — list the interface’s addresses and confirm it holds only the static one (plus its link-local), with no surprise global SLAAC address alongside it.
  • If you see a SLAAC address where you expected your static one, suspect the static config never applied — the SLAAC address is the fallback, not the failure. Go find why the intended config didn’t take rather than fighting the address you see.
  • Remember the router is half the story. What a host does depends on the RA flags, so “why is this host on DHCPv6 / SLAAC” sometimes has its answer on the router, not the host.

Why it’s worth knowing

IPv6 addressing feels flaky until you realize it’s not flaky — it’s automatic, and automatic means a host will do something sensible even when you wanted it to do something specific. Knowing the three mechanisms and the RA that arbitrates them turns “why is this box on the wrong address” from a mystery into a two-minute check: which mechanism is active, did my intended one apply, and is the router telling hosts something I didn’t expect. IPv6 rewards knowing how the address got there — because half the time, the machine chose it, not you. If you’ve chased down a phantom IPv6 address, I’d like to hear where it came from.