tailscale
tailscale ≥ 1.60.0- Binary
tailscale- Minimum
1.60.0- Probed with
tailscale version- Tested
- 1.98.41.102.4
A terminal UI (TUI) for tailscale and headscale on Linux. Self-hosted Tailscale from the terminal, both ends of it: the Headscale control plane on this host, and this machine as a tailnet node.

Self-hosted Tailscale from the terminal, both ends of it: the Headscale control plane on this host, and this machine as a tailnet node.
The node screens show the state, login server, addresses and routes, and the peers. j joins (this host's control plane offered first, join profiles pre-filling every step), with a pre-auth key that never touches a command line, and trusts a private CA when the server's certificate needs one, offering the CAs tui-cert keeps here.
The control-plane screens list headscale's users, nodes, nodes waiting to register, pre-auth keys and DNS, with one line naming the next missing step, the host firewall's ports included, which f hands to tui-firewall prefilled. S sets the transport (an own certificate picked from the pairs tui-cert issued) and can enable headscale's embedded DERP relay, O the identity provider (Google or any OIDC), r approves routes, and the dns screen edits MagicDNS, nameservers, split DNS and records. Each change to config.yaml is a minimal diff, confirmed, then a restart.
When tailscale or headscale is absent, i installs it. --demo shows every screen with nothing installed.
| Key | Action |
|---|---|
| tab / 1…6 | Switch screen (node, peers, and headscale's users, nodes, preauth keys, dns) |
| j | Join: server, key, hostname, routes; from a profile; trusts a private CA (tui-cert's) |
| a / A | Toggle accepting routes / edit the advertised subnet routes |
| x / E | Pick the exit node to use / toggle offering this node as one |
| h | Set the hostname |
| d / u | Disconnect / reconnect (u starts a stopped or disabled tailscaled) |
| L | Log out of the tailnet |
| p | Switch between tailscale's own login profiles |
| i | Install tailscale or headscale when absent; reinstall headscale if config.yaml is gone |
| n | Create a headscale user (users) or pre-auth key (keys: shown once, whole; w saves it) |
| S / O | Control plane: server, transport (tui-cert's pairs), embedded DERP relay / OIDC provider |
| F | Fix ownership of headscale's state, secret and backup files (users screen) |
| f | Hand the terminal to tui-firewall with the ports readiness reports closed, prefilled |
| r (nodes) | Approve / revoke a node's advertised routes (subnet router, exit node) |
| R (nodes) | Register a node waiting for its login, as a user |
| e / m / x (nodes) | Expire / rename / delete the selected headscale node |
| e / n / x (dns) | Edit a DNS setting / add a split domain or record / remove it |
| r / ctrl+r | Reload (ctrl+r on the control plane's nodes screen, where r is routes) |
| ? | Help |
| q | Quit |
Press ? inside the tool for the full help screen, which is generated from the same action table as the key map.
This tool is a face on the program below, so its version matters. Tested is not a claim: a version lands there only after the tool's own suite passed against it on a real machine in the lab, and the run is kept as evidence in the repository. At startup the tool probes the backend once and says what it found in its header — a version nobody has run against is shown as (untested) in the warning colour, one older than the minimum as (below minimum) in the error colour. Neither stops it: the backend still refuses what it cannot do, in its own words.
tailscale1.60.0tailscale versionheadscale0.22.0headscale versionheadscale <0.23preauthkeys list requires a --user, so the pre-auth keys screen may be empty; users and nodes are unaffected
Maintain tailscale or headscale? You are welcome to help shape this tool. About → maintainers
Written after the work, from a machine the commands were actually run on. Every guide that mentions tui-tailscale is listed here.
A local CA from tui-cert, Keycloak served over https with a certificate from it, and a Headscale control plane set up with tui-tailscale that admits only the members of one Keycloak group. Run end to end in the family lab and told through the screens it produced, including the login that was refused.
A Headscale control plane with no public DNS name and no Let's Encrypt. tui-cert runs a local certificate authority, tui-tailscale serves its certificate and trusts it on each client, and machines join with pre-auth keys.
One public host runs the Headscale control plane with a Let's Encrypt certificate, people log in with their Google account, and the same host serves its private network to every client. Every step is one key in tui-tailscale, previewed before it runs.
Once per machine, then every tool in the family is one pacman away.
$ curl -fsSL https://pkgs.tui.tools/install.sh | shA family whose whole promise is preview before you run is not going to insist you pipe a script into a shell. These are the commands that script runs.
$ curl -fsSL -o /tmp/tui-tools.asc https://pkgs.tui.tools/pubkey.asc
sudo pacman-key --add /tmp/tui-tools.asc
sudo pacman-key --lsign-key \
"$(gpg --show-keys --with-colons /tmp/tui-tools.asc | awk -F: '/^fpr:/{print $10; exit}')"
printf '[tui-tools]\nServer = https://pkgs.tui.tools/arch/$arch\n' \
| sudo tee -a /etc/pacman.conf
sudo pacman -Sy$ sudo pacman -S tui-tailscaleUpgrades then arrive with the rest of your system updates.
$ paru -S tui-tailscale-binThe -bin package installs the released static binary.
Once per machine, then every tool in the family is one apt away.
$ curl -fsSL https://pkgs.tui.tools/install.sh | shA family whose whole promise is preview before you run is not going to insist you pipe a script into a shell. These are the commands that script runs.
$ sudo install -d -m 0755 /etc/apt/keyrings
curl -fsSL https://pkgs.tui.tools/pubkey.asc \
| sudo gpg --dearmor -o /etc/apt/keyrings/tui-tools.gpg
echo "deb [signed-by=/etc/apt/keyrings/tui-tools.gpg] https://pkgs.tui.tools/deb stable main" \
| sudo tee /etc/apt/sources.list.d/tui-tools.list
sudo apt update$ sudo apt install tui-tailscaleUpgrades then arrive with the rest of your system updates.
Once per machine, then every tool in the family is one dnf away.
$ curl -fsSL https://pkgs.tui.tools/install.sh | shA family whose whole promise is preview before you run is not going to insist you pipe a script into a shell. These are the commands that script runs.
$ sudo rpm --import https://pkgs.tui.tools/pubkey.asc
sudo curl -fsSL -o /etc/yum.repos.d/tui-tools.repo https://pkgs.tui.tools/rpm/tui-tools.repo
sudo dnf makecache$ sudo dnf install tui-tailscaleUpgrades then arrive with the rest of your system updates.
Needs the tui-tools repository, a one-time setup you do once per machine.
$ sudo zypper install tui-tailscaleThe rpm repository is shared with dnf; zypper support is not tested yet.
$ curl -fsSL https://github.com/tui-tools/tui-tailscale/releases/download/v1.1.0/tui-tailscale_1.1.0_linux_amd64.tar.gz | tar -xz tui-tailscale
sudo install -m0755 tui-tailscale /usr/local/bin/tui-tailscale$ curl -fsSL https://github.com/tui-tools/tui-tailscale/releases/download/v1.1.0/tui-tailscale_1.1.0_linux_arm64.tar.gz | tar -xz tui-tailscale
sudo install -m0755 tui-tailscale /usr/local/bin/tui-tailscaleOne static binary. Verify it against checksums.txt from the same release.
$ git clone https://github.com/tui-tools/tui-tailscale
cd tui-tailscale && make build
sudo install -m0755 bin/tui-tailscale /usr/local/bin/tui-tailscaleNeeds Go 1.27 or newer.
Every change is shown as an exact command line and confirmed before it runs. The dialog and the runner receive the same value, so the preview cannot drift from what executes.
Every change escalates, previewed first: tailscale, the key file under /run, IP forwarding, the trust store, headscale's CLI, config.yaml, the OIDC secret, its unit and the installs. The node is read as you; headscale, its journal and the firewall are read as root.
Nothing keeps running after you quit, and nothing is installed to run later. The system is the source of truth; the tool re-reads it after every change.
No connection of its own. On demand, previewed: the installs (i) fetch Tailscale's repository files or the tui-tools key (pinned fingerprint). Unprivileged reads: O and --probe-issuer fetch the IdP's discovery document; j checks the login server's certificate.
Released statically linked, with no runtime dependencies to install.
checksums.txt carries a keyless cosign signature from this repository's release workflow, every archive has a CycloneDX SBOM, and every archive, package and the checksum file carry SLSA build provenance. The security page shows the three commands that check it.
Report a security issue privately, through GitHub's private vulnerability reporting on the repository's Security tab. The family-wide policy, and what counts as in scope, is on the security page.
| File | Size | SHA-256 |
|---|---|---|
| checksums.txt | 1 KB | — |
| checksums.txt.sigstore.json | 10 KB | — |
| provenance.intoto.jsonl | 12 KB | — |
| tui-tailscale-1.1.0-1-aarch64.pkg.tar.zst | 2.2 MB | 1eb3792d4ddce3de0f3773ef7acee1afa9cb98369020d6ff85df7f938a195e1f |
| tui-tailscale-1.1.0-1-x86_64.pkg.tar.zst | 2.4 MB | 02fbd24524bcb0521bb1fb8d37e1ea227ddcc58478de76bb222827ae6f16e25d |
| tui-tailscale-1.1.0-1.aarch64.rpm | 2.2 MB | c71f2cd80fb02d6c91d203745a6ad9c57c6cf0065c75137af1fed03357006c9b |
| tui-tailscale-1.1.0-1.x86_64.rpm | 2.4 MB | 77e2fc974a80855816dbe26accd661104615696bfc1cbb4fa334a2c28f596e2b |
| tui-tailscale_1.1.0_amd64.deb | 2.4 MB | 5170144f79ea8554c898c3f9c7577de2f37b5cb6e97052510176408c35dba377 |
| tui-tailscale_1.1.0_arm64.deb | 2.2 MB | e9986922adaaab6e7d0bf6ec2aa79f2657aace8d2c45d04c6a05da0d63d1de40 |
| tui-tailscale_1.1.0_linux_amd64.tar.gz | 2.4 MB | 004336574a0112fb639b8b8665af30d1f0cb1de356a033bebaf0bcdbf7dc8099 |
| tui-tailscale_1.1.0_linux_amd64.tar.gz.cyclonedx.json | 25 KB | b1cf5c99eca0aba9261e492add216b0971f2fee3abf7224127714dbe7a8df832 |
| tui-tailscale_1.1.0_linux_arm64.tar.gz | 2.2 MB | 4d955ca7d2f2dfad4968747c19e531997191d83843298f3884f91f7588308e94 |
| tui-tailscale_1.1.0_linux_arm64.tar.gz.cyclonedx.json | 25 KB | 0d1d1b93dfa992e4b0ab8733aa4032661192a5fd3cfb691d07b0231061dfa948 |
Every release ships a checksums.txt. Download it next to the archive and run sha256sum -c checksums.txt --ignore-missing. See verifying a download.
## tui-tailscale v1.1.0 tui-tailscale 1.1.0 tui-tailscale 1.1.0 keeps a private tailnet's relays in-house and removes three frictions found setting up company control planes. `S` ends with a relay question and can enable headscale's embedded DERP relay as a minimal diff of `config.yaml`, with the STUN port read by readiness and opened through `f`. `f` now hands tui-firewall the ports readiness found closed, prefilled (`tui-firewall --open 443/tcp,41641/udp --comment 'tailnet control plane and node'`), one form and one confirm per port. A created pre-auth key is shown whole on a dialog of its own and never cut; on a terminal too narrow for it, no part of it is drawn, and `w` writes it once to a root-only file under `/run`. The header stays two rows at any width. Built on tui-kit v0.4.4: every child runs without a controlling terminal, and the headscale and tailscale installs use the kit's companion builders. Keys, flags and `--check` field names are unchanged; `--check` gains `readiness.ports.stunPort` and `readiness.ports.stun` when the embedded relay is on, and `readiness.relays` reports `embedded` or `embedded+tailscale-public` once it is. Built by this repository's CI on the tag itself. Each archive ships a CycloneDX SBOM, `checksums.txt` carries a keyless cosign signature, and every file has SLSA build provenance — see the README's "Verify a download" for the two commands that check them. The commits in this release: ## Changelog * cac8903ac170f4a49efc688c466b84497ddc65e3 1.1.0: embedded DERP, prefilled firewall hand-off, uncut keys, header fit; tui-kit v0.4.4 (#28 #30 #31 #32) (#33)
## tui-tailscale v1.0.1 tui-tailscale 1.0.1 tui-tailscale 1.0.1 closes a policy bypass and four rough edges found setting up company control planes. On a control plane with OIDC, `R` no longer registers a node whose browser login the identity provider's allow lists refused, nor one whose login is still at the provider; any other registration there goes through a danger confirm that says it skips the provider's policy. `r` and the return from `f` look for binaries again, so tui-firewall installed in another terminal is picked up, and `f` offers to install tui-firewall when it is missing. The ports reader follows jumps and gotos into ufw's and firewalld's chains instead of reporting open ports as closed, and says "unknown" when a jump cannot be followed. The users panel and the readiness line say that relays go through Tailscale's public DERP servers unless headscale's embedded DERP is enabled, and the README's private tailnet walkthrough explains it. Every apt step runs with `DEBIAN_FRONTEND=noninteractive NEEDRESTART_MODE=a` (tui-kit v0.4.2), shown in the preview, so needrestart cannot hang `i` on Ubuntu. Keys, flags and `--check` field names are unchanged; `--check` gains `readiness.refusedRegistrations`, `readiness.relays` and `readiness.relayHint`. Built by this repository's CI on the tag itself. Each archive ships a CycloneDX SBOM, `checksums.txt` carries a keyless cosign signature, and every file has SLSA build provenance — see the README's "Verify a download" for the two commands that check them. The commits in this release: ## Changelog * 6257b87d5debcca9d4ade1afcf4acf110808dd9a 1.0.1: R refuses IdP-refused registrations; re-probe on r and f; ports reader; DERP note (#26 #25 #24 #27 #23) (#29)
## tui-tailscale v1.0.0 tui-tailscale 1.0.0: stable tui-tailscale 1.0.0 is the first stable tool of the tui-tools family. Stable means a frozen contract under semver: the keys, the flags and the `--check` JSON only grow in minor releases, and anything removed or changed waits for a major release announced one minor ahead. It has run a real control plane and its nodes end to end, installs from apt, dnf, pacman and a static binary, and ships signed checksums, SBOMs and build provenance. This release also carries the fixes found on that real walkthrough: after a successful browser login the node screen waits while tailscaled comes up and then says who joined, instead of reporting an expired login, and a machine that is only a node shows the headscale tabs dimmed with where its control plane is; readiness no longer blocks on a spent single-use key once the first node has joined, and `--check` adds `canJoinMore`; a stopped or disabled tailscaled is started with `u`, and a headscale whose `config.yaml` was deleted is restored with `i`, both previewed, with `tailscale.daemon`, `headscale.configPresent` and `headscale.stateDirPresent` in `--check`. New demo cases: `--demo=node-only` and `--demo=partial-reset`. Built by this repository's CI on the tag itself. Each archive ships a CycloneDX SBOM, `checksums.txt` carries a keyless cosign signature, and every file has SLSA build provenance — see the README's "Verify a download" for the two commands that check them. The commits in this release: ## Changelog * ee8fd3182749f7b7b03e92884f332663c48625dc 0.2.1: login state after browser login, readiness with spent keys, stopped daemon and missing config (#20 #19 #18) (#21) * 67cb1f5df544ce99d0e06f47037abe58922aeb3c Promote tui-tailscale to stable: 1.0.0 (#22)
## tui-tailscale v0.2.0 tui-tailscale 0.2.0: private tailnets, join profiles, DNS Built by this repository's CI on the tag itself. Each archive ships a CycloneDX SBOM, `checksums.txt` carries a keyless cosign signature, and every file has SLSA build provenance — see the README's "Verify a download" for the two commands that check them. The commits in this release: ## Changelog * 5d2860747fbc62a051c77b63efaff1aa5e04f900 0.2.0: profiles, DNS, guided setup, CA trust, ports readiness (#10 #4 #14 #12 #15-part) (#16) * 8a7d6c8e9b8b6394add7100999a4c6a46e8cb76b Bump the github-actions group across 1 directory with 4 updates (#1) * a492f8592d63e224fabdc18f3be1cc89e206cf03 Private tailnet: tui-cert pairs in S, CA trust in j, FilePicker; release prep 0.2.0 (#17)
## tui-tailscale v0.1.0 tui-tailscale 0.1.0: self-hosted Tailscale from the terminal, both ends. This node: join, accept and advertise routes, exit node, peers, install. The headscale control plane: transport (plain http, Let's Encrypt, own certificate, reverse proxy), OIDC with a Google preset, users, nodes, pre-auth keys, route approval, readiness. Validated end to end on a real Ubuntu 24.04 host with Google OIDC and a subnet router, and on the family lab (Ubuntu 24.04 and 26.04, Fedora 44, Omarchy Server 4.0.1). Built by this repository's CI on the tag itself. Each archive ships a CycloneDX SBOM, `checksums.txt` carries a keyless cosign signature, and every file has SLSA build provenance — see the README's "Verify a download" for the two commands that check them. The commits in this release: ## Changelog * e2cd91f022286a055b751b9cb78b1c4ef6bd7e2b Bootstrap tui-tailscale 0.1.0: node and peers screens, join, prefs, install (#2) * a8f7b52b19f76a3636269c20a62013fe922cccfe Control plane: headscale users, nodes, keys, transport, OIDC presets, routes; re-probe after installs (#8) * 5dd6eb21715f42783424f5ccceb098bcebe51b9a Initial commit * 59baa58c14c09474930c3e9843f9f619b442872b Prepare the 0.1.0 release: install channels on, first-tailnet walkthrough (#11) * 038c820826af9550d027436835895f7d64d57aca Record the lab run on Ubuntu 26.04: tailscale 1.102.4 through the resolute plan (#7) * e094062185faa5f0a8ba60f1c85e58ec2ab67d50 compat: tailscale 1.102.4 tested on ubuntu-24.04, fedora-44 and omarchy-server-4.0.1 (#5)