esh-pve-nas and esh-vm-db join esh-docker-vm on 4411:b105, at :50:55 and :50:60 respectively, each applied by the same prefix-deriving if-up.d hook so the last two groups read straight off the IPv4 address. Two obstacles are recorded because both will recur. The Proxmox node had link-local only despite every relevant sysctl appearing correct, because its bridge carries per-interface forwarding and the kernel ignores router advertisements on a forwarding interface unless accept_ra is explicitly two rather than one. The fix takes the advertised prefix while declining the default route, so the hypervisor gains an address without any change to how it routes; this was verified after applying, with the v6 default route count still at zero. The database VM refuses key authentication for the privileged accounts and its unprivileged login cannot escalate without a password, so the hook went in through the QEMU guest agent from the hypervisor, which executes as root inside the guest. The document notes the base64 indirection needed to get a multi-line script through intact.
7.3 KiB
ESH IPv6 naming scheme
Every ESH LAN carries an eight-hex-digit phrase as the first half of the interface identifier. Picked 2026-08-18/19. This file is the canonical record.
Why this file exists. The scheme originally lived as a single line in
persistent-memory.mdand was silently deleted by amemory: snapshotcommit (837fa36). Recovering it took a hunt through session transcripts to find the commit that had held it. A naming convention is not temporal state — it belongs in a document, so it now is one.
The names
| network | hex | reads as |
|---|---|---|
Default |
4BA5:3417 |
A BASE FOR IT |
esh-mgmt |
15DA:B055 |
IS DA BOSS |
esh-server |
4411:B105 |
FOR ALL BIOS |
esh-userland |
CAFE:4411 |
CAFE FOR ALL |
esh-iot |
4DBA:D107 |
FOR DA BAD IOT |
esh-cameras |
1533:FACE5 |
I SEE FACES |
| (reserved) DMZ | 4411:DBAD |
FOR ALL DA BAD |
The DMZ name is claimed against a network that does not exist yet — there is no DMZ on the ESH UDM. Do not reuse it.
Substitutions are the standard hexspeak set: 0→O, 1→I/L, 5→S, plus letters
that are already native hex (A–F). Anything outside 0-9a-f is not
expressible — b0ss and c00l do not work, which is why the set above uses
B055 and avoids c00l entirely.
House style, arrived at rather than designed: eight digits, and a complete
phrase rather than a single word. Words are allowed to straddle the group
boundary (4DBA:D107 is 4·D·BAD·107); the phrase reads through the colon.
Address structure
2607:73c0:402:1d02 : 4411:b105 : 50 : 45
└──── ISP /64 ────┘ └ segment ─┘ └ 10.0.50.45 ┘
- Prefix — Cityside's, not ours to name. ESH holds a
/56(2607:73c0:402:1d00::/56, 256 × /64); the subnet id is assigned by UniFi'sipv6_pd_prefixid.esh-camerasis1d00,esh-serveris1d02. - Segment word pair — 32 bits, from the table above.
- Host — the last two IPv4 octets, written as literal digits so they read
straight off the address.
10.0.50.45→:50:45.
The scheme lives entirely in the interface identifier, so it is
delegation-size independent. It works identically on a /56, a /48, or
NH3's single /64. It never competes with the subnet id, which is far too small
to hold a word (8 bits at ESH — two hex digits).
Note: 4411:b105:50:45 fills all four host groups, so there is no :: in
these addresses. Writing ...::4411:b105:50:45 is malformed and will be
rejected.
What can and cannot carry a name
| slot | nameable? |
|---|---|
/64 subnet id (ipv6_pd_prefixid) |
No — 8 bits at ESH, two hex digits, no room for a word |
| the gateway's own address | No — fixed at ::1 by UniFi, no field for it |
| a UniFi client reservation | No — UniFi has no IPv6 equivalent of use_fixedip |
| a host taking its own address | Yes — this is the one that works |
⚠ The original note concluded these names could never appear in a dig or
ip -6 output. That is wrong. The first three rows are correct, but they only
establish that UniFi cannot assign the address. A Linux host can simply take
one within its own advertised prefix, and the router gets no vote. Appliances
with no shell — cameras, most IoT — genuinely cannot, so 1533:FACE5 and
4DBA:D107 are likely to stay documentation-only.
Applying it to a host
Do not use an iface … inet6 static stanza: on Debian that sets
accept_ra=0, killing SLAAC and the IPv6 default route — a good way to strand a
headless box. Use an if-up.d hook that derives the live prefix instead.
Live example, /etc/network/if-up.d/ipv6-scheme-addr on esh-docker-vm:
#!/bin/sh
[ "$IFACE" = ens18 ] || exit 0
(
i=0
while [ $i -lt 30 ]; do
PFX=$(ip -6 -o addr show dev "$IFACE" scope global 2>/dev/null \
| awk '{print $4}' | cut -d/ -f1 | head -1 | cut -d: -f1-4)
if [ -n "$PFX" ]; then
ip -6 addr replace "${PFX}:4411:b105:50:45/64" dev "$IFACE" && exit 0
fi
sleep 2
i=$((i + 1))
done
) >/dev/null 2>&1 &
exit 0
Three deliberate properties:
- The prefix is derived, never hardcoded — self-heals if Cityside re-delegates.
- Backgrounded with a retry — SLAAC may not have landed when
if-up.druns, and a hook that blocks or fails would stall interface bring-up. - Additive —
/etc/network/interfacesalready sourcesinterfaces.d/; nothing existing is edited, and removal is onerm.
Remaining gap: a mid-life prefix change is only picked up at the next interface-up. A timer would close it; not worth building until the prefix is observed to actually move.
Deployed
All three Linux hosts on esh-server now carry the segment name, with the last
two groups reading straight off their IPv4 address:
| host | address | v4 | applied via |
|---|---|---|---|
esh-docker-vm (AdGuard) |
2607:73c0:402:1d02:4411:b105:50:45 |
10.0.50.45 | if-up.d on ens18 |
esh-pve-nas |
2607:73c0:402:1d02:4411:b105:50:55 |
10.0.50.55 | if-up.d on vmbr0 |
esh-vm-db |
2607:73c0:402:1d02:4411:b105:50:60 |
10.0.50.60 | if-up.d on ens18 |
esh-docker-vm's is load-bearing, not decorative: the ESH UDM advertises an
IPv6 resolver to clients via RDNSS, macOS prefers it over the DHCPv4-supplied
one, so whatever sits there is what resolves *.internal for every Mac on the
network. It previously pointed at AdGuard's MAC-derived SLAAC address, which
would have broken if that VM's NIC ever changed. Both esh-userland and
esh-server now advertise the scheme address instead
(dhcpdv6_dns_auto=false + dhcpdv6_dns_1=<address>), verified on the wire by
soliciting an RA and parsing option type 25.
⚠ Proxmox bridges need accept_ra=2 or SLAAC never runs
esh-pve-nas had link-local only despite accept_ra=1, autoconf=1 and
IPv6 enabled — every sysctl looked correct. The cause: vmbr0.forwarding = 1
(Proxmox sets per-interface forwarding on bridges), and the kernel ignores RAs on
a forwarding interface unless accept_ra is explicitly 2. accept_ra=1
means "accept only if not forwarding", so it silently did nothing.
Fixed in /etc/sysctl.d/60-ipv6-accept-ra.conf on that host:
net.ipv6.conf.vmbr0.accept_ra = 2
net.ipv6.conf.vmbr0.accept_ra_defrtr = 0
accept_ra_defrtr=0 is deliberate — it takes the advertised prefix (so
SLAAC configures an address) while declining the default route, so a
hypervisor gains an IPv6 identity with no change to its routing behaviour.
Verified after: SLAAC address present, v6 default routes still 0, v4 intact.
Expect the same on any other Proxmox node when its LAN gets IPv6.
Getting into a host with no direct root
esh-vm-db refuses key auth for root and infra-ops, and lkraven's sudo
wants a password. It is VMID 101 on esh-pve, and the QEMU guest agent runs
as uid 0 inside it, so the hook was installed with:
qm guest exec 101 -- /bin/sh -c 'echo <base64> | base64 -d > /etc/network/if-up.d/... '
base64 because quoting a multi-line script through two SSH layers mangles it. Worth remembering as the general path for guests whose credentials are not vaulted.
Natural next candidates, both on esh-server and both real Linux hosts:
esh-pve-nas → …:4411:b105:50:55, esh-vm-db → …:4411:b105:50:60.