Download Latest Version headscale_0.28.0.tar.gz (59.5 MB)
Email in envelope

Get an email when there's a new version of Headscale

Home / v0.28.0
Name Modified Size InfoDownloads / Week
Parent folder
checksums.txt 2026-02-04 767 Bytes
headscale_0.28.0.tar.gz 2026-02-04 59.5 MB
headscale_0.28.0_linux_amd64 2026-02-04 53.2 MB
headscale_0.28.0_linux_amd64.deb 2026-02-04 20.1 MB
headscale_0.28.0_linux_arm64.deb 2026-02-04 18.5 MB
headscale_0.28.0_darwin_amd64 2026-02-04 53.7 MB
headscale_0.28.0_darwin_arm64 2026-02-04 50.9 MB
headscale_0.28.0_freebsd_amd64 2026-02-04 51.8 MB
headscale_0.28.0_linux_arm64 2026-02-04 50.0 MB
README.md 2026-02-04 13.8 kB
v0.28.0 source code.tar.gz 2026-02-04 987.8 kB
v0.28.0 source code.zip 2026-02-04 1.1 MB
Totals: 12 Items   360.0 MB 6

Minimum 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 the tagOwners policy and applied at registration time. Tags can be managed via the CLI or API after registration. Tagged nodes can return to user-owned by re-authenticating with tailscale up --advertise-tags= --force-reauth.

A one-time migration will validate and migrate any RequestTags (stored in hostinfo) to the tags column. Tags are validated against your policy's tagOwners rules during migration. #3011

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 #2961

Pre-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 format hskey-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

  • API: The Node message in the gRPC/REST API has been simplified - the ForcedTags, InvalidTags, and ValidTags fields have been removed and replaced with a single Tags field that contains the node's applied tags #2993
  • API clients should use the Tags field instead of ValidTags
  • The headscale nodes list CLI command now always shows a Tags column and the --tags flag has been removed
  • PreAuthKey CLI: Commands now use ID-based operations instead of user+key combinations #2992
  • headscale preauthkeys create no longer requires --user flag (optional for tracking creation)
  • headscale preauthkeys list lists all keys (no longer filtered by user)
  • headscale preauthkeys expire --id <ID> replaces --user <USER> <KEY>
  • headscale preauthkeys delete --id <ID> replaces --user <USER> <KEY>

Before:

bash headscale preauthkeys create --user 1 --reusable --tags tag:server headscale preauthkeys list --user 1 headscale preauthkeys expire --user 1 <KEY> headscale preauthkeys delete --user 1 <KEY>

After:

bash headscale preauthkeys create --reusable --tags tag:server headscale preauthkeys list headscale preauthkeys expire --id 123 headscale preauthkeys delete --id 123

  • Tags: The gRPC SetTags endpoint now allows converting user-owned nodes to tagged nodes by setting tags. #2885
  • Tags: Tags are now resolved from the node's stored Tags field only #2931
  • --advertise-tags is processed during registration, not on every policy evaluation
  • PreAuthKey tagged devices ignore --advertise-tags from clients
  • User-owned nodes can use --advertise-tags if authorized by tagOwners policy
  • 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 move CLI command has been removed
  • The MoveNode API endpoint has been removed
  • Nodes are permanently associated with their user or tag at registration time
  • Add oidc.email_verified_required config option to control email verification requirement #2860
  • When true (default), only verified emails can authenticate via OIDC in conjunction with oidc.allowed_domains or oidc.allowed_users. Previous versions allowed to authenticate with an unverified email but did not store the email address in the user profile. This is now rejected during authentication with an unverified email error.
  • When false, unverified emails are allowed for OIDC authentication and the email address is stored in the user profile regardless of its verification state.
  • SSH Policy: Wildcard (*) is no longer supported as an SSH destination #3009
  • Use autogroup:member for user-owned devices
  • Use autogroup:tagged for tagged devices
  • Use specific tags (e.g., tag:server) for targeted access

Before:

json { "action": "accept", "src": ["group:admins"], "dst": ["*"], "users": ["root"] }

After:

json { "action": "accept", "src": ["group:admins"], "dst": ["autogroup:member", "autogroup:tagged"], "users": ["root"] }

  • SSH Policy: SSH source/destination validation now enforces Tailscale's security model #3010

Per Tailscale SSH documentation, the following rules are now enforced:

  1. Tags cannot SSH to user-owned devices: SSH rules with tag:* or autogroup:tagged as source cannot have username destinations (e.g., alice@) or autogroup:member/autogroup:self as destination
  2. Username destinations require same-user source: If destination is a specific username (e.g., alice@), the source must be that exact same user only. Use autogroup:self for same-user SSH access instead

Invalid policies now rejected at load time:

```json // INVALID: tag source to user destination {"src": ["tag:server"], "dst": ["alice@"], ...}

// INVALID: autogroup:tagged to autogroup:member {"src": ["autogroup:tagged"], "dst": ["autogroup:member"], ...}

// INVALID: group to specific user (use autogroup:self instead) {"src": ["group:admins"], "dst": ["alice@"], ...} ```

Valid patterns:

```json // Users/groups can SSH to their own devices via autogroup:self {"src": ["group:admins"], "dst": ["autogroup:self"], ...}

// Users/groups can SSH to tagged devices {"src": ["group:admins"], "dst": ["autogroup:tagged"], ...}

// Tagged devices can SSH to other tagged devices {"src": ["autogroup:tagged"], "dst": ["autogroup:tagged"], ...}

// Same user can SSH to their own devices {"src": ["alice@"], "dst": ["alice@"], ...} ```

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 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.enabled configuration 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
  • Add --id flag to expire/delete commands as alternative to --prefix for API Keys #3016

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:

:::bash
# 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 headscale

Changelog

  • [7f003e] Add a page to describe supported registration methods
  • [5d3002] Add a tags page and describe a few common operations
  • [d32f67] Add missing words
  • [89e436] Bump year/version for mkdocs
  • [49b70d] Conversion from personal to tagged node is reversible
  • [04b407] Fix node expiration success message
  • [ee127e] Remove trace log for preauthkeys create
  • [2695d1] Use registration key instead of machine key
  • [44af04] all: update Go module dependencies
  • [4a744f] changelog: change api key format
  • [97fa11] changelog: set 0.28 date
  • [b5329f] flake.lock: update nixpkgs to 2026-02-03
  • [eac8a5] flake.nix: update hashes for dependency changes
  • [ca75e0] integration: add test for tagged→user-owned conversion panic
  • [a09b0d] policy/v2: add Caller() to log statements in compileACLWithAutogroupSelf
  • [1f32c8] policy/v2: add IsTagged() guards to prevent panics on tagged nodes
  • [c2f28e] policy/v2: add test for issue [#2990] same-user tagged device
  • [11f0d4] policy/v2: include nodes with empty filters in BuildPeerMap
  • [362696] policy/v2: keep partial IPSet on SSH destination resolution errors
  • [fb137a] policy/v2: use partial IPSet on group resolution errors in autogroup:self path
  • [df184e] state: fix expiry handling during node tag conversion
  • [306aab] state: fix nil pointer panic when re-registering tagged node without user
  • [4912ce] state: inline reauthExistingNode and convertTaggedNodeToUser
  • [46daa6] state: omit AuthKeyID/AuthKey in node Updates to prevent FK errors
  • [0630fd] state: refactor HandleNodeFromAuthPath for clarity
  • [ce7c25] state: set User pointer during tagged→user-owned conversion
  • [d7f7f2] state: validate tags before UpdateNode to ensure consistency
Source: README.md, updated 2026-02-04