Connect Capy to your Tailscale tailnet so project machines can reach private services like databases and internal APIs, without exposing them to the public internet.
Connect Tailscale so agent machines can securely reach private services inside your network: internal databases, staging APIs, package registries, anything on your tailnet. Machines in enabled projects join your tailnet as ephemeral nodes at boot, tagged with a tag you choose, so you control exactly what they can access with your Tailscale ACLs. No public exposure, no static IP allow lists.
On the Scopes step pick Custom scopes, expand the Keys section, and check Write on Auth Keys; the tag picker that appears is required for the write scope — select the tag from the previous step. Leave every other scope unchecked:
Keys → Auth Keys → Write, with your tag selected
Generate the credential and copy the client ID and secret; the secret is shown once and starts with tskey-client-.
3
Connect Capy
Go to Settings → Integrations → Tailscale, click Connect, and enter the client ID, client secret, and your tag. Capy validates the credentials against your tailnet before saving, and the secret is stored encrypted. Any org member can connect; each Capy org holds one Tailscale connection.
4
Enable projects
The Projects section appears on the same page once connected. Turn on each project whose machines should join your tailnet; machines in other projects never join.
When a machine in an enabled project boots or wakes, Capy mints a single-use, short-lived auth key from your OAuth client and the machine joins your tailnet as an ephemeral node named capy-<machine-id>, carrying your tag. From that point, agent commands on the machine can reach whatever your ACLs allow.
Ephemeral and self-cleaning. Nodes are removed by Tailscale automatically when a machine pauses or is destroyed; a resumed machine rejoins with a fresh key. Your machine list never accumulates stale entries.
Never blocking. A failed join never blocks a machine from booting; the machine runs without tailnet access and rejoins on its next wake.
Keys stay on the machine. Each auth key is minted per machine, expires after five minutes, and is delivered to a root-owned file readable by no other user. Keys never appear in process arguments, environment variables, or logs, and never persist into machine snapshots.
Capy machines have exactly the access your ACL grants their tag, and nothing else by default. For example, to let agents reach a private Postgres instance, declare its address as a host alias and accept traffic to its port:
A destination can be a hosts alias, a Tailscale IP or CIDR, or another tag (for example tag:database:5432 if your database nodes are themselves on the tailnet).Scope the tag’s rules to the specific services agents need; there is no reason for Capy machines to see your whole tailnet.
Turning a project off stops its machines from joining at their next boot or wake. Disconnecting the integration (the ⋯ menu on the connection card) removes the stored credentials and stops all new joins immediately.Either way, already-running machines keep their tailnet session until they pause or stop. To cut one off immediately, remove its node from your Tailscale machines list, and revoke the OAuth client in Tailscale if the credentials themselves should die.
Connecting fails with an invalid credentials error
Capy verifies the client by minting and immediately revoking a probe key. Check that the OAuth client has Keys → Auth Keys write scope, that the tag on the scope matches the tag you entered, and that the tag exists in your policy file’s tagOwners.
The connection shows Reconnect needed
Your tailnet definitively rejected the credentials, usually because the OAuth client was revoked or the tag was removed from tagOwners. Machines keep booting without tailnet access until you reconnect with working credentials.
A machine isn't in my tailnet
Check that its project’s toggle is on; only machines booted or woken after enabling join. A machine whose join failed rejoins on its next wake, so pausing and resuming it retries immediately.
Machines join but can't reach my service
That’s an ACL question: nodes tagged with your tag need an accept rule to the service’s host and port. Test from the machine with tailscale ping <host>.
Do machines have stable IPs I can allow-list instead?
No; machine infrastructure uses dynamic addresses. The tag is the stable identity, which is exactly what the ACL rules key on.
Was this page helpful?
⌘I
Assistant
Responses are generated using AI and may contain mistakes.