docs/networking/ipv6.md

# IPv6

The ISP hands out a /56 which we delegate into the VLANs via
OPNsense's track-interface mechanism. ULA (`fd4b:c0de:1::/48`) is used
for stable internal addressing that survives PD renumbering.

See also: mercemay.top/src/homelab-compose/

## Prefix plan

| VLAN | GUA prefix          | ULA prefix              |
|------|---------------------|-------------------------|
| 10   | tracked ::10/64     | fd4b:c0de:1:10::/64     |
| 20   | tracked ::20/64     | fd4b:c0de:1:20::/64     |
| 30   | tracked ::30/64     | fd4b:c0de:1:30::/64     |
| 40   | tracked ::40/64     | fd4b:c0de:1:40::/64     |
| 50   | tracked ::50/64     | fd4b:c0de:1:50::/64     |

Docker uses its default ipv6 ULA with `enable_ipv6: true` on the
`caddy-edge` bridge so Caddy can dial both stacks.

## Router advertisements

Router advertisements (RA) are assisted + stateful: SLAAC gives every
device a stable address from the ULA; DHCPv6 hands out the GUA for
LAN hosts that need stable reverse DNS.

## Firewall

- `tracked` (GUA) inbound: block all, allow only established/related.
- ULA in/out: same firewall profile as the v4 CIDR.
- ICMPv6: allow types 1, 2, 3, 4, 128-137 bidirectionally (required
  for PMTUD and ND).

## Services and v6

All Caddy sites bind `[::]:443` and `0.0.0.0:443`. Prometheus scrape
targets are written as hostnames, not IPs, so they work on both
stacks.

## Known limitations

- No native v6 to Gitea SSH: Gitea is published on 127.0.0.1:2222 and
  Caddy does not (yet) forward TCP 22 over v6. LAN clients use the
  v4 bridge address instead.
- Some *arr containers hit trackers that are v4-only; gluetun's
  wireguard endpoint is explicitly a v4 address.

## Renumber drill

Twice a year we simulate an ISP prefix change:

1. Revoke the current delegated prefix on OPNsense.
2. Wait for RA to flush.
3. Confirm that all ULA-addressed services (home DNS, *.home.arpa)
   stay reachable.
4. Re-request PD and confirm GUA recovery.