English | 简体中文 | 繁體中文 | Русский
New: Also available: Headscale server on Docker.
Headscale server installer for Ubuntu, Debian, AlmaLinux, Rocky Linux, CentOS, RHEL, Fedora and openSUSE.
This script installs and configures Headscale — a self-hosted, open-source implementation of the Tailscale coordination server. Connect all your devices using the official Tailscale client apps, with your own server in control.
See also: WireGuard, OpenVPN and IPsec VPN server auto setup scripts.
- Fully automated Headscale server setup, no user input needed
- Supports interactive install using custom options
- Supports managing users, nodes and pre-auth keys
- Downloads the official Headscale binary with checksum verification
- Installs Headscale as a systemd service with a dedicated system user
- Configures firewall rules automatically (firewalld or iptables)
- A Linux server (cloud server, VPS or dedicated server)
- A publicly reachable domain name with HTTPS is strongly recommended for production use
Note
Without HTTPS some Tailscale clients may not connect properly. See TLS and reverse proxy for setup options.
Download the script on your Linux server:
wget -O headscale.sh https://get.vpnsetup.net/hsThis URL downloads the script from a mirror I host. If you prefer, you can get it directly from GitHub:
wget -O headscale.sh https://github.com/hwdsl2/headscale-install/raw/main/headscale-install.shOption 1: Auto install with a server URL.
sudo bash headscale.sh --auto --serverurl https://hs.example.comReplace https://hs.example.com with your actual HTTPS server URL. If --serverurl is not provided, the server's public IP address is auto-detected and HTTP is used, which is not recommended for production. See TLS and reverse proxy for setup options.
Option 2: Interactive install using custom options.
sudo bash headscale.shYou can customize the following options: server URL, TCP port, initial username and MagicDNS base domain.
Click here if you are unable to download.
You may also use curl to download:
curl -fL -o headscale.sh https://github.com/hwdsl2/headscale-install/raw/main/headscale-install.shIf you are unable to download, open headscale-install.sh, then click the Raw button on the right. Press Ctrl/Cmd+A to select all, Ctrl/Cmd+C to copy, then paste into your favorite editor.
View usage information for the script.
Usage: bash headscale.sh [options]
Options:
--adduser [user name] add a new user
--deleteuser [user name] delete a user (and all their nodes and keys)
--listusers list all users
--listnodes list all registered nodes
--listnodes --user [name] list nodes for a specific user
--registernode [node key] register a node by its node key
--user [name] (requires --user <name>)
--deletenode [node ID] delete a node by its numeric ID
--createkey --user [name] create a reusable pre-auth key for a user
--listkeys list pre-auth keys
--uninstall remove Headscale and delete all configuration
-y, --yes assume "yes" as answer to prompts
-h, --help show this help message and exit
Install options (optional):
--auto auto install Headscale using default or custom options
--serverurl [URL] server URL (e.g. https://hs.example.com)
--port [number] TCP port for Headscale (1-65535, default: 8080)
--listenaddr [address] listen address (default: 0.0.0.0, use 127.0.0.1 for local only)
--username [name] name for the initial user (default: admin)
--basedomain [domain] MagicDNS base domain (default: headscale.internal)
To customize options, you may also run this script without arguments.
On first run, the script:
- Downloads and installs the Headscale binary
- Creates a
headscalesystem user and group - Writes the configuration to
/etc/headscale/config.yaml - Installs and starts the
headscalesystemd service - Creates the initial user and prints a reusable pre-auth key
Copy the pre-auth key from the output and connect a device with the official Tailscale client:
tailscale up --login-server https://hs.example.com --authkey <key-from-output>Refer to the Headscale documentation for instructions on connecting clients:
After setup, run the script again to manage your server.
Register a node by its node key:
sudo bash headscale.sh --registernode <key> --user adminAdd a user:
sudo bash headscale.sh --adduser aliceDelete a user:
sudo bash headscale.sh --deleteuser aliceCreate a pre-auth key for a user:
sudo bash headscale.sh --createkey --user aliceList all users:
sudo bash headscale.sh --listusersList all registered nodes:
sudo bash headscale.sh --listnodesList nodes for a specific user:
sudo bash headscale.sh --listnodes --user aliceDelete a node by ID:
sudo bash headscale.sh --deletenode 3List pre-auth keys:
sudo bash headscale.sh --listkeysRemove Headscale:
sudo bash headscale.sh --uninstallShow help:
sudo bash headscale.sh --helpYou may also run the script without arguments for an interactive management menu.
You can also run Headscale commands directly using headscale <command>. Run headscale -h or refer to the Headscale documentation for available commands.
Tailscale clients require HTTPS for full functionality. The recommended setup is a reverse proxy in front of Headscale that handles TLS, then pass --serverurl https://hs.example.com during install (or set server_url in /etc/headscale/config.yaml and restart the service).
When using a reverse proxy, add --listenaddr 127.0.0.1 to restrict Headscale to listen on localhost only (recommended).
Example with Caddy (automatic TLS via Let's Encrypt):
hs.example.com {
reverse_proxy localhost:8080
}
Example with nginx:
server {
listen 443 ssl;
server_name hs.example.com;
ssl_certificate /path/to/cert.pem;
ssl_certificate_key /path/to/key.pem;
location / {
proxy_pass http://127.0.0.1:8080;
proxy_set_header Host $host;
proxy_set_header X-Real-IP $remote_addr;
proxy_set_header X-Forwarded-For $proxy_add_x_forwarded_for;
proxy_set_header X-Forwarded-Proto $scheme;
proxy_read_timeout 3600s;
proxy_http_version 1.1;
proxy_set_header Upgrade $http_upgrade;
proxy_set_header Connection "upgrade";
}
}Firewall ports to open:
| Port | Protocol | Purpose |
|---|---|---|
8080 |
TCP | Headscale coordination server (or your reverse proxy port) |
443 |
TCP | HTTPS (if using a reverse proxy) |
The configuration file is at /etc/headscale/config.yaml. Edit this file to change settings such as the server URL, base domain or DNS servers, then restart the service:
sudo systemctl restart headscaleCheck service status and logs:
sudo systemctl status headscale
sudo journalctl -u headscale -n 50sudo bash headscale.sh --auto \
--serverurl https://hs.example.com \
--port 8080 \
--listenaddr 127.0.0.1 \
--username admin \
--basedomain headscale.internalAll install options are optional when using --auto. If --serverurl is not provided, the server's public IP address is auto-detected and HTTP is used (not recommended for production).
Copyright (C) 2026 Lin Song
This work is licensed under the MIT License.
Headscale is Copyright (c) 2020, Juan Font, and is distributed under the BSD 3-Clause License.
Tailscale® is a registered trademark of Tailscale Inc. This project is not affiliated with or endorsed by Tailscale Inc.