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.2Stable 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.2 · 2026-10-22
FileSizeSHA-256
checksums.txt1 KB—
checksums.txt.sigstore.json10 KB—
provenance.intoto.jsonl12 KB—
tui-tailscale-1.1.2-1-aarch64.pkg.tar.zst2.2 MB7f8e6b125b245286e820fca753fadb9780e22bbd6871be64ff76e0a83013fbf4
tui-tailscale-1.1.2-1-x86_64.pkg.tar.zst2.4 MB27e4314e2c8f741bad01c93e9b0a8e4fd5beb173dc0c1d693b4db9f64023323c
tui-tailscale-1.1.2-1.aarch64.rpm2.2 MB9aa85966968b6d0142d6f0e669b678e0788df98815ff5e1845563a745744c370
tui-tailscale-1.1.2-1.x86_64.rpm2.4 MB7f58a5618e470f3394f88c5a522c8c329af11b132382b173b584f43162507b22
tui-tailscale_1.1.2_amd64.deb2.4 MB6341f1b5a8baf81cec1737d9cad7839fc68dcf8d992fb49b3c5c56d5575aa0c1
tui-tailscale_1.1.2_arm64.deb2.2 MB576c9904cfe4bc89f565f144e2902332f9926b8bd67a8a3e7c08246c904b9a36
tui-tailscale_1.1.2_linux_amd64.tar.gz2.4 MB71690df19f637efeb83d1b5768a111a802fa0d13f9b75f7e8085f551ffa8f16a
tui-tailscale_1.1.2_linux_amd64.tar.gz.cyclonedx.json25 KB88c7c5391ac70543470d04060d84cc9146dde69f38c441950b42e5f96a7a17e4
tui-tailscale_1.1.2_linux_arm64.tar.gz2.2 MBc98c4acf78acd7489107d809e534aa0e3441945390779501e0c09a0723ecbcb2
tui-tailscale_1.1.2_linux_arm64.tar.gz.cyclonedx.json25 KBf9e6c40365eec26a7d228343411535ee12c2ad33b44c864cd045920027500efc

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

2026-10-22
## tui-tailscale v1.1.2

tui-tailscale 1.1.2

- Built with Go 1.27.3, which fixes CVE-2026-111943 in the standard library (crypto/x509), and tui-kit v0.4.5; dependencies on their latest versions. No change in behavior.

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
* 052ddeffdd9c609bc7d5abbf46a223c384fe8554 1.1.2: Go 1.27.3 (stdlib security fixes) (#39)
* 9e3191be099c8b48aff80f86a5b21a669427c0c6 Bump the github-actions group across 1 directory with 9 updates (#37)

v1.1.1

2026-10-20
## tui-tailscale v1.1.1

tui-tailscale 1.1.1

- Built with Go 1.27.2, which fixes CVE-2026-78667, CVE-2026-78669 and CVE-2026-97031 in the standard library (net/http, crypto/tls). No change in behavior.

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
* cd83685a643581f035a3db3c06fca038be56724c 1.1.1: Go 1.27.2 (stdlib security fixes) (#38)

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)