-
released this
2025-12-18 12:42:32 +01:00 | 8 commits to main since this release📅 Originally published on GitHub: Thu, 18 Dec 2025 11:55:06 GMT
🏷️ Git tag created: Thu, 18 Dec 2025 11:42:32 GMTMinimum supported Tailscale client version: v1.74.0
Tags as identity
Tags are now implemented following the Tailscale model where tags and user ownership are mutually exclusive. Devices can be either
user-owned (authenticated via web/OIDC) or tagged (authenticated via tagged PreAuthKeys). Tagged devices receive their identity from
tags rather than users, making them suitable for servers and infrastructure. Applying a tag to a device removes user-based
ownership. See the Tailscale tags documentation for details on how tags work.User-owned nodes can now request tags during registration using
--advertise-tags. Tags are validated against thetagOwnerspolicy
and applied at registration time. Tags can be managed via the CLI or API after registration.Smarter map updates
The map update system has been rewritten to send smaller, partial updates instead of full network maps whenever possible. This reduces bandwidth usage and improves performance, especially for large networks. The system now properly tracks peer
changes and can send removal notifications when nodes are removed due to policy changes.
#2856 #2961Pre-authentication key security improvements
Pre-authentication keys now use bcrypt hashing for improved security #2853. Keys
are stored as a prefix and bcrypt hash instead of plaintext. The full key is only displayed once at creation time. When listing keys,
only the prefix is shown (e.g.,hskey-auth-{prefix}-***). All new keys use the formathskey-auth-{prefix}-{secret}. Legacy plaintext keys in the format{secret}will continue to work for backwards compatibility.Web registration templates redesign
The OIDC callback and device registration web pages have been updated to use the Material for MkDocs design system from the official
documentation. The templates now use consistent typography, spacing, and colours across all registration flows.Database migration support removed for pre-0.25.0 databases
Headscale no longer supports direct upgrades from databases created before version 0.25.0. Users on older versions must upgrade
sequentially through each stable release, selecting the latest patch version available for each minor release.BREAKING
- Tags: The gRPC
SetTagsendpoint now allows converting user-owned nodes to tagged nodes by setting tags. Once a node is tagged, it cannot be converted back to a user-owned node. #2885 - Tags: Tags are now resolved from the node's stored Tags field only #2931
--advertise-tagsis processed during registration, not on every policy evaluation- PreAuthKey tagged devices ignore
--advertise-tagsfrom clients - User-owned nodes can use
--advertise-tagsif authorized bytagOwnerspolicy - Tags can be managed via CLI (
headscale nodes tag) or the SetTags API after registration
- Database migration support removed for pre-0.25.0 databases #2883
- If you are running a version older than 0.25.0, you must upgrade to 0.25.1 first, then upgrade to this release
- See the upgrade path documentation for detailed guidance
- In version 0.29, all migrations before 0.28.0 will also be removed
- Remove ability to move nodes between users #2922
- The
headscale nodes moveCLI command has been removed - The
MoveNodeAPI endpoint has been removed - Nodes are permanently associated with their user at registration time
- The
Changes
- Smarter change notifications send partial map updates and node removals instead of full maps #2961
- Send lightweight endpoint and DERP region updates instead of full maps #2856
- Add
oidc.email_verified_requiredconfig option to control email verification requirement #2860- When
true(default), only verified emails can authenticate via OIDC withallowed_domainsorallowed_users - When
false, unverified emails are allowed for OIDC authentication
- When
- Add NixOS module in repository for faster iteration #2857
- Add favicon to webpages #2858
- Redesign OIDC callback and registration web templates #2832
- Reclaim IPs from the IP allocator when nodes are deleted #2831
- Add bcrypt hashing for pre-authentication keys #2853
- Add prefix to API keys (
hskey-api-{prefix}-{secret}) #2853 - Add prefix to registration keys for web authentication tracking (
hskey-reg-{random}) #2853 - Tags can now be tagOwner of other tags #2930
- Add
taildrop.enabledconfiguration option to enable/disable Taildrop file sharing #2955 - Allow disabling the metrics server by setting empty
metrics_listen_addr#2914 - Log ACME/autocert errors for easier debugging #2933
- Improve CLI list output formatting #2951
- Use Debian 13 distroless base images for containers #2944
- Fix ACL policy not applied to new OIDC nodes until client restart #2890
- Fix autogroup:self preventing visibility of nodes matched by other ACL rules #2882
- Fix nodes being rejected after pre-authentication key expiration #2917
- Fix list-routes command respecting identifier filter with JSON output #2927
Upgrade
Please follow the steps outlined in the upgrade guide to update your existing Headscale installation.
It's best to update from one stable version to the next (e.g., 0.24.0 → 0.25.1 → 0.26.1) in case you are multiple releases behind. You should always pick the latest available patch release.
Be sure to check the changelog above for version-specific upgrade instructions and breaking changes.
Backup Your Database
Always backup your database before upgrading. Here's how to backup a SQLite database:
# Stop headscale systemctl stop headscale # Backup sqlite database cp /var/lib/headscale/db.sqlite /var/lib/headscale/db.sqlite.backup # Backup sqlite WAL/SHM files (if they exist) cp /var/lib/headscale/db.sqlite-wal /var/lib/headscale/db.sqlite-wal.backup cp /var/lib/headscale/db.sqlite-shm /var/lib/headscale/db.sqlite-shm.backup # Start headscale (migration will run automatically) systemctl start headscaleChangelog
c4600346f9.github/workflows: prebuilt integration test artifacts (#2954)2c3c943acf.github/workflows: split long TestAutoApproveMultiNetwork into multiple jobs5655ef86d7AGENTS: golangci-lint from main, no "full matrix"249630bed8Add API documentation14af9b3ab1Add docs to manage headscale from another local user21af106f68Containers should be read-onlya288f04a1aDockerfile: align packages9c33cbfdc8Exclude docs/ only for prettier pre-commit hook665cc44094Explicitly dropapt-get cleanand usedist-cleanc5133ee5d3Fix trailing whitespace5c6cd62df1Legacy preauthkeys must be used as-ise86d063056Mention /health instead of /windowsf00c412cdeMove static doc assets into docs/assets2010805712Provide Headscale's favicon at its expected place72d5fd04a7Remove duplicated documentation and link to getting started insteade0c9e18e22Update OIDC documentation for allowed groups filter9b327f6b56Update pre-commit-hooks6359511a62Use debian13 distroless imagesbba91a89beUse lists for integration docs218a8db1b9add favicon to webpages (#2858)6d24afba1cadd pre-commit hooks, move claude to agents. (#2877)0e1673041call: remove deadcode (#2952)56bec66a44app: only wire up debug server if set3cf2d7195aauth: ensure machines are allowed in when pak change (#2917)f3767dddf8batcher: ensure removal from batcher616c0e895dbatcher: fix closed panic7fb0f9a501batcher: send endpoint and derp only updates. (#2856)e8753619decapver: generate8394e7094acapver: update latest (#2774)5767ca5085change: smarter change notifications1dcb04ce9bchangelog: add changelog entry2aa5b8b68dchangelog: add entry for templates redesign705b239677changelog: prep for 0.27.2 rc3f0bfe28ccchangelog: prepare for 0.28.0 beta0078eb7790chore: fix filterHash to work with autogroup:self in the acls (#2882)f3f2d30004cli: better formatting of lists (#2951)16d811b306cli: remove node move command (#2922)ed78bf4b98cmd/hi: improve test cleanup to reduce CI disk usage (#2881)bfcd9d261dcmd/hi: reject if we are already running (#2919)4b25976288db: add comment to always check errors in migration1c146f70e9db: remove _schema from migration testsd2fcd5b95bdocs(tools): Add tailscale-exporterdaf9f36c78editorconfig: add basic editor config299cef4e99fix: free ips from usedIps ipset on DeleteNode5d0a6ab0e9fix: list-routes command now respects identifier filter with JSON output75e24de7bdflake: disable CGO in dev shellcf1ad47b42flake: remove hi from shell9368fee1c5generate: add new patches (#2921)87bd67318bgolangci-lint: use forbidigo to block time.Sleep (#2946)75247f82b8hscontrol/db: add init schema, drop pre-0.25 support (#2883)cb4d5b1906hscontrol/oidc: fix ACL policy not applied to new OIDC nodes (#2890)db293e0698hscontrol/state: make NodeStore batch configuration tunable (#2886)285c4e46a9hscontrol/templates: add Material for MkDocs design assets3ed1067a95hscontrol/templates: refactor to use CSS classes and embedded filesa496864762hscontrol: add template HTML consistency teste3ced80278hscontrol: consolidate assets into single package09c9762fe0hscontrol: convert BlankHandler to use elem-go1f5df017a1hscontrol: log acme/autocert errors (#2933)4e77e910c5hscontrol: use octal literal syntax in test21ba197d06integration: make entrypoint override more robusta50bd13930integration: prepare AutoApprove test for new tagsf67ed36fe2integration: replicate tag propagation issueeb788cd007make tags first class node owner (#2885)82d4275c3bmapper: correct some variable names missed from changec8376e44a2mapper: move tail node conversion to node type (#2950)eec196d200modernize: run gopls modernize to bring up to 1.25 (#2920)d14be8d43bnix: add NixOS module and tests (#2857)7be20912f5oidc: make email verification configurablef0e464dc36policy: add test to confirm group cant approve tag15c84b34e0policy: allow tags to own tags (#2930)9d77207ed8policy: clarify usernam resolve comment506bd8c8ebpolicy: more accurate node change000d5c3b0cprettier: use standard config for all files including changelog (#2879)22ee2bfc9ctags: process tags on registration, simplify policy (#2931)89285c317btemplates: migrate OIDC callback to elem-go251e16d772tools/capver: regenerate from docker tags642073f4b8types: add option to disable taildrop, improve tests (#2955)da9018a0ebtypes: make pre auth key use bcrypt (#2853)
Downloads
- Tags: The gRPC
-
released this
2025-11-30 19:10:56 +01:00 | 83 commits to main since this release📅 Originally published on GitHub: Sun, 30 Nov 2025 18:41:27 GMT
🏷️ Git tag created: Sun, 30 Nov 2025 18:10:56 GMTChanges
- Fix ACL policy not applied to new OIDC nodes until client restart
#2890 - Fix autogroup:self preventing visibility of nodes matched by other ACL rules
#2882 - Fix nodes being rejected after pre-authentication key expiration
#2917
Upgrade
Please follow the steps outlined in the upgrade guide to update your existing Headscale installation.
It's best to update from one stable version to the next (e.g., 0.24.0 → 0.25.1 → 0.26.1) in case you are multiple releases behind. You should always pick the latest available patch release.
Be sure to check the changelog above for version-specific upgrade instructions and breaking changes.
Backup Your Database
Always backup your database before upgrading. Here's how to backup a SQLite database:
# Stop headscale systemctl stop headscale # Backup sqlite database cp /var/lib/headscale/db.sqlite /var/lib/headscale/db.sqlite.backup # Backup sqlite WAL/SHM files (if they exist) cp /var/lib/headscale/db.sqlite-wal /var/lib/headscale/db.sqlite-wal.backup cp /var/lib/headscale/db.sqlite-shm /var/lib/headscale/db.sqlite-shm.backup # Start headscale (migration will run automatically) systemctl start headscaleChangelog
7f1631c4f1auth: ensure machines are allowed in when pak change (#2917)c6d399a66cchangelog: prep for 0.27.2 rc7e8cee6b10chore: fix filterHash to work with autogroup:self in the acls (#2882)4fe5cbe703hscontrol/oidc: fix ACL policy not applied to new OIDC nodes (#2890)
Downloads
- Fix ACL policy not applied to new OIDC nodes until client restart
-
released this
2025-11-11 20:17:02 +01:00 | 87 commits to main since this release📅 Originally published on GitHub: Tue, 11 Nov 2025 19:32:29 GMT
🏷️ Git tag created: Tue, 11 Nov 2025 19:17:02 GMTMinimum supported Tailscale client version: v1.64.0
Changes
- Expire nodes with a custom timestamp
#2828 - Fix issue where node expiry was reset when tailscaled restarts
#2875 - Fix OIDC authentication when multiple login URLs are opened
#2861 - Fix node re-registration failing with expired auth keys
#2859 - Remove old unused database tables and indices
#2844
#2872 - Ignore litestream tables during database validation
#2843 - Fix exit node visibility to respect ACL rules
#2855 - Fix SSH policy becoming empty when unknown user is referenced
#2874 - Fix policy validation when using bypass-grpc mode
#2854 - Fix autogroup:self interaction with other ACL rules
#2842 - Fix flaky DERP map shuffle test
#2848 - Use current stable base images for Debian and Alpine containers
#2827
Upgrade
Please follow the steps outlined in the upgrade guide to update your existing Headscale installation.
It's best to update from one stable version to the next (e.g., 0.24.0 → 0.25.1 → 0.26.1) in case you are multiple releases behind. You should always pick the latest available patch release.
Be sure to check the changelog above for version-specific upgrade instructions and breaking changes.
Backup Your Database
Always backup your database before upgrading. Here's how to backup a SQLite database:
# Stop headscale systemctl stop headscale # Backup sqlite database cp /var/lib/headscale/db.sqlite /var/lib/headscale/db.sqlite.backup # Backup sqlite WAL/SHM files (if they exist) cp /var/lib/headscale/db.sqlite-wal /var/lib/headscale/db.sqlite-wal.backup cp /var/lib/headscale/db.sqlite-shm /var/lib/headscale/db.sqlite-shm.backup # Start headscale (migration will run automatically) systemctl start headscaleChangelog
abed534628Document how to restrict access to exit nodes per user/groupd23fa26395Fix flaky TestShuffleDERPMapDeterministic by ensuring deterministic map iteration (#2848)0a43aab8f5Use Debian 12 as minimum version for the deb package4bd614a559Use current stable base images for Debian and Alpine785168a7b8changelog: prepare for 0.27.119a33394f6changelog: set 0.27 date (#2823)af2de35b6cchore: fix autogroup:self with other acl rules (#2842)02c7c1a0e7cli: only validate bypass-grpc set policy (#2854)5a2ee0c391db: add comment about removing migrations28faf8cd71db: add defensive removal of old indicies456a5d5ccedb: ignore _litestream tables when validating (#2843)ddbd3e14badb: remove all old, unused tables (#2844)f9bb88ad24expire nodes with a custom timestamp (#2828)5cd15c3656fix: make state cookies valid when client uses multiple login URLs3bd4ecd9cdfix: preserve node expiry when tailscaled restarts3455d1cb59hscontrol/db: fix RenameUser to use Updates()4a8dc2d445hscontrol/state,db: preserve node expiry on MapRequest updates4728a2ba9ehscontrol/state: allow expired auth keys for node re-registrationddd31ba774hscontrol: use Updates() instead of Save() for partial updates773a46a968integration: add test to replicate #286284fe3de251integration: reduce TestAutoApproveMultiNetwork matrix to 3 tests (#2815)d9c3eaf8c8matcher: Add func for comparing Dests and TheInternetf658a8eacdmkdocs: 0.27.1c649c89e00policy: Reproduce exit node visibility issues21e3f2598dpolicy: fix issue where non existent user results in empty ssh pola28d9bed6dpolicy: reproduce 2863 in testd7a43a7cf1state: use AllApprovedRoutes instead of SubnetRoutes2024219bd1types: Distinguish subnet and exit node accessbd9cf42b96types: NodeView CanAccess uses internal1c0bb0338dtypes: split SubnetRoutes and ExitRoutes
Downloads
- Expire nodes with a custom timestamp
-
released this
2025-10-27 11:18:57 +01:00 | 117 commits to main since this release📅 Originally published on GitHub: Mon, 27 Oct 2025 11:16:35 GMT
🏷️ Git tag created: Mon, 27 Oct 2025 10:18:57 GMTMinimum supported Tailscale client version: v1.64.0
Database integrity improvements
This release includes a significant database migration that addresses
longstanding issues with the database schema and data integrity that has
accumulated over the years. The migration introduces aschema.sqlfile as the
source of truth for the expected database schema to ensure new migrations that
will cause divergence does not occur again.These issues arose from a combination of factors discovered over time: SQLite
foreign keys not being enforced for many early versions, all migrations being
run in one large function until version 0.23.0, and inconsistent use of GORM's
AutoMigrate feature. Moving forward, all new migrations will be explicit SQL
operations rather than relying on GORM AutoMigrate, and foreign keys will be
enforced throughout the migration process.We are only improving SQLite databases with this change - PostgreSQL databases
are not affected.Please read the
PR description for more
technical details about the issues and solutions.SQLite Database Backup Example:
# Stop headscale systemctl stop headscale # Backup sqlite database cp /var/lib/headscale/db.sqlite /var/lib/headscale/db.sqlite.backup # Backup sqlite WAL/SHM files (if they exist) cp /var/lib/headscale/db.sqlite-wal /var/lib/headscale/db.sqlite-wal.backup cp /var/lib/headscale/db.sqlite-shm /var/lib/headscale/db.sqlite-shm.backup # Start headscale (migration will run automatically) systemctl start headscaleDERPMap update frequency
The default DERPMap update frequency has been changed from 24 hours to 3 hours.
If you set thederp.update_frequencyconfiguration option, it is recommended
to change it to3hto ensure that the headscale instance gets the latest
DERPMap updates when upstream is changed.Autogroups
This release adds support for the three missing autogroups:
self
(experimental),member, andtagged. Please refer to the
documentation for a detailed
explanation.autogroup:selfis marked as experimental and should be used with caution, but
we need help testing it. Experimental here means two things; first, generating
the packet filter from policies that useautogroup:selfis very expensive, and
it might perform, or straight up not work on Headscale installations with a
large number of nodes. Second, the implementation might have bugs or edge cases
we are not aware of, meaning that nodes or users might gain more access than
expected. Please report bugs.Node store (in memory database)
Under the hood, we have added a new datastructure to store nodes in memory. This
datastructure is calledNodeStoreand aims to reduce the reading and writing
of nodes to the database layer. We have not benchmarked it, but expect it to
improve performance for read heavy workloads. We think of it as, "worst case" we
have moved the bottle neck somewhere else, and "best case" we should see a good
improvement in compute resource usage at the expense of memory usage. We are
quite excited for this change and think it will make it easier for us to improve
the code base over time and make it more correct and efficient.BREAKING
- Remove support for 32-bit binaries
#2692 - Policy: Zero or empty destination port is no longer allowed
#2606 - Stricter hostname validation #2383
- Hostnames must be valid DNS labels (2-63 characters, alphanumeric and
hyphens only, cannot start/end with hyphen) - Client Registration (New Nodes): Invalid hostnames are automatically
renamed toinvalid-XXXXXXformatmy-laptop→ accepted as-isMy-Laptop→my-laptop(lowercased)my_laptop→invalid-a1b2c3(underscore not allowed)test@host→invalid-d4e5f6(@ not allowed)laptop-🚀→invalid-j1k2l3(emoji not allowed)
- Hostinfo Updates / CLI: Invalid hostnames are rejected with an error
- Valid names are accepted or lowercased
- Names with invalid characters, too short (<2), too long (>63), or
starting/ending with hyphen are rejected
- Hostnames must be valid DNS labels (2-63 characters, alphanumeric and
Changes
- Database schema migration improvements for SQLite
#2617- IMPORTANT: Backup your SQLite database before upgrading
- Introduces safer table renaming migration strategy
- Addresses longstanding database integrity issues
- Add flag to directly manipulate the policy in the database
#2765 - DERPmap update frequency default changed from 24h to 3h
#2741 - DERPmap update mechanism has been improved with retry, and is now failing
conservatively, preserving the old map upon failure.
#2741 - Add support for
autogroup:member,autogroup:tagged
#2572 - Fix bug where return routes were being removed by policy
#2767 - Remove policy v1 code #2600
- Refactor Debian/Ubuntu packaging and drop support for Ubuntu 20.04.
#2614 - Remove redundant check regarding
noiseconfig
#2658 - Refactor OpenID Connect documentation
#2625 - Don't crash if config file is missing
#2656 - Adds
/robots.txtendpoint to avoid crawlers
#2643 - OIDC: Use group claim from UserInfo
#2663 - OIDC: Update user with claims from UserInfo before comparing with allowed
groups, email and domain
#2663 - Policy will now reject invalid fields, making it easier to spot spelling
errors #2764 - Add FAQ entry on how to recover from an invalid policy in the database
#2776 - EXPERIMENTAL: Add support for
autogroup:self
#2789 - Add healthcheck command #2659
Upgrade
Please follow the steps outlined in the upgrade guide to update your existing Headscale installation.
It's best to update from one stable version to the next (e.g., 0.24.0 → 0.25.1 → 0.26.1) in case you are multiple releases behind. You should always pick the latest available patch release.
Be sure to check the changelog above for version-specific upgrade instructions and breaking changes.
Backup Your Database
Always backup your database before upgrading. Here's how to backup a SQLite database:
# Stop headscale systemctl stop headscale # Backup sqlite database cp /var/lib/headscale/db.sqlite /var/lib/headscale/db.sqlite.backup # Backup sqlite WAL/SHM files (if they exist) cp /var/lib/headscale/db.sqlite-wal /var/lib/headscale/db.sqlite-wal.backup cp /var/lib/headscale/db.sqlite-shm /var/lib/headscale/db.sqlite-shm.backup # Start headscale (migration will run automatically) systemctl start headscaleChangelog
450a7b15ec#2796: Add creation_time and ko_data_creation_time to goreleaser.yml kos64b7142e22.goreleaser: add upgrade section (#2820)c808587de0cli: do not show new pre-releases on stable (#2813)e68e2288f7gen: test-integration (#2814)52d27d58f0hscontrol: add /version HTTP endpoint (#2821)
Downloads
- Remove support for 32-bit binaries
-
released this
2025-10-23 17:57:41 +02:00 | 122 commits to main since this release📅 Originally published on GitHub: Thu, 23 Oct 2025 16:08:52 GMT
🏷️ Git tag created: Thu, 23 Oct 2025 15:57:41 GMTMinimum supported Tailscale client version: v1.64.0
Database integrity improvements
This release includes a significant database migration that addresses
longstanding issues with the database schema and data integrity that has
accumulated over the years. The migration introduces aschema.sqlfile as the
source of truth for the expected database schema to ensure new migrations that
will cause divergence does not occur again.These issues arose from a combination of factors discovered over time: SQLite
foreign keys not being enforced for many early versions, all migrations being
run in one large function until version 0.23.0, and inconsistent use of GORM's
AutoMigrate feature. Moving forward, all new migrations will be explicit SQL
operations rather than relying on GORM AutoMigrate, and foreign keys will be
enforced throughout the migration process.We are only improving SQLite databases with this change - PostgreSQL databases
are not affected.Please read the
PR description for more
technical details about the issues and solutions.SQLite Database Backup Example:
# Stop headscale systemctl stop headscale # Backup sqlite database cp /var/lib/headscale/db.sqlite /var/lib/headscale/db.sqlite.backup # Backup sqlite WAL/SHM files (if they exist) cp /var/lib/headscale/db.sqlite-wal /var/lib/headscale/db.sqlite-wal.backup cp /var/lib/headscale/db.sqlite-shm /var/lib/headscale/db.sqlite-shm.backup # Start headscale (migration will run automatically) systemctl start headscaleDERPMap update frequency
The default DERPMap update frequency has been changed from 24 hours to 3 hours.
If you set thederp.update_frequencyconfiguration option, it is recommended
to change it to3hto ensure that the headscale instance gets the latest
DERPMap updates when upstream is changed.Autogroups
This release adds support for the three missing autogroups:
self
(experimental),member, andtagged. Please refer to the
documentation for a detailed
explanation.autogroup:selfis marked as experimental and should be used with caution, but
we need help testing it. Experimental here means two things; first, generating
the packet filter from policies that useautogroup:selfis very expensive, and
it might perform, or straight up not work on Headscale installations with a
large number of nodes. Second, the implementation might have bugs or edge cases
we are not aware of, meaning that nodes or users might gain more access than
expected. Please report bugs.Node store (in memory database)
Under the hood, we have added a new datastructure to store nodes in memory. This
datastructure is calledNodeStoreand aims to reduce the reading and writing
of nodes to the database layer. We have not benchmarked it, but expect it to
improve performance for read heavy workloads. We think of it as, "worst case" we
have moved the bottle neck somewhere else, and "best case" we should see a good
improvement in compute resource usage at the expense of memory usage. We are
quite excited for this change and think it will make it easier for us to improve
the code base over time and make it more correct and efficient.BREAKING
- Remove support for 32-bit binaries
#2692 - Policy: Zero or empty destination port is no longer allowed
#2606 - Stricter hostname validation #2383
- Hostnames must be valid DNS labels (2-63 characters, alphanumeric and
hyphens only, cannot start/end with hyphen) - Client Registration (New Nodes): Invalid hostnames are automatically
renamed toinvalid-XXXXXXformatmy-laptop→ accepted as-isMy-Laptop→my-laptop(lowercased)my_laptop→invalid-a1b2c3(underscore not allowed)test@host→invalid-d4e5f6(@ not allowed)laptop-🚀→invalid-j1k2l3(emoji not allowed)
- Hostinfo Updates / CLI: Invalid hostnames are rejected with an error
- Valid names are accepted or lowercased
- Names with invalid characters, too short (<2), too long (>63), or
starting/ending with hyphen are rejected
- Hostnames must be valid DNS labels (2-63 characters, alphanumeric and
Changes
- Database schema migration improvements for SQLite
#2617- IMPORTANT: Backup your SQLite database before upgrading
- Introduces safer table renaming migration strategy
- Addresses longstanding database integrity issues
- Add flag to directly manipulate the policy in the database
#2765 - DERPmap update frequency default changed from 24h to 3h
#2741 - DERPmap update mechanism has been improved with retry, and is now failing
conservatively, preserving the old map upon failure.
#2741 - Add support for
autogroup:member,autogroup:tagged
#2572 - Fix bug where return routes were being removed by policy
#2767 - Remove policy v1 code #2600
- Refactor Debian/Ubuntu packaging and drop support for Ubuntu 20.04.
#2614 - Remove redundant check regarding
noiseconfig
#2658 - Refactor OpenID Connect documentation
#2625 - Don't crash if config file is missing
#2656 - Adds
/robots.txtendpoint to avoid crawlers
#2643 - OIDC: Use group claim from UserInfo
#2663 - OIDC: Update user with claims from UserInfo before comparing with allowed
groups, email and domain
#2663 - Policy will now reject invalid fields, making it easier to spot spelling
errors #2764 - Add FAQ entry on how to recover from an invalid policy in the database
#2776 - EXPERIMENTAL: Add support for
autogroup:self
#2789 - Add healthcheck command #2659
Changelog
047dbda136Add FAQ on how to disable log submission2a1392fb5bAdd healthcheck to container docs46477b8021Downgrade completed broadcast message to debuged38d00aaaFix autogroup:self alternative examplec97d0ff23dFix fatal error on missing config file by handling viper.ConfigFileNotFoundError8becb7e54aMention explicitly that @ is only required in policy8010cc574eRemove outdated hint about an empty config file2c9e98d3f5fix: guard every error statement with early return (#2810)66826232ffintegration: add tests for api bypass (#2811)2bf1200483policy: fix autogroup:self propagation and optimize cache invalidation (#2807)1cdea7ed9bstricter hostname validation and replace (#2383)
Downloads
- Remove support for 32-bit binaries
-
released this
2025-10-17 08:28:30 +02:00 | 133 commits to main since this release📅 Originally published on GitHub: Fri, 17 Oct 2025 07:24:08 GMT
🏷️ Git tag created: Fri, 17 Oct 2025 06:28:30 GMTMinimum supported Tailscale client version: v1.64.0
Database integrity improvements
This release includes a significant database migration that addresses
longstanding issues with the database schema and data integrity that has
accumulated over the years. The migration introduces aschema.sqlfile as the
source of truth for the expected database schema to ensure new migrations that
will cause divergence does not occur again.These issues arose from a combination of factors discovered over time: SQLite
foreign keys not being enforced for many early versions, all migrations being
run in one large function until version 0.23.0, and inconsistent use of GORM's
AutoMigrate feature. Moving forward, all new migrations will be explicit SQL
operations rather than relying on GORM AutoMigrate, and foreign keys will be
enforced throughout the migration process.We are only improving SQLite databases with this change - PostgreSQL databases
are not affected.Please read the PR description for more technical details about the issues and solutions.
SQLite Database Backup Example:
# Stop headscale systemctl stop headscale # Backup sqlite database cp /var/lib/headscale/db.sqlite /var/lib/headscale/db.sqlite.backup # Backup sqlite WAL/SHM files (if they exist) cp /var/lib/headscale/db.sqlite-wal /var/lib/headscale/db.sqlite-wal.backup cp /var/lib/headscale/db.sqlite-shm /var/lib/headscale/db.sqlite-shm.backup # Start headscale (migration will run automatically) systemctl start headscaleDERPMap update frequency
The default DERPMap update frequency has been changed from 24 hours to 3 hours.
If you set thederp.update_frequencyconfiguration option, it is recommended
to change it to3hto ensure that the headscale instance gets the latest
DERPMap updates when upstream is changed.Autogroups
This release adds support for the three missing autogroups:
self
(experimental),member, andtagged. Please refer to the
documentation for a detailed
explanation.autogroup:selfis marked as experimental and should be used with caution, but
we need help testing it. Experimental here means two things; first, generating
the packet filter from policies that useautogroup:selfis very expensive, and
it might perform, or straight up not work on Headscale installations with a
large number of nodes. Second, the implementation might have bugs or edge cases
we are not aware of, meaning that nodes or users might gain more access than
expected. Please report bugs.Node store (in memory database)
Under the hood, we have added a new datastructure to store nodes in memory. This
datastructure is calledNodeStoreand aims to reduce the reading and writing
of nodes to the database layer. We have not benchmarked it, but expect it to
improve performance for read heavy workloads. We think of it as, "worst case" we
have moved the bottle neck somewhere else, and "best case" we should see a good
improvement in compute resource usage at the expense of memory usage. We are
quite excited for this change and think it will make it easier for us to improve
the code base over time and make it more correct and efficient.BREAKING
- Remove support for 32-bit binaries
#2692 - Policy: Zero or empty destination port is no longer allowed
#2606
Changes
- Database schema migration improvements for SQLite
#2617- IMPORTANT: Backup your SQLite database before upgrading
- Introduces safer table renaming migration strategy
- Addresses longstanding database integrity issues
- Add flag to directly manipulate the policy in the database
#2765 - DERPmap update frequency default changed from 24h to 3h
#2741 - DERPmap update mechanism has been improved with retry, and is now failing
conservatively, preserving the old map upon failure.
#2741 - Add support for
autogroup:member,autogroup:tagged
#2572 - Fix bug where return routes were being removed by policy
#2767 - Remove policy v1 code #2600
- Refactor Debian/Ubuntu packaging and drop support for Ubuntu 20.04.
#2614 - Remove redundant check regarding
noiseconfig
#2658 - Refactor OpenID Connect documentation
#2625 - Don't crash if config file is missing
#2656 - Adds
/robots.txtendpoint to avoid crawlers
#2643 - OIDC: Use group claim from UserInfo
#2663 - OIDC: Update user with claims from UserInfo before comparing with allowed
groups, email and domain
#2663 - Policy will now reject invalid fields, making it easier to spot spelling
errors #2764 - Add FAQ entry on how to recover from an invalid policy in the database
#2776 - EXPERIMENTAL: Add support for
autogroup:self
#2789 - Add healthcheck command #2659
Changelog
0512f7c57e.github/ISSUE_TEMPLATE: add node number to environment05996a5048.github/workflow: only run a few selected postgres testsf6c4b338fd.github/workflows: add generate check5ba7120418.github/workflows: prettier4a8d2d9ed3.github/workflows: reduce integration retry to 37f8b14f6f3.github/workflows: remove integration retrye949859d33Add DERP docsbd35fcf338Add FAQ entry about policy migration in the database30d12dafedAdd FAQ entry about the recommended upgrade pathbcd80ee773Add debugging and troubleshooting guide76ca7a2b50Add headscale-console98fc0563acBump version in docs33e9e7a71fCLAUDE: split into agents3f72ee9de8Clarify SIGHUP log message (#2661)51c6367bb1Correctly document the default for dns.override_local_dns2f3c365b68Describe how to remove a DERP region49b3468845Do not ignore config-example.ymlc15aa541bbDocument HEADSCALE_CONFIGb50e10a1beDocument breaking change for dns.override_local_dns30cec3aa2bDocument ports in usec04e17d82eDocument valid log levelscd704570beDrop support for Ubuntu 20.0443c9c50af4Drop syslog.target and systemd-managed /var/runbe337c6a33Enable derp.server.verify_clients by defaulte73b2a9fb9Ensure that a username starts with a letter (#2635)fa619ea9f3Fix CHANGELOG for autogroup:member and autogroup:tagged (#2733)086fcad7d9Fix Internal server error on /verify (#2735)bad783321eFix/machine/mapendpoint vulnerability (#2642)46c59a3fffFix command in bug report templatea8f2eebf66Fix config param name in TLS doce7fe645be5Fix invocation of golangci-lint (#2703)3123d5286bFix typos4e6d42d5bdKeycloak's group format is configurable30a1f7e68eLog registrationID to simplify interactive node registration2d680b5ebbMisc typos and spelling5d8a2c25eaOIDC: Query userinfo endpoint before verifying user4a941a2cb4Refactor Debian/Ubuntu packaged461db3abdRefactor OpenID Connect documentationa2a6d20218Refactor to use reflect.TypeFor8ff5baadbeRefresh OIDC docsb8044c29ddReplace magic-nix-cache-action (#2575)a98d9bd05fThe preauthkeys commands expect a user id instead of a username881a6b9227The sequential prefix allocation uses a best-effort approach3fbde7a1b6Update official.md860a8a597fUpdate tools.md4d61da30d0Use an IPv4 address range suitable for documentationc6427aa296Use group id instead of group name for Entra IDc07cc491bfadd health command (#2659)7fce5065c4all: remove 32 bit support (#2692)73023c2ec3all: use immutable node view in read pathd41fb4d540app: fix sigint hanging8e25f7f9ddbunch of qol (#2748)4668e5dd96changelog: add entry for dbe7a28a14afchangelog: prepare for 0.27.0 (#2797)d29feaef79chore(derp): allow nil regions in DERPMaps630bfd265achore(derp): prioritize loading DERP maps from URLs022098fe4echore: make reg cache expiry tunable081af2674bci: fix golangci-lint flag for v2 compatibility (#2654)3950f8f171cli: use gobuild version handling (#2770)ea7376f522cmd/hi: add integration test runner CLI tool (#2648)afc11e1f0ccmd/hi: fixes and qol (#2649)3326c5b7eccmd/hi: lint and format684239e015cmd/mapresponses: add mini tool to inspect mapresp state from integration2b30a15a68cmd: add option to get and set policy directly from database (#2765)c6736dd6d6db: add sqlite "source of truth" schema50ed24847bdebug: add json and improve38be30b6d4derp: allow override to ip for debug7056fbb63bderp: fix flaky shuffle test (#2772)b87567628aderp: increase update frequency and harden on failures (#2741)3e3c72ea6fdocs(acls): Add example for allow/deny all acl policyded049b905don't crash if config file is missing (#2656)df69840f92feat(tools): Add Go client implementation6750414db1feat: add autogroup:member, autogroup:tagged (#2572)c2a58a304dfeat: add autogroup:self (#2789)d77874373dfeat: add robots.txtd325211617feat: add verify client config for embedded DERP (#2260)1605e2a7a9fix typo in TailSQL's logefc6974017fix typo in parseCapabilityVersion, and removed unused error (#2644) (#2644)43f90d205efix: allow all traffic if acls field is omited from the policy3f6657ae57fix: documentation4927e9d590fix: improve mapresponses and profiles extraction in hi toolc4a8c038cdfix: return valid AuthUrl in followup request on expired reg id3bad5d5590flake.lock: Update (#2585)6220e64978flake.lock: Update (#2669)1a7a2f4196flake.lock: Update (#2699)40b3d54c1fflake.lock: Update (#2755)d311d2e206flake: dont override gopls4de56c40d8flake: goreleaser doesnt follow go nix convention (#2779)39443184d6gen: new proto version22e6094a90golangci: disable varnamelen30525cee0egoreleaser: always do draft (#2595)a975b6a8b1hscontrol: remove go-grpc-middleware v1 dependency (#2653)9b962956b5integration: Eventually, debug output, lint and format044193bf34integration: Use Eventually around external calls (#2685)c87471136bintegration: eventually fixups (#2799)4893cdac74integration: make timestamp constc6d7b512bdintegration: replace time.Sleep with assert.EventuallyWithT (#2680)3b16b75fe6integration: rework retry for waiting for node sync9779adc0b7integration: run headscale with delve and debug symbols (#2689)306d8e1bd4integration: validate expected online status in ping233dffc186lint and leftoverb6d5788231mapper: produce map before polla058bf3cd3mapper: produce map before poll (#2628)ed3a9c8d6dmapper: send change instead of full update (#2775)ccd79ed8d4mcp: add some standard mcp serverbd6ed80936policy/v2: error on missing or zero port (#2606)ee0ef396a2policy: fix ssh usermap, fixing autogroup:nonroot (#2768)2938d03878policy: reject unsupported fields (#2764)a52f1df180policy: remove v1 code (#2600)01c1f6f82apolicy: validate error message for asterix in ssh (#2766)c91b9fc761poll: add missing godoc (#2763)b904276f2bpoll: use nodeview everywhere0303b76e1fpostgres uses more memory855c48aec2remove unneeded check (#2658)fddc7117e4stability and race conditions in auth and node store (#2781)9d236571f4state/nodestore: in memory representation of nodes476f30ab20state: ensure netinfo is preserved and not removed1553f0ab53state: introduce stateb4f7782fd8support force flag for nodes backfillips4912769ab3update dependencies (#2798)81b3e8f743util: harden parsing of tracerouted2879b2b36web: change node registration parameter order (#2607)1b1c989268{policy, node}: allow return paths in route reduction (#2767)
Downloads
- Remove support for 32-bit binaries
-
released this
2025-06-06 12:16:37 +02:00 | 257 commits to main since this release📅 Originally published on GitHub: Fri, 06 Jun 2025 11:22:02 GMT
🏷️ Git tag created: Fri, 06 Jun 2025 10:16:37 GMTSecurity fix
- Ensure nodes are matching both node key and machine key
when connecting.
#2642
Commits
474ea236d0Fix/machine/mapendpoint vulnerability (#2642)
Downloads
- Ensure nodes are matching both node key and machine key
-
released this
2025-05-14 16:45:14 +02:00 | 258 commits to main since this release📅 Originally published on GitHub: Wed, 14 May 2025 15:12:14 GMT
🏷️ Git tag created: Wed, 14 May 2025 14:45:14 GMTBREAKING
Routes
Route internals have been rewritten, removing the dedicated route table in the
database. This was done to simplify the codebase, which had grown unnecessarily
complex after the routes were split into separate tables. The overhead of having
to go via the database and keeping the state in sync made the code very hard to
reason about and prone to errors. The majority of the route state is only
relevant when headscale is running, and is now only kept in memory. As part of
this, the CLI and API has been simplified to reflect the changes;$ headscale nodes list-routes ID | Hostname | Approved | Available | Serving (Primary) 1 | ts-head-ruqsg8 | | 0.0.0.0/0, ::/0 | 2 | ts-unstable-fq7ob4 | | 0.0.0.0/0, ::/0 | $ headscale nodes approve-routes --identifier 1 --routes 0.0.0.0/0,::/0 Node updated $ headscale nodes list-routes ID | Hostname | Approved | Available | Serving (Primary) 1 | ts-head-ruqsg8 | 0.0.0.0/0, ::/0 | 0.0.0.0/0, ::/0 | 0.0.0.0/0, ::/0 2 | ts-unstable-fq7ob4 | | 0.0.0.0/0, ::/0 |Note that if an exit route is approved (0.0.0.0/0 or ::/0), both IPv4 and IPv6
will be approved.- Route API and CLI has been removed
#2422 - Routes are now managed via the Node API
#2422 - Only routes accessible to the node will be sent to the node
#2561
Policy v2
This release introduces a new policy implementation. The new policy is a
complete rewrite, and it introduces some significant quality and consistency
improvements. In principle, there are not really any new features, but some long
standing bugs should have been resolved, or be easier to fix in the future. The
new policy code passes all of our tests.Changes
- The policy is validated and "resolved" when loading, providing errors for
invalid rules and conditions.- Previously this was done as a mix between load and runtime (when it was
applied to a node). - This means that when you convert the first time, what was previously a
policy that loaded, but failed at runtime, will now fail at load time.
- Previously this was done as a mix between load and runtime (when it was
- Error messages should be more descriptive and informative.
- There is still work to be here, but it is already improved with "typing"
(e.g. only Users can be put in Groups)
- There is still work to be here, but it is already improved with "typing"
- All users must contain an
@character.- If your user naturally contains and
@, like an email, this will just work. - If its based on usernames, or other identifiers not containing an
@, an
@should be appended at the end. For example, if your user isjohn, it
must be written asjohn@in the policy.
- If your user naturally contains and
Migration notes when the policy is stored in the database.
This section only applies if the policy is stored in the database and
Headscale 0.26 doesn't start due to a policy error
(failed to load ACL policy).- Start Headscale 0.26 with the environment variable
HEADSCALE_POLICY_V1=1
set. You can check that Headscale picked up the environment variable by
observing this message during startup:Using policy manager version: 1 - Dump the policy to a file:
headscale policy get > policy.json - Edit
policy.jsonand migrate to policy V2. Use the command
headscale policy check --file policy.jsonto check for policy errors. - Load the modified policy:
headscale policy set --file policy.json - Restart Headscale without the environment variable
HEADSCALE_POLICY_V1.
Headscale should now print the messageUsing policy manager version: 2and
startup successfully.
SSH
The SSH policy has been reworked to be more consistent with the rest of the
policy. In addition, several inconsistencies between our implementation and
Tailscale's upstream has been closed and this might be a breaking change for
some users. Please refer to the
upstream documentation
for more information on which types are allowed insrc,dstandusers.There is one large inconsistency left, we allow
*as a destination as we
currently do not supportautogroup:self,autogroup:memberand
autogroup:tagged. The support for*will be removed when we have support for
the autogroups.Current state
The new policy is passing all tests, both integration and unit tests. This does
not mean it is perfect, but it is a good start. Corner cases that is currently
working in v1 and not tested might be broken in v2 (and vice versa).We do need help testing this code
Other breaking changes
- Disallow
server_urlandbase_domainto be equal
#2544 - Return full user in API for pre auth keys instead of string
#2542 - Pre auth key API/CLI now uses ID over username
#2542
Changes
- Use Go 1.24 #2427
- Add
headscale policy checkcommand to check policy
#2553 oidc.map_legacy_usersandoidc.strip_email_domainhas been removed
#2411- Add more information to
/debugendpoint
#2420- It is now possible to inspect running goroutines and take profiles
- View of config, policy, filter, ssh policy per node, connected nodes and
DERPmap
- OIDC: Fetch UserInfo to get EmailVerified if necessary
#2493- If a OIDC provider doesn't include the
email_verifiedclaim in its ID
tokens, Headscale will attempt to get it from the UserInfo endpoint.
- If a OIDC provider doesn't include the
- OIDC: Try to populate name, email and username from UserInfo
#2545 - Improve performance by only querying relevant nodes from the database for node
updates #2509 - node FQDNs in the netmap will now contain a dot (".") at the end. This aligns
with behaviour of tailscale.com
#2503 - Restore support for "Override local DNS"
#2438 - Add documentation for routes
#2496
Changelog
8c7e650616Remove map_legacy_users from example configuration (#2590)d7a503a34echangelog: entry for 0.26 (#2594)62b489dc68fix: change FormatUint base from 64 to 10 in preauthkeys list command (#2588)2dc2f3b3f0users: harden, test, and add cleaner of identifier (#2593)
Downloads
- Route API and CLI has been removed
-
released this
2025-05-10 09:49:08 +02:00 | 262 commits to main since this release📅 Originally published on GitHub: Sat, 10 May 2025 10:17:00 GMT
🏷️ Git tag created: Sat, 10 May 2025 07:49:08 GMTBREAKING
Routes
Route internals have been rewritten, removing the dedicated route table in the
database. This was done to simplify the codebase, which had grown unnecessarily
complex after the routes were split into separate tables. The overhead of having
to go via the database and keeping the state in sync made the code very hard to
reason about and prone to errors. The majority of the route state is only
relevant when headscale is running, and is now only kept in memory. As part of
this, the CLI and API has been simplified to reflect the changes;$ headscale nodes list-routes ID | Hostname | Approved | Available | Serving (Primary) 1 | ts-head-ruqsg8 | | 0.0.0.0/0, ::/0 | 2 | ts-unstable-fq7ob4 | | 0.0.0.0/0, ::/0 | $ headscale nodes approve-routes --identifier 1 --routes 0.0.0.0/0,::/0 Node updated $ headscale nodes list-routes ID | Hostname | Approved | Available | Serving (Primary) 1 | ts-head-ruqsg8 | 0.0.0.0/0, ::/0 | 0.0.0.0/0, ::/0 | 0.0.0.0/0, ::/0 2 | ts-unstable-fq7ob4 | | 0.0.0.0/0, ::/0 |Note that if an exit route is approved (0.0.0.0/0 or ::/0), both IPv4 and IPv6
will be approved.- Route API and CLI has been removed
#2422 - Routes are now managed via the Node API
#2422 - Only routes accessible to the node will be sent to the node
#2561
Policy v2
This release introduces a new policy implementation. The new policy is a
complete rewrite, and it introduces some significant quality and consistency
improvements. In principle, there are not really any new features, but some long
standing bugs should have been resolved, or be easier to fix in the future. The
new policy code passes all of our tests.Changes
- The policy is validated and "resolved" when loading, providing errors for
invalid rules and conditions.- Previously this was done as a mix between load and runtime (when it was
applied to a node). - This means that when you convert the first time, what was previously a
policy that loaded, but failed at runtime, will now fail at load time.
- Previously this was done as a mix between load and runtime (when it was
- Error messages should be more descriptive and informative.
- There is still work to be here, but it is already improved with "typing"
(e.g. only Users can be put in Groups)
- There is still work to be here, but it is already improved with "typing"
- All users must contain an
@character.- If your user naturally contains and
@, like an email, this will just work. - If its based on usernames, or other identifiers not containing an
@, an
@should be appended at the end. For example, if your user isjohn, it
must be written asjohn@in the policy.
- If your user naturally contains and
Migration notes when the policy is stored in the database.
This section only applies if the policy is stored in the database and
Headscale 0.26 doesn't start due to a policy error (failed to load ACL policy).- Start Headscale 0.26 with the environment variable
HEADSCALE_POLICY_V1=1
set. You can check that Headscale picked up the environment variable by
observing this message during startup:Using policy manager version: 1 - Dump the policy to a file:
headscale policy get > policy.json - Edit
policy.jsonand migrate to policy V2. Use the command
headscale policy check --file policy.jsonto check for policy errors. - Load the modified policy:
headscale policy set --file policy.json - Restart Headscale without the environment variable
HEADSCALE_POLICY_V1.
Headscale should now print the messageUsing policy manager version: 2and
startup successfully.
SSH
The SSH policy has been reworked to be more consistent with the rest of the
policy. In addition, several inconsistencies between our implementation and
Tailscale's upstream has been closed and this might be a breaking change for
some users. Please refer to the
upstream documentation
for more information on which types are allowed insrc,dstandusers.There is one large inconsistency left, we allow
*as a destination as we
currently do not supportautogroup:self,autogroup:memberand
autogroup:tagged. The support for*will be removed when we have support for
the autogroups.Current state
The new policy is passing all tests, both integration and unit tests. This does
not mean it is perfect, but it is a good start. Corner cases that is currently
working in v1 and not tested might be broken in v2 (and vice versa).We do need help testing this code
Other breaking changes
- Disallow
server_urlandbase_domainto be equal
#2544 - Return full user in API for pre auth keys instead of string
#2542 - Pre auth key API/CLI now uses ID over username
#2542
Changes
- Use Go 1.24 #2427
- Add
headscale policy checkcommand to check policy
#2553 oidc.map_legacy_usersandoidc.strip_email_domainhas been removed
#2411- Add more information to
/debugendpoint
#2420- It is now possible to inspect running goroutines and take profiles
- View of config, policy, filter, ssh policy per node, connected nodes and
DERPmap
- OIDC: Fetch UserInfo to get EmailVerified if necessary
#2493- If a OIDC provider doesn't include the
email_verifiedclaim in its ID
tokens, Headscale will attempt to get it from the UserInfo endpoint.
- If a OIDC provider doesn't include the
- OIDC: Try to populate name, email and username from UserInfo
#2545 - Improve performance by only querying relevant nodes from the database for node
updates #2509 - node FQDNs in the netmap will now contain a dot (".") at the end. This aligns
with behaviour of tailscale.com
#2503 - Restore support for "Override local DNS"
#2438 - Add documentation for routes
#2496
Changelog
dd0cbdf40cAdd migration steps when policy is stored in the database (#2581)833e0f66f1Remove subnet router visibility workaround from docs (#2569)d81b0053e5Simplify policy migration (#2582)43943aeee9bring back last_seen in database (#2579)377b854dd8cli: policy check, dont require config or log (#2580)37dc0dad35policy/v2: separate exit node and 0.0.0.0/0 routes (#2578)56db4ed0f1policy/v2: validate that no undefined group or tag is used (#2576)
Downloads
- Route API and CLI has been removed
-
released this
2025-05-04 22:06:44 +02:00 | 269 commits to main since this release📅 Originally published on GitHub: Sun, 04 May 2025 20:35:17 GMT
🏷️ Git tag created: Sun, 04 May 2025 20:06:44 GMTBREAKING
Routes
Route internals have been rewritten, removing the dedicated route table in the
database. This was done to simplify the codebase, which had grown unnecessarily
complex after the routes were split into separate tables. The overhead of having
to go via the database and keeping the state in sync made the code very hard to
reason about and prone to errors. The majority of the route state is only
relevant when headscale is running, and is now only kept in memory. As part of
this, the CLI and API has been simplified to reflect the changes;$ headscale nodes list-routes ID | Hostname | Approved | Available | Serving (Primary) 1 | ts-head-ruqsg8 | | 0.0.0.0/0, ::/0 | 2 | ts-unstable-fq7ob4 | | 0.0.0.0/0, ::/0 | $ headscale nodes approve-routes --identifier 1 --routes 0.0.0.0/0,::/0 Node updated $ headscale nodes list-routes ID | Hostname | Approved | Available | Serving (Primary) 1 | ts-head-ruqsg8 | 0.0.0.0/0, ::/0 | 0.0.0.0/0, ::/0 | 0.0.0.0/0, ::/0 2 | ts-unstable-fq7ob4 | | 0.0.0.0/0, ::/0 |Note that if an exit route is approved (0.0.0.0/0 or ::/0), both IPv4 and IPv6
will be approved.- Route API and CLI has been removed
#2422 - Routes are now managed via the Node API
#2422 - Only routes accessible to the node will be sent to the node
#2561
Policy v2
This release introduces a new policy implementation. The new policy is a
complete rewrite, and it introduces some significant quality and consistency
improvements. In principle, there are not really any new features, but some long
standing bugs should have been resolved, or be easier to fix in the future. The
new policy code passes all of our tests.Changes
- The policy is validated and "resolved" when loading, providing errors for
invalid rules and conditions.- Previously this was done as a mix between load and runtime (when it was
applied to a node). - This means that when you convert the first time, what was previously a
policy that loaded, but failed at runtime, will now fail at load time.
- Previously this was done as a mix between load and runtime (when it was
- Error messages should be more descriptive and informative.
- There is still work to be here, but it is already improved with "typing"
(e.g. only Users can be put in Groups)
- There is still work to be here, but it is already improved with "typing"
- All users must contain an
@character.- If your user naturally contains and
@, like an email, this will just work. - If its based on usernames, or other identifiers not containing an
@, an
@should be appended at the end. For example, if your user isjohn, it
must be written asjohn@in the policy.
- If your user naturally contains and
SSH
The SSH policy has been reworked to be more consistent with the rest of the
policy. In addition, several inconsistencies between our implementation and
Tailscale's upstream has been closed and this might be a breaking change for
some users. Please refer to the
upstream documentation
for more information on which types are allowed insrc,dstandusers.There is one large inconsistency left, we allow
*as a destination as we
currently do not supportautogroup:self,autogroup:memberand
autogroup:tagged. The support for*will be removed when we have support for
the autogroups.Current state
The new policy is passing all tests, both integration and unit tests. This does
not mean it is perfect, but it is a good start. Corner cases that is currently
working in v1 and not tested might be broken in v2 (and vice versa).We do need help testing this code
Other breaking changes
- Disallow
server_urlandbase_domainto be equal
#2544 - Return full user in API for pre auth keys instead of string
#2542 - Pre auth key API/CLI now uses ID over username
#2542
Changes
- Use Go 1.24 #2427
- Add
headscale policy checkcommand to check policy
#2553 oidc.map_legacy_usersandoidc.strip_email_domainhas been removed
#2411- Add more information to
/debugendpoint
#2420- It is now possible to inspect running goroutines and take profiles
- View of config, policy, filter, ssh policy per node, connected nodes and
DERPmap
- OIDC: Fetch UserInfo to get EmailVerified if necessary
#2493- If a OIDC provider doesn't include the
email_verifiedclaim in its ID
tokens, Headscale will attempt to get it from the UserInfo endpoint.
- If a OIDC provider doesn't include the
- OIDC: Try to populate name, email and username from UserInfo
#2545 - Improve performance by only querying relevant nodes from the database for node
updates #2509 - node FQDNs in the netmap will now contain a dot (".") at the end. This aligns
with behaviour of tailscale.com
#2503 - Restore support for "Override local DNS"
#2438 - Add documentation for routes
#2496
Changelog
586a20fbffAdd a FAQ entry about two nodes seeing each other18d21d3585Add documentation for routes (#2496)d2a6356d89Add unraid-headscale-admin web UI to docs (#2515)29ba29478bAdd usage example to routes flagfe06a00d45Container images are also available on GHCR (#2470)e52f1e87ceDrop routes table87326f5c4fExperimental implementation of Policy v2 (#2214)24ad235917Explicitly handle /headscale/{config,lib,run} in container docscb7c0173ecFix deprecation warnings (#2558)92e587a82cFix goroutine leak in EphemeralGC on node cancel (#2538)56d085bd08Fix panic on fast reconnection of node (#2536)4651d06fa8Make matchers part of the Policy interface (#2514)b9868f6516Make more granular SSH tests for both Policies (#2555)f3a1e693f2Mention "Network flow logs" as a missing feature707438f25eMention that private keys generated if needed9a86ffc102Misc doc fixes (#2562)603f3ad490Multi network integration tests (#2464)b5953d689cOIDC: Fetch UserInfo to get EmailVerified if necessary (#2493)0d3134720bOnly read relevant nodes from database in PeerChangedResponse (#2509)7891378f57Redo route code (#2422)cbce8f6011Remove coderabbit0a243b4162Remove leftover printf1e0516b99dRestore support for "Override local DNS" (#2438)05202099f7Set content-type to JSON for some debug endpoints53d9c95160Update container.md3287aa8bbaUpdate oidc.md7dc86366b4Update source.mdc61fbe9c5factivate json logs (#2424)098ab0357cadd casbin user test (#2474)818046f240add faq section on scaling/performance (#2476)3bf7d5a9c9add git hash to binary, print on startup (#2415)00d5d647edadd third-party tool headscale-pfe3521be705allow users to be defined with @ in v1 (#2495)1dddd3e93bapp: throw away not found body (#2566)eb1ecefd9eauth: ensure that routes are autoapproved when the node is stored (#2550)a4a203b9a3cli/nodes: filter nodes without any routes (#2551)93afb03f67cmd: add policy check command (#2553)30539b2e26config: disallow same server url and base_domain (#2544)109989005densure final dot on node name (#2503)c923f461aberror on undefined host in policy (#2490)03a91693acfeat: Create headscale user and group as system user/groups (#2322)5a18e91317fix auto approver on register and new policy (#2506)16868190c8fix double login URL with OIDC (#2445)da2ca054b1fix routes not being saved when new nodes registers (#2444)f1206328dcfix webauth + autoapprove routes (#2528)b3fa16fbdaflake.lock: Update (#2419)2cce3a99ebflake.lock: Update (#2430)b220fb7d51flake.lock: Update (#2440)b6fbd37539flake.lock: Update (#2454)badbb68217flake.lock: Update (#2468)f52f15ff08flake.lock: Update (#2510)9a4d0e1a99flake.lock: Update (#2518)c30e3a4762flake: add golang-lint lsp (#2507)f317a85ab4go.mod: update rest of deps (#2559)bcff0eaae7handle register auth errors (#2435)f783555469integration: clean up unreferenced hs- networks (#2534)57861507abintegration: remove failing resolvconf tests (#2549)1d65865425make version info in bug template more explicit (#2413)0fbe392499more wait, more retry (#2532)6b6509eeebnotify nodes after owner change (#2543)cfe9bbf829oidc: try to get username from userinfo (#2545)d810597414policy/matcher: fix bug using contains instead of overlap (#2556)710d75367epolicy/v2: fix host validation, consistent pattern (#2533)2b38f7bef7policy/v2: make default (#2546)e4d10ad964policy/v2: validate autogroup:interet only in dst (#2552)45e38cb080policy: reduce routes sent to peers based on packetfilter (#2561)cbc99010f0populate serving from primary routes (#2489)b92bd3d27eremove oidc migration (#2411)0b5c29e875remove policy handling for old capver (#2429)b943cce868set 0.25.0 changelog date (#2423)8e7e52cf3asome clarifications for tags (#2531)8f9fbf16f1types/authkey: include user object in response (#2542)800456018aupdate bug template with debug (#2481)e7d2d79134update capmap and deps for release (#2522)604f7f6282update to go 1.24 (#2427)1f0110fe06use helper function for constructing state updates (#2410)bbe57f6cd4use tailscale version in all unsupported errs (#2426)6403c8d5d2use tsweb debugger (#2420)
Downloads
- Route API and CLI has been removed
mirror of
https://github.com/juanfont/headscale.git
synced 2026-01-11 03:40:28 +01:00