v0.29.4
drawdb-io/drawdbv0.29.4Sep 23, 2026by github-actions[bot]
Upgrading?
AI Summary
This release focuses on stabilizing Headscale with critical fixes for OIDC login, node management, and ACME renewal. It also introduces performance optimizations to the mapper to reduce unnecessary network traffic and updates policy handling for exit nodes and metadata.
Key Highlights
- Hardened OIDC callback with secure cookies and single-use authorization codes to prevent CSRF attacks.
- Mapper performance optimizations that stop redundant map broadcasts and reduce CPU usage.
- Fixed issues with expired nodes staying online, long poll connections, and ACME renewal failures.
- Support for `#`-prefixed metadata fields in policy grants, SSH rules, and node attributes.
New Features
- New metrics `headscale_mapper_changes_dropped_total` and `headscale_ha_health_updates_total`.
- CLI command `headscale users rename` fixed to work by name.
- Policy v2 support for `via` exit node capture.
- Peer map keyed by node ID for better write performance.
Full Release Notes
**Minimum supported Tailscale client version: v1.80.0** ### Changes - Fix a node being listed among its own peers in an incremental map update, which crashes the Tailscale Android app on the device list [#3459](https://github.com/juanfont/headscale/pull/3459) - Fix deleting a node leaving its long poll open, so the client stayed connected instead of asking for a new login [#3449](https://github.com/juanfont/headscale/pull/3449) - Fix interactive OIDC login when the confirmation page is reloaded by an ad blocker, back navigation, or pull-to-refresh; the confirmation page now has its own URL, keeping single-use authorization codes out of reloads [#3448](https://github.com/juanfont/headscale/pull/3448) - Harden the OIDC callback: state and nonce cookies take their Secure flag from `server_url` so they survive a TLS-terminating proxy, a callback state is single-use, and an invalid `oidc.issuer` or a missing `oidc.client_id`/`oidc.client_secret` now fails at startup [#3334](https://github.com/juanfont/headscale/pull/3334) - Fix HTTP metrics only counting `OPTIONS` requests, so `http_requests_total` and `http_request_duration_seconds` now cover regular traffic [#3414](https://github.com/juanfont/headscale/pull/3414) - Fix extra-records filewatcher hanging on shutdown after the watched file is deleted, and leaking the watcher when setup fails [#3437](https://github.com/juanfont/headscale/pull/3437) - Lowercase DNS extra record names so mixed-case records resolve [#3366](https://github.com/juanfont/headscale/pull/3366) - Fix `headscale users rename` sending the raw `--identifier` flag value instead of the matched user's identifier, so renaming by name works again [#3442](https://github.com/juanfont/headscale/pull/3442) - Fix tailsql not shutting down with headscale, leaving the process hanging on graceful shutdown [#3400](https://github.com/juanfont/headscale/pull/3400) - Fix tvOS setup instructions: install the VPN configuration before setting the coordination server URL [#3431](https://github.com/juanfont/headscale/pull/3431) - Map requests that only bump LastSeen, endpoints or DERP region no longer resend the whole node to every peer, and health probes that change nothing no longer write. Adds `headscale_mapper_changes_dropped_total` and `headscale_ha_health_updates_total` [#3417](https://github.com/juanfont/headscale/issues/3417) [#3450](https://github.com/juanfont/headscale/pull/3450) - The peer map is keyed by node ID and reused for writes that cannot change peer visibility, so a routine map request no longer rebuilds it. Adds `headscale_nodestore_snapshot_builds_total` [#3417](https://github.com/juanfont/headscale/issues/3417) [#3450](https://github.com/juanfont/headscale/pull/3450) - Fix an expired node staying online forever, because expiring it updated the key deadline without ending its map session [#3472](https://github.com/juanfont/headscale/pull/3472) - Fix ACME renewal stopping permanently after a `badNonce` reply, because the error logging middleware drained the response body the acme client needs to detect it [#3461](https://github.com/juanfont/headscale/pull/3461) - Fix `#`-prefixed metadata fields being rejected outside `acls`, so policy editors can store metadata in grants, SSH rules and `nodeAttrs` [#3481](https://github.com/juanfont/headscale/pull/3481) - Fix exit nodes not offered by recent macOS and iOS clients, which read the `suggest-exit-node` peer attribute rather than the advertised `0.0.0.0/0` routes [#3487](https://github.com/juanfont/headscale/pull/3487) - Fix exit node not offered to viewers whose only matching rule is a `via` grant; peer visibility now comes from the peer map alone [#3409](https://github.com/juanfont/headscale/pull/3409) ## Upgrade Please follow the steps outlined in the [upgrade guide](https://headscale.net/stable/setup/upgrade/) to update your existing Headscale installation. ## Changelog * 3a2b133a418d008e73b627b404c2b2465d10d4da .github/workflows: regenerate the integration test matrix * bdfa3401ff40af2ccd4ad8e1e96069640907460c AGENTS.md: drop stale line numbers * 8106636c7f8d0cf8c9d4fb0beae94415069b768b CHANGELOG: add 0.29.4 * b9b2beb78167888d3859eaf2f8dba942f6aec257 Update AppleTV configuration steps * 2a76860bdb9dcc575e694448c14a50588b2846e7 build: bump test image Go to 1.27.1 * 974becf658e09cef54f243b1407f5008ba77a270 change, mapper: distinguish deleted nodes * b3b55cc472959113d457ca99aca06cd4cd0a401b cli: fix users rename when resolved by name * 46a80ea8f915a8f27c870fe8a2c2ed8d97cf68b1 dns: cancel extra-records retry on shutdown and close watcher on setup error * 33db8c6b2940b716fb2e7bc5c848f98e8ba06b51 fix(metrics): collect metrics for non-OPTIONS requests * 032470a5d3ef04dd866f15a5f493b13e42a88e84 hscontrol: cancel tailsql on graceful shutdown * ebe18cebffb528efc53247054aa42994ece40fe5 hscontrol: keep the ACME error body readable in acmeLogger * c7d9d035006d3b44b05e8545022d4e62067a0319 hscontrol: replace tailscale line refs with doc links * 1e528f7f52c208b666d8884a1f24046fa148c324 integration: cover deletion across client versions * b9c7b4c44beec953f15c92a8feadcbe8964807ce integration: cover node deletion ending the long poll * 7783e7f679e6de1b5e28c13807e3276681725d39 integration: cover node expiry and recovery for every client * 625fa86e1ac5129903765ec0bd2fcf664022b73e integration: pin docker client to daemon API version * cc41593d9d48d99d5249f5a7bc4889a333faf7ba integration: pin which Hostinfo changes reach peers * fc894aa9da6c63f38a4b2bcea402c44f769110d2 linting issue fix * 2b8dbea41278ce5e22d35400f55f30307f557b49 mapper: assert no map response lists the recipient as its own peer * b8da1c2d6f2ccb71812d3b095d9b9b50495c28df mapper: drop empty changes before fan-out * 397149e9be086424447eb731593f6c49d2696132 mapper: stop a deleted node's map session * 9fbf7b9b6010f74c84598ac3dd973a1970b0a905 mapper: take peer visibility from the peer map only * d3882440258b0dd4742b0209ed3fcfb722f2f565 noise: make deleted-node expiry clock independent * 2b28f5756b3b5b293568b1e03f5babc21f230079 oidc: harden callback CSRF cookies, state reuse, and issuer config * cbb9357d1cb4ef43df37c7884a5fe4e826efad7b oidc: harden reloadable confirmation flow * 2da47a77d66de2e5bd52a17b7be7fab5601578ea oidc: serve the registration confirmation page from a reloadable URL * 938c2bd75303cd3f4b2c8cd3462c3a72b8e6cb8e policy,state: key the peer map by node ID * bc5b9d56b26178dee7ce9660b76fa44f9eef792c policy,types: skip recompile when the user list is unchanged * 8490631f06226a719f4106689be9e43e96a16706 policy/v2: add via exit node capture * 694bafee0a254a87e4dac629efc64d5d7b999bab policy/v2: compare peer CapMap against SaaS route captures * 5aded15bf2e53f21892decc702370346dd39876e policy/v2: suggest approved exit nodes by default * aa4c952bca9c8d55e79a930d474099b5674e4845 policy: ignore '#' metadata fields across the whole policy * fb197db16386ede870dad8d0cfb738940334fb5c poll, noise: tell a deleted node to re-authenticate * 83eff4000a97faae552b908fd08280e26e918a97 poll: interrupt blocked map writes * a7f7e6a4016b3c1e8877e60a0eae2277811105b2 servertest: compare user-owned nodes in via compat tests * 8973347d228fbf92efc86af05c4cc2be95fc7b54 state: classify map requests before broadcasting * d4b073e830f5782ebc3d637338e07e767bdc9598 state: exclude self from peers on the named peer-ID path * a91f708adc70c4fa615e8b10b82c58d086599ba5 state: mark expired nodes offline without ending the session * 0fca2bb646bb89736443344468c7fa4e8d56d941 state: preserve committed node deletion changes * fdb782daa5974b78868ae156cc81a5da9fce7870 state: rename persist helpers to say what they do * 6a0f67d56e2d031ac4f0a2cc23b644c2563a00ab state: resolve changed peers through adjacency * 237dc74e73c5aca4716da9b11f0b462eb5ec007f state: reuse peer adjacency for payload-only writes * 8f7ee375e9a608614e43925017f7164b57015587 state: skip node health writes that change nothing * b972da3fe98e17338ad6dd01f64f10fb30a3c624 state: stop broadcasting a whole peer on disconnect * e3dba1fdf9a8e88bfdd7a58fc2d318c2cd7e2d3b templates: apply the tvOS setup reorder to the served /apple page * 2b6cb3a2cceb08bed82d533c060d033e5540e330 types/change: drop unused VisibilityChange * 4411264ef992d69735e41469f51a098e778636f4 types: detect policy change on user identity and exit routes * b4f991b3814144702371213b01152cb91b22a5b1 types: lowercase DNS extra record names * e6c0a8adeeee30665c130e5c5c5468e5f4a82d6c types: regenerate node view
Related Repositories
affaan-m/ECC★ 285,766
The agent harness performance optimization system. Skills, instincts, memory, security, and research-first development for Claude Code, Codex, Opencode, Cursor and beyond.
react/react★ 251,623
The library for web and native user interfaces.
nodejs/node★ 122,519
Node.js JavaScript runtime ✨🐢🚀✨
Leonxlnx/taste-skill★ 100,612
Agent skills that give coding agents taste: art direction, reference images and a browser check instead of generic AI pages
louislam/uptime-kuma★ 92,731
A fancy self-hosted monitoring tool