tui-tools

tui-tailscale

Self-hosted Tailscale from the terminal: the control plane and this node

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.

v1.1.0Stable since 1.0.0vpnMIT
The node screen: state, login server, addresses, and the settings that decide what this node routes
The node screen: state, login server, addresses, and the settings that decide what this node routes

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.

Keys

KeyAction
tab / 1…6Switch screen (node, peers, and headscale's users, nodes, preauth keys, dns)
jJoin: server, key, hostname, routes; from a profile; trusts a private CA (tui-cert's)
a / AToggle accepting routes / edit the advertised subnet routes
x / EPick the exit node to use / toggle offering this node as one
hSet the hostname
d / uDisconnect / reconnect (u starts a stopped or disabled tailscaled)
LLog out of the tailnet
pSwitch between tailscale's own login profiles
iInstall tailscale or headscale when absent; reinstall headscale if config.yaml is gone
nCreate a headscale user (users) or pre-auth key (keys: shown once, whole; w saves it)
S / OControl plane: server, transport (tui-cert's pairs), embedded DERP relay / OIDC provider
FFix ownership of headscale's state, secret and backup files (users screen)
fHand 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+rReload (ctrl+r on the control plane's nodes screen, where r is routes)
?Help
qQuit

Press ? inside the tool for the full help screen, which is generated from the same action table as the key map.

Compatibility

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.

tailscale

tailscale ≥ 1.60.0
Binary
tailscale
Minimum
1.60.0
Probed with
tailscale version
Tested
1.98.41.102.4

headscale

headscale ≥ 0.22.0
Binary
headscale
Minimum
0.22.0
Probed with
headscale version
Tested
0.29.3

What changes on older versions

  • headscale <0.23

    preauthkeys 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

Guides

Written after the work, from a machine the commands were actually run on. Every guide that mentions tui-tailscale is listed here.

  • A company tailnet with Keycloak single sign-on

    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 private tailnet with your own CA

    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.

  • Self-hosted Tailscale with Headscale and Google login

    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.

Install

Once per machine, then every tool in the family is one pacman away.

Add the repository
$ curl -fsSL https://pkgs.tui.tools/install.sh | sh
Or run the same thing yourself, one command at a time

A 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.

The one-time setup, by hand
$ 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
Arch Linux · tui-tailscale
$ sudo pacman -S tui-tailscale

Upgrades then arrive with the rest of your system updates.

What it can do to your machine

  • Preview, then confirm

    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.

  • Escalates for actions

    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.

  • No daemon, no state of its own

    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.

  • Opens network connections

    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.

  • Static binary

    Released statically linked, with no runtime dependencies to install.

  • Signed release, with provenance

    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.

Reporting

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.

Downloads

v1.1.0 · 2026-09-25
FileSizeSHA-256
checksums.txt1 KB—
checksums.txt.sigstore.json10 KB—
provenance.intoto.jsonl12 KB—
tui-tailscale-1.1.0-1-aarch64.pkg.tar.zst2.2 MB1eb3792d4ddce3de0f3773ef7acee1afa9cb98369020d6ff85df7f938a195e1f
tui-tailscale-1.1.0-1-x86_64.pkg.tar.zst2.4 MB02fbd24524bcb0521bb1fb8d37e1ea227ddcc58478de76bb222827ae6f16e25d
tui-tailscale-1.1.0-1.aarch64.rpm2.2 MBc71f2cd80fb02d6c91d203745a6ad9c57c6cf0065c75137af1fed03357006c9b
tui-tailscale-1.1.0-1.x86_64.rpm2.4 MB77e2fc974a80855816dbe26accd661104615696bfc1cbb4fa334a2c28f596e2b
tui-tailscale_1.1.0_amd64.deb2.4 MB5170144f79ea8554c898c3f9c7577de2f37b5cb6e97052510176408c35dba377
tui-tailscale_1.1.0_arm64.deb2.2 MBe9986922adaaab6e7d0bf6ec2aa79f2657aace8d2c45d04c6a05da0d63d1de40
tui-tailscale_1.1.0_linux_amd64.tar.gz2.4 MB004336574a0112fb639b8b8665af30d1f0cb1de356a033bebaf0bcdbf7dc8099
tui-tailscale_1.1.0_linux_amd64.tar.gz.cyclonedx.json25 KBb1cf5c99eca0aba9261e492add216b0971f2fee3abf7224127714dbe7a8df832
tui-tailscale_1.1.0_linux_arm64.tar.gz2.2 MB4d955ca7d2f2dfad4968747c19e531997191d83843298f3884f91f7588308e94
tui-tailscale_1.1.0_linux_arm64.tar.gz.cyclonedx.json25 KB0d1d1b93dfa992e4b0ab8733aa4032661192a5fd3cfb691d07b0231061dfa948

Every release ships a checksums.txt. Download it next to the archive and run sha256sum -c checksums.txt --ignore-missing. See verifying a download.

Releases

v1.1.0

2026-09-25
## 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)

v1.0.1

2026-09-25
## 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)

v1.0.0

2026-09-25
## 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)

v0.2.0

2026-09-25
## 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)

v0.1.0

2026-09-25
## 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)