name: headscale # Self-hosted Headscale coordination server (the open-source Tailscale control # plane) for the owner's tailnet, behind the central Caddy proxy at # remote.waldson.com.br. The HTTP API and the login/OIDC endpoints are reached # only through Caddy on proxy_net; Caddy transparently upgrades the long-lived # client control connections, the same as ntfy. The one thing published to the # host is STUN on 3478/udp for the embedded DERP relay. Administration is # CLI-only via `docker exec ... headscale` (see README.md for the deploy, # upgrade, and user/node runbook). The whole posture lives in the committed # config.yaml; only SQLite state and generated keys are mutable at runtime. services: headscale: # Pinned to the current minor series. Headscale is pre-1.0, so the minor is # the breaking-change axis: `pull` brings 0.29.x patches while a minor bump # (0.30) stays a deliberate tag edit. Headscale trails new Tailscale client # capabilities, so review compatibility before bumping the tag - if a client # refuses to connect after an upgrade, version skew is the first suspect. image: headscale/headscale:v0.29 # The image entrypoint is `headscale`; the server needs the `serve` # subcommand (same shape as ntfy's `serve`). command: serve restart: unless-stopped # Run as the droplet's deploy user so the SQLite db and generated private # keys in the bind mount stay owned by 1000 and are manageable over plain # SSH, matching the Syncthing and ntfy stacks. Headscale's default unix # socket lives under root-only /var/run; config.yaml relocates it into the # data dir so this non-root process can create it and the CLI still works. user: "1000:1000" volumes: # Committed posture: server URL, MagicDNS, embedded DERP. Read-only. - ./config.yaml:/etc/headscale/config.yaml:ro # SQLite database, noise/DERP private keys, and the CLI socket live here on # a host bind mount, so the instance survives recreation and is # inspectable over SSH. Git-ignored via the repo's data/ rule. - ./data:/var/lib/headscale ports: # STUN for the embedded DERP relay's NAT traversal. The relay itself and # every control connection ride Caddy's existing 443; only this UDP port # is new on the host firewall. The gRPC remote-CLI port is deliberately # not published - admin is via docker exec over the unix socket. - "3478:3478/udp" mem_limit: 256m networks: - proxy_net networks: proxy_net: external: true