Users in Headscale organize and isolate nodes (devices) into separate namespaces. Each user owns a set of nodes and can have independent ACL policies applied.
Creating Users
Docker Command
Helper Script
Headplane GUI
docker exec headscale headscale users create USERNAME
Example: docker exec headscale headscale users create alice
docker exec headscale headscale users create bob
docker exec headscale headscale users create family
./scripts/headscale.sh users create USERNAME
Example: ./scripts/headscale.sh users create alice
Open http://localhost:3001/admin/
Go to Users page
Click Create User
Enter username
Click Save
Listing Users
Docker Command
Helper Script
Headplane GUI
docker exec headscale headscale users list
Output: ID | Name | Created
1 | alice | 2024-01-15 10:30:00
2 | bob | 2024-01-15 11:45:00
3 | family | 2024-01-16 09:00:00
./scripts/headscale.sh users list
Open http://localhost:3001/admin/
Go to Users page
View all users with their node counts
User Organization Strategies
Strategy 1: Personal Users
Create one user per person:
docker exec headscale headscale users create alice
docker exec headscale headscale users create bob
docker exec headscale headscale users create charlie
Use case : Family network where each person has their own devices.
Benefits :
Clear ownership of devices
Easy to apply per-user ACL rules
Simple to revoke access by removing a user
Strategy 2: Functional Users
Create users based on function or role:
docker exec headscale headscale users create personal
docker exec headscale headscale users create servers
docker exec headscale headscale users create iot
docker exec headscale headscale users create guests
Use case : Home lab or small business with different device types.
Benefits :
Groups similar devices together
Easier to manage device categories
Simplified ACL policies based on function
Strategy 3: Hybrid Approach
Combine personal and functional users:
# Personal users
docker exec headscale headscale users create admin
# Functional users
docker exec headscale headscale users create infrastructure
docker exec headscale headscale users create applications
docker exec headscale headscale users create guests
Use case : More complex networks with both personal and shared resources.
Managing User Devices
View Nodes by User
List All Nodes
Filter by User
Using Helper Script
docker exec headscale headscale nodes list
Using Headplane GUI
Open http://localhost:3001/admin/
Go to Users page
Click on a user to see all their devices
View device details, IP addresses, and online status
Pre-Auth Keys per User
Each user needs their own pre-auth keys to connect devices.
Create a pre-auth key for a user
Docker Command
Helper Script
Headplane GUI
docker exec headscale headscale preauthkeys create --user alice --reusable --expiration 24h
./scripts/headscale.sh keys create alice --reusable --expiration 24h
Open http://localhost:3001/admin/
Go to Pre-Auth Keys
Click Create New Key
Select user: alice
Configure options (reusable, expiration, tags)
Click Create
List keys for a user
docker exec headscale headscale preauthkeys list --user alice
Or: ./scripts/headscale.sh keys list alice
Expire a key
docker exec headscale headscale preauthkeys expire --user alice --key KEY_ID
User-Based ACL Policies
Control access between users with ACL policies in config/policy.json:
{
"acls" : [
{
"action" : "accept" ,
"src" : [ "alice" ],
"dst" : [ "bob:*" ],
"comment" : "Alice can access all of Bob's devices"
},
{
"action" : "accept" ,
"src" : [ "bob" ],
"dst" : [ "alice:80,443" ],
"comment" : "Bob can only access Alice's web services"
},
{
"action" : "accept" ,
"src" : [ "servers" ],
"dst" : [ "*:*" ],
"comment" : "Server user can access everything"
}
]
}
Example: Isolate Guest User
{
"acls" : [
{
"action" : "accept" ,
"src" : [ "guests" ],
"dst" : [ "servers:80,443" ],
"comment" : "Guests can only access web servers"
},
{
"action" : "accept" ,
"src" : [ "alice" , "bob" ],
"dst" : [ "*:*" ],
"comment" : "Regular users have full access"
}
]
}
Deleting Users
Deleting a user will remove all associated nodes and pre-auth keys. This action cannot be undone.
Delete a user
Docker Command
Helper Script
Headplane GUI
docker exec headscale headscale users destroy USERNAME
./scripts/headscale.sh users destroy USERNAME
The script will prompt for confirmation: Warning: This will delete user 'USERNAME' and all associated data
Are you sure? (yes/no):
Open http://localhost:3001/admin/
Go to Users page
Find the user
Click Delete
Confirm deletion
Verify deletion
docker exec headscale headscale users list
The deleted user should no longer appear in the list.
User Best Practices
Naming Conventions
Lowercase names : Use lowercase for consistency (alice, not Alice)
No spaces : Use hyphens or underscores (john-smith or john_smith)
Descriptive names : Make purpose clear (home-servers, guest-wifi)
Avoid special characters : Stick to letters, numbers, hyphens, and underscores
Security Recommendations
Separate Privileges Create separate users for different trust levels:
admin - Full access
personal - Your devices
guests - Limited access
iot - IoT devices with restricted access
Regular Audits Periodically review users and their devices: docker exec headscale headscale users list
docker exec headscale headscale nodes list
Short-Lived Keys Create pre-auth keys with short expiration: # 24 hours for testing
--expiration 24h
# 1 hour for production
--expiration 1h
Single-Use Keys For one-time device additions, omit --reusable: docker exec headscale headscale preauthkeys create \
--user alice \
--expiration 1h
Tag-Based Organization
Instead of creating many users, use tags within a single user:
# Create keys with tags
docker exec headscale headscale preauthkeys create \
--user admin \
--reusable \
--expiration 24h \
--tags tag:personal
docker exec headscale headscale preauthkeys create \
--user admin \
--reusable \
--expiration 24h \
--tags tag:servers
Define tag owners in config/policy.json:
{
"groups" : {
"group:admins" : []
},
"tagOwners" : {
"tag:personal" : [ "group:admins" ],
"tag:servers" : [ "group:admins" ],
"tag:guests" : [ "group:admins" ]
},
"acls" : [
{
"action" : "accept" ,
"src" : [ "tag:personal" ],
"dst" : [ "tag:servers:*" ]
}
]
}
Migration Between Users
Currently, Headscale doesn’t support moving nodes between users. To reassign a device:
Remove node from old user
docker exec headscale headscale nodes delete --identifier NODE_ID
Create new pre-auth key for target user
docker exec headscale headscale preauthkeys create --user newuser --expiration 1h
Reconnect device with new key
sudo tailscale down
sudo tailscale up --login-server http://localhost:8000 --authkey NEW_KEY
Troubleshooting
User Creation Fails
Error : “user already exists”
# List existing users to check
docker exec headscale headscale users list
# Use a different name
docker exec headscale headscale users create alice2
Cannot Delete User
Error : “user has nodes”
List user's nodes
docker exec headscale headscale nodes list | grep username
Delete all user's nodes first
docker exec headscale headscale nodes delete --identifier NODE_ID
Then delete the user
docker exec headscale headscale users destroy username
Pre-Auth Key Not Working
# Check if key exists and hasn't expired
docker exec headscale headscale preauthkeys list --user username
# Create a new key if needed
docker exec headscale headscale preauthkeys create --user username --expiration 24h
Next Steps