{"record":{"id":"7e956c7beb7282c1","repo":"juanfont/headscale","slug":"stun-address-not-set","errorCode":null,"errorMessage":"STUN address not set","messagePattern":"STUN address not set","errorType":"validation","errorClass":null,"httpStatus":null,"severity":"critical","filePath":"hscontrol/app.go","lineNumber":53,"sourceCode":"\t\"github.com/juanfont/headscale/hscontrol/state\"\n\t\"github.com/juanfont/headscale/hscontrol/types\"\n\t\"github.com/juanfont/headscale/hscontrol/types/change\"\n\t\"github.com/juanfont/headscale/hscontrol/util\"\n\t\"github.com/pkg/profile\"\n\t\"github.com/rs/zerolog/log\"\n\t\"github.com/sasha-s/go-deadlock\"\n\t\"golang.org/x/crypto/acme\"\n\t\"golang.org/x/crypto/acme/autocert\"\n\t\"golang.org/x/sync/errgroup\"\n\t\"tailscale.com/envknob\"\n\t\"tailscale.com/tailcfg\"\n\t\"tailscale.com/types/dnstype\"\n\t\"tailscale.com/types/key\"\n\t\"tailscale.com/util/dnsname\"\n)\n\nvar (\n\terrSTUNAddressNotSet                   = errors.New(\"STUN address not set\")\n\terrUnsupportedLetsEncryptChallengeType = errors.New(\n\t\t\"unknown value for Lets Encrypt challenge type\",\n\t)\n\terrEmptyInitialDERPMap = errors.New(\n\t\t\"initial DERPMap is empty, Headscale requires at least one entry\",\n\t)\n)\n\nvar (\n\tdebugDeadlock        = envknob.Bool(\"HEADSCALE_DEBUG_DEADLOCK\")\n\tdebugDeadlockTimeout = envknob.RegisterDuration(\"HEADSCALE_DEBUG_DEADLOCK_TIMEOUT\")\n)\n\nfunc init() {\n\tdeadlock.Opts.Disable = !debugDeadlock\n\tif debugDeadlock {\n\t\tdeadlock.Opts.DeadlockTimeout = debugDeadlockTimeout()\n\t\tdeadlock.Opts.PrintAllCurrentGoroutines = true","sourceCodeStart":35,"sourceCodeEnd":71,"githubUrl":"https://github.com/juanfont/headscale/blob/565fd254d06c4c7f9a8cad1714a43445c79ba420/hscontrol/app.go#L35-L71","documentation":"Headscale returns this sentinel from Headscale.Serve() (hscontrol/app.go:552) when the embedded DERP server is enabled (derp.server.enabled) but derp.server.stun_addr is empty. The embedded DERP relay always needs a STUN server, so the config combination is rejected at startup. Nothing is started; the process fails fast before serving.","triggerScenarios":"Config file with derp.server.enabled: true and derp.server.stun_addr unset or \"\". Any invocation of headscale serve (or NewHeadscaleApp + Serve) with that combination returns errSTUNAddressNotSet at hscontrol/app.go:551-553.","commonSituations":"Enabling the embedded DERP server after a minimal config generated from an old example; YAML indentation mistakes that leave stun_addr nested under the wrong key; copying a config that only uses external DERP relays and then flipping server.enabled without adding the STUN block.","solutions":["Set derp.server.stun_addr in config.yaml (e.g. stun_addr: 0.0.0.0:3478) and ensure the UDP port is open on the host firewall","If you do not want an embedded DERP/STUN server, set derp.server.enabled: false instead and rely on derp.urls / external regions","Validate config with `headscale configtest` (or dump the parsed DERP section) before restarting the service"],"exampleFix":"# before\nderp:\n  server:\n    enabled: true\n    # stun_addr missing\n\n# after\nderp:\n  server:\n    enabled: true\n    region_id: 999\n    region_code: headscale\n    region_name: Headscale Embedded DERP\n    stun_addr: 0.0.0.0:3478","handlingStrategy":"validation","validationCode":"# before starting headscale, assert the DERP/STUN config pair:\nif grep -q 'enabled: true' <<< \"$(yq '.derp.server' /etc/headscale/config.yaml)\"; then\n  [ -n \"$(yq '.derp.server.stun_addr' /etc/headscale/config.yaml)\" ] \\\n    || { echo 'derp.server.stun_addr must be set when derp.server.enabled'; exit 1; }\nfi","typeGuard":null,"tryCatchPattern":"if err := h.Serve(); err != nil {\n    if errors.Is(err, errSTUNAddressNotSet) {\n        // config bug: fail fast with a clear operator message\n        log.Fatal().Msg(\"set derp.server.stun_addr (e.g. 0.0.0.0:3478) or disable derp.server\")\n    }\n    return err\n}","preventionTips":["Keep derp.server.enabled and derp.server.stun_addr in the same config block so they change together","Run `headscale configtest` (or parse the config in CI) before deploying","Document the STUN UDP port in firewall provisioning next to the DERP TCP port"],"tags":["config","derp","stun","startup","headscale"],"backgroundTag":null,"analyzedSha":"565fd254d06c4c7f9a8cad1714a43445c79ba420","analyzedAt":"2026-08-15T13:12:30.133Z","schemaVersion":2},"datasetVersion":"2026-08-15T22:17:37.221Z"}