Skip to content

IPv6 networking

Every VM gets its own public IPv6 address: the point of the whole exercise. Guests are IPv6-only (public_net.ipv4 is null, which the hcloud client tolerates). This page explains the model and how to make it work on your provider.

The model: a routed prefix

Public-address-per-VM requires an IPv6 prefix routed to the host: not NAT, and not a shared on-link /64. cloudalone's core is provider-agnostic:

  1. You give it one routed prefix via CLOUDALONE_IPV6_SLICE (e.g. a /64).
  2. It routes that prefix onto the br-cloud bridge and gives the bridge its ::1 (the VM gateway).
  3. It enables IPv6 forwarding and assigns each VM a static address via cloud-init.

That's plain L3 routing: no NDP proxying, no NAT. Packets for the prefix arrive at the host, get forwarded to br-cloud, and reach the VM; VM replies go back out through the host's uplink.

An on-link SLAAC /64 is usually not enough

Many hosts hand you a single on-link /64 via SLAAC. On some providers (e.g. Scaleway Dedibox) the upstream router will not route arbitrary addresses from that /64 to you; its uRPF filter silently drops them. You need a prefix that is genuinely routed to your host. See "Acquiring a routed prefix" below.

Per-VM addressing

Each server gets its own /96 sub-prefix of the routed prefix and uses ::1 of it, mirroring Hetzner (where a server has a /64 and the usable address is ::1). cloudalone reports public_net.ipv6.ip as that /96 network, so the hcloud CLI derives the VM's real, unique address:

hcloud server ip -6 web1     # → 2001:db8:abcd:100:0:1:0:1

::1 of the routed prefix is the bridge gateway and is skipped during allocation.

Acquiring a routed prefix

The only per-environment part is how the host obtains the routed prefix. Set ipv6_prefix in the deploy inventory to the prefix, and, on Dedibox, dhcpv6_duid.

Dedibox delivers IPv6 as a routed prefix via DHCPv6 Prefix Delegation rather than a usable on-link /64.

  1. In the console: order the free /48 block and Activate IPv6 SLAAC (required for DHCPv6 to answer). Note the DUID shown for your /56 subnet.
  2. The deploy installs a persistent DHCPv6-PD client (cloudalone-dhcpv6.service) that sends that DUID so the provider keeps the /56 routed to the box.
  3. Point ipv6_prefix at a /64 from the delegated /56 (subnet 0).
# deploy/inventory.py
"ipv6_prefix": "2001:bc8:320c:100::/64",
"dhcpv6_duid": "00:03:00:01:44:58:09:b5:91:27",

Where the provider already routes a /64 to the server, just point the config at it; no DHCPv6 client needed. Leave dhcpv6_duid unset.

"ipv6_prefix": "2a01:4f8:abcd:1234::/64",

If you control routing (a static route from your router, or a tunnel-broker /48//64), route the prefix to the host and point ipv6_prefix at the slice you want VMs to use.

Reaching a VM

ssh root@$(hcloud server ip -6 web1)
  • macOS: a bare IPv6 literal may need ssh -6 <addr> or AddressFamily inet6 in ~/.ssh/config (a client-side getaddrinfo quirk).
  • No IPv6 on your machine: jump through the host, which does have IPv6 to the VM: ssh -J root@<host> root@<vm-ipv6>.

Host survival across reboots

Enabling forwarding makes the kernel ignore Router Advertisements unless accept_ra=2; otherwise the host can lose its own default IPv6 route on reboot. The deploy persists accept_ra=2 on the uplink and recreates br-cloud via systemd-networkd, so the host and VMs come back after a reboot.