FIELD NOTES

Real errors hit building this, written up in case the same string lands in someone else's search results.

NOTE #01 Container restart-loop from a duplicated entrypoint
Error: unknown command "headscale" for "headscale"
CAUSEThe image's entrypoint is already headscale. Setting command: headscale serve in compose appends to that entrypoint, producing headscale headscale serve.
FIXUse command: serve instead — the binary name is already implicit.
NOTE #02 Refuses to boot with no relay map configured
Error: headscale ran into an error and had to shut down: initial DERPMap is empty, Headscale requires at least one entry
CAUSEA trimmed-down config.yaml left out the derp: block entirely. Current headscale won't start without at least one DERP entry, even if relay fallback is never expected to be used.
FIXAdd a derp: section pointing at a real DERP map, even with server.enabled set to false.
NOTE #03 Port 5000 silently unavailable on macOS
listen tcp 0.0.0.0:5000: bind: address already in use
CAUSEmacOS reserves port 5000 (and 7000) for the AirPlay Receiver service by default — nothing to do with Docker at all.
FIXMap a different host port (-p 5050:5000) rather than disabling a system service.
NOTE #04 preauthkeys --user expects an ID, not a username
invalid argument "myuser" for "-u, --user" flag: strconv.ParseUint: parsing "myuser": invalid syntax
CAUSEA breaking change between headscale versions switched some commands from username-based to numeric-ID-based user references.
FIXRun headscale users list to find the numeric ID, and use that instead of the name.
NOTE #05 The shell doesn't know placeholders are placeholders
zsh: parse error near `\n'
CAUSEText like <your-key-here> is meant to be replaced before running — but zsh reads < and > as file redirection.
FIXFully substitute placeholder text before pasting into a real shell.