Latest / Linux Server Admin with Fexingo: Sysadmin, Bash, and Server Engineering / Linux Server IPv6 Configuration with systemd-networkd
Transcript
- Lucas: If today's tech conversation gave you something usable, I want to quickly mention something behind the scenes before we dive in. Luna: Sure, what's up? Lucas: This show — and all the other Fexingo shows — stay ad-free because a small group of listeners chips in monthly through buy me a coffee dot com slash fexingo. That's it. No big sponsor, no investor. Just people who find the content useful. Luna: Yeah, and it genuinely keeps the lights on. We're not asking for anything — just acknowledging that support is what makes this possible. Lucas: Exactly. Alright — let's talk IPv6 on Linux servers with systemd-networkd. Because if you're still running pure IPv4 in 2026, you're fighting an uphill battle. Luna: Is IPv6 actually mandatory now? I've heard providers are phasing out IPv4 allocations. Lucas: They are. Amazon Web Services charges extra for public IPv4 addresses. Many ISPs in Europe and Asia assign only IPv6 by default, with carrier-grade NAT for legacy traffic. So if you're deploying a Linux server today, you need to understand how to configure IPv6 correctly. Luna: Right. And systemd-networkd is the default network manager on most modern distros like Ubuntu and Debian now. So that's what we'll focus on. Lucas: Precisely. Let's start with the simplest case: a server on a network that provides SLAAC — Stateless Address Autoconfiguration. systemd-networkd handles this out of the box with a basic.network file. Luna: What does that file look like? Lucas: You create a file like /etc/systemd/network/10-eth0.network. Inside, you write: Name=eth0, then DHCP=ipv6. That's it. systemd-networkd will listen for router advertisements and assign a global unicast address automatically. Luna: But SLAAC only gives you a /64 prefix, right? The server picks its own interface identifier based on EUI-64 or privacy extensions. Lucas: Correct. And modern Linux defaults to privacy extensions — stable privacy addresses by default, actually. You can check with 'sysctl net.ipv6.conf.eth0.use_tempaddr'. If it's 2, it generates temporary addresses for outbound connections. Luna: That's good for privacy, but sometimes you want a stable, predictable address for DNS or monitoring. So static addressing comes in. Lucas: Right. For a static IPv6 address, you add an Address= line in the section. For example: Address=2001:db8:1::100/64. And if you need a gateway, you add Gateway=2001:db8:1::1. Then you disable DHCP for IPv6 by not including DHCP=ipv6. Luna: And what about DNS? systemd-networkd can push DNS servers via router advertisements, but with static addressing you need to set them manually. Lucas: Exactly. You can add DNS=2001:db8:1::53 under. Or if you're using systemd-resolved, those get pushed automatically. One gotcha: if you set both static and DHCP, systemd-networkd merges them unless you specify DHCP=no. Luna: Let's talk about dual-stack. Most servers need both IPv4 and IPv6. How do you handle that in one.network file? Lucas: You can mix. Under, you set DHCP=ipv4 for IPv4 DHCP, and either DHCP=ipv6 for SLAAC or static Address= for IPv6. Here's a concrete example: Name=eth0, DHCP=ipv4, Address=2001:db8:1::100/64, Gateway=2001:db8:1::1, DNS=2001:db8:1::53. Luna: That gives you IPv4 from DHCP and static IPv6. Clean. But what if you want IPv6 via SLAAC and IPv4 static? Just swap the DHCP line. Lucas: Exactly. And systemd-networkd handles the ordering. One thing to watch: if your router sends a route for the default IPv6 gateway via RA, you don't need a Gateway= line for IPv6. But if you set one, it overrides the RA. Luna: What about disabling IPv6 entirely? I've seen some admins do that for simplicity. Lucas: You can, but it's a bad practice. Even if your app doesn't use IPv6, the kernel does — for things like localhost communication and some routing protocols. Disabling IPv6 can break applications like X11 forwarding over SSH or certain Docker networks. Luna: So what's the right way to limit IPv6 without completely disabling it? Lucas: Use sysctl to disable autoconfiguration on specific interfaces: net.ipv6.conf.eth0.autoconf=0 and net.ipv6.conf.eth0.accept_ra=0. That stops SLAAC and router advertisements without turning off the IPv6 stack. Luna: And if you really need to disable IPv6 globally, you can add 'ipv6.disable=1' to the kernel command line. But that's a sledgehammer. Lucas: It is. Let's talk troubleshooting. Radio — ravdump is your friend. Install radvdump and run 'radvdump' on the server. It shows the router advertisements your interface receives, including prefix, lifetime, and flags. Luna: So if your server isn't getting an IPv6 address, you can check if the RA is even reaching it? Lucas: Exactly. If ravdump shows nothing, either the router isn't sending RAs, or there's a firewall blocking ICMPv6. Remember, ICMPv6 is essential for IPv6 — don't block it. Particularly neighbor solicitations and router advertisements. Luna: What about duplicate address detection? DAD failures can be tricky. Lucas: DAD is automatic. You can see its status with 'ip -6 addr show'. If an address shows 'tentative', DAD is in progress. If it stays tentative, there's a conflict. Common cause: two interfaces on the same link with the same link-local address. Or a misconfigured router. Luna: For link-local addresses, systemd-networkd generates them automatically based on the interface MAC. But you can set a custom link-local address if needed. Lucas: Right. Under you can add LinkLocalAddress=2001:db8:ff::1/64. That overrides the default EUI-64. But honestly, I've rarely needed that in production. Luna: One more thing: systemd-networkd's IPv6 acceptance of router advertisements can be controlled per interface via the setting. Lucas: Yes. By default it's on for dhcp enabled interfaces. You can set IPv6AcceptRA=no to ignore RAs entirely. That's useful on internal networks where you manage routes statically. Luna: Let's bring it together with a real scenario. Say you're deploying a web server that needs to be reachable via IPv6. What's the minimal configuration? Lucas: Assuming your ISP provides a /56 or /64 prefix via DHCPv6-PD — prefix delegation — you'd set up your router to assign a subnet to the server. On the server, a static or SLAAC address. Then ensure your firewall allows inbound TCP port 80 and 443 on the IPv6 address. With nftables, you'd add rules for ip6 family. Luna: And test connectivity with ping6 or curl -6. Lucas: Right. 'ping -6 google.com' or 'curl -6 http://your-server'. If it fails, check routing: 'ip -6 route show'. The default route should point to your router's link-local address. Luna: One mistake I've seen: people set Gateway= to a global unicast address instead of the link-local address of the router. That doesn't work. Lucas: Exactly. The gateway must be the router's link-local address on the same link. So for eth0, that's usually fe80::1 or something similar. You can find it by running 'ip -6 neigh show' or checking the RA with radvdump. Luna: Alright, so the key takeaways: use systemd-networkd.network files, decide between SLAAC and static, don't block ICMPv6, and always verify with radvdump and ip -6. Lucas: And if you're migrating from IPv4-only, start by adding IPv6 alongside — dual-stack — before cutting over. That way you can fall back if something breaks. Luna: Good advice. Thanks Lucas. Lucas: Thanks Luna. Next time we'll dive into IPv6 firewall rules with nftables — there are some important differences from IPv4.