Skip to content

Manage a Tailnet Key ​

A Tailnet Key is a secret member of an Environment, used for Tailscale joining. Each Environment can hold one. The Dashboard shows whether it's set, when it was last updated, and the latest observed join health.

Joining must succeed

A Cell with a saved Tailnet Key must join before its Runtime starts. An expired or revoked key, disallowed tag, unreachable coordination service, or timeout fails the Run with tailnet_join_failed. Replace the key or fix Tailscale connectivity and tag permissions before starting another Run.

Prepare the Key ​

In Tailscale's admin console, generate a key with all of these properties:

RequirementConfiguration
ReusableEnable Reusable when generating the key.
EphemeralEnable Ephemeral for devices that are removed after going offline.
Pre-approvedEnable Pre-approved to authorize devices in advance when device approval is enabled.
TaggedAttach a dedicated tag using Tailscale's tags configuration.

Choose the tag's permissions in your tailnet access control policy. For access to services behind a subnet router, configure route approval and access rules in Tailscale. These settings prepare the key; Zozo currently stores it without checking its Tailscale properties or validity.

Rotate before expiry

A Tailscale key expires even if it's reusable. Replace your Tailnet Key before its configured expiry or after revocation. Zozo doesn't renew it automatically; future nodes will need a valid key to join. If a key is exposed, revoke it in Tailscale and replace it here.

Save and Pin the Environment ​

  1. Open Settings in your Dashboard (#/settings).
  2. Under Environments, create or open an Environment.
  3. Enter the key in Tailnet Key, then select Set Tailnet Key.
  4. Confirm the secret placeholder and update time appear. The saved value can't be read back.
  5. Open Projects, then choose the Environment in your Project's Environment menu.

Pinning delivers the Environment's Variables to future Runs. The Tailnet Key is handed to the Cell through a private file, whose bytes are cleared before the Runtime starts. It never enters the Runtime's process environment.

Replace or Remove the Key ​

Open the Environment again. Enter a new value and select Replace Tailnet Key to rotate it. Select Remove Tailnet Key and confirm to clear it. Removing the saved value doesn't revoke it in Tailscale; revoke it there too when retiring it.

Secret Carriage and Recovery ​

The Tailnet Key follows the Environment's secured storage lifecycle. It's excluded from the Event journal, Stack Backups, the Stack Audit Export, and Export Archives. A Host Replacement carries it only through the sealed Credential manifest. After recovery from an ordinary Stack Backup, re-enter it.

An Onramp carries it only when you select its Environment. The selected secret material is sealed for the destination Stack.

Local Stack Behavior ​

A Local Stack is a Self-hosted Stack on your own machine. You can manage the same Tailnet Key there. A Run using the host Executor uses your machine's own network. The stored key is unused and doesn't change the machine's Tailscale connection. The Run journals an unused join outcome. The Run and the Environment's Tailnet Key field show a notice that the host Executor uses your machine's own network. Runs in Cells join independently using their pinned Environment.

Reach Private Services ​

The Cell runs Tailscale in userspace with ephemeral, memory-only state. It accepts approved subnet routes and never selects an exit node. The key's tag and your tailnet access rules determine which services it can reach.

After joining, the Runtime receives ALL_PROXY, HTTP_PROXY, and HTTPS_PROXY, each set to socks5h://127.0.0.1:1055. Use a client that supports SOCKS5 proxies and remote DNS so MagicDNS names resolve, for example:

sh
curl --proxy "$ALL_PROXY" https://test-server.your-tailnet.ts.net/health

Clients that ignore these proxy variables need explicit SOCKS5 configuration. An Environment with no Tailnet Key keeps the ordinary Cell network.

Join Health ​

The Environment and each pinning Project show the latest join outcome observed by a Run. Saving or replacing a key doesn't test it. Zozo holds no Tailscale API credential and makes no Tailscale API calls.

StateMeaning and remedy
unknownNo Run has reported a join attempt yet. Start a Run in a Cell to observe it.
okThe Cell joined successfully.
expiredTailscale reported an expired key. Replace the Tailnet Key.
refusedTailscale refused authentication or permissions. Check key validity and tag permissions.
unreachableJoining timed out or failed without an authentication diagnosis. Check coordination connectivity and retry.

Each attempted join appends one non-secret Event with outcome, tag, and tailnet address when available. The Tailnet Key value stays redacted. Health is an observation of the last attempt, so a replacement key needs a new Run before health changes.

Docs for Zozo: a coding-agent harness.