Tailscale VPN
Let a server reach databases and APIs on your private Tailscale network
Introduction
Executable Apps and Runnable Code can be connected to Tailscale to provide access to private services inside your Tailnet.
Remote HTTP and OpenAPI servers run outside Gatana, so this setting does not exist for them.
Turning It On
Open the server's Settings tab, find Tailscale VPN, and check Connect to your tailnet. Paste an auth key, and optionally a machine name. The server restarts to join the tailnet.
If the section is not there, Tailscale is not available in your environment. In the Gatana cloud service it is part of the paid plans. A self-hosted installation offers it only when it is configured for it.
The Auth Key
Create the key in your Tailscale admin console, under Settings and then Keys. The key is spent at the first registration: the server stores the machine identity it received and keeps it across restarts, redeploys and idle stops. A server that has joined does not care that its key expires later.
Three properties matter:
| Property | Why |
|---|---|
| Tagged | The tag carries the ACLs, so you can scope access. A machine that joins with a tagged key also gets key expiry disabled by default, so it never has to re-authenticate. |
| Not ephemeral | Gatana stops idle servers, sometimes for a long time. Tailscale removes an ephemeral machine that stays offline, and the removal throws the server's identity away. |
| Reusable | Optional. The key is normally spent once, but a reusable key lets the server register again by itself if you remove its machine from your admin console. |
Give the tag only the access the server needs. An MCP server often runs third-party code, and on the tailnet it reaches exactly what its tag is allowed to reach. Grant it the one database port it is there for, not your whole network.
For a key without a tag, open the machine in your admin console and choose Disable key expiry; otherwise the machine must re-authenticate when its node key expires, which is after 180 days by default.
To move the server to a different key, paste the new key into the same field. The server restarts and joins as a new machine; remove the old machine in your admin console.
Reaching Hosts On Your Tailnet
Nothing in your server's code has to change. The tailnet is reachable over ordinary sockets, so plain database drivers work as well as HTTP clients:
// A Postgres server on your tailnet, by its Tailscale address
const db = new Client({ host: '100.101.102.103', user: 'reader' });
// Or a host behind a subnet router, by its address on your own network
const res = await fetch('http://10.0.5.20:8080/internal/api');Machine names from MagicDNS need one extra step. Your server keeps using Gatana's own name resolution, so ask the tailnet resolver for those names directly, at 100.100.100.100. Addresses always work, so the simplest approach is to configure your server with the address of the host it needs.
The environment variable GATANA_TAILSCALE is set to true when the tailnet is attached, so code that runs both with and without it can tell the difference.
Lifecycle And Limits
- The server keeps its machine identity: restarts, redeploys and idle stops all re-attach as the same machine. A self-hosted installation without persistent storage falls back to registering on every restart; there the key has to be reusable, and rotated before it expires.
- The machine identity is kept on a small volume of its own. It appears on the Storage page as a Tailscale identity volume, does not count against the storage quota, and cannot be deleted while the server uses it. After a key change the old identity volume lingers for a while and can be deleted by hand.
- A server on the tailnet stops its old instance before the new one starts when it redeploys, so a redeploy pauses the server for a moment, the same way persistent storage does.
- The tailnet comes up before your server starts, so its first connection already works.
- If the tunnel restarts on its own, open connections through it break and your server has to reconnect.
- The server cannot advertise routes, act as an exit node, or publish anything with
tailscale serve.
Troubleshooting
The server never finishes starting. Almost always the auth key, on the first join or after a key change. Gatana waits for the tailnet before it starts your server, so a key that is expired, already spent, or single-use leaves the deployment waiting. Open the Deployment tab and select the tailscale (sidecar) container above the log view to read what Tailscale itself reports, then paste a fresh key.
You removed the machine from your admin console. With a reusable key the server registers again on its own at the next start. With a spent or expired key it cannot; paste a fresh key.
The server starts but cannot reach a host. Check your tailnet ACLs for the key's tag. Look for the machine in your Tailscale admin console under the name from the settings, or gatana-<server slug> by default, and confirm the tag it carries.
Last updated on