Skip to Content
DocumentationNetworkingTailscale private networking

Tailscale private networking

Tailscale  provides a private mesh VPN that lets you access your Companion Hub apps from anywhere — without exposing them to the public internet.

When to use Tailscale

Tailscale is ideal when:

  • You want private access to your apps from your devices only
  • You don’t want apps publicly accessible on the internet
  • You need to connect multiple machines in a private network
  • You want to access your Hub from anywhere securely
  • You own more than one Companion appliance and want them to share AI capacity — see Hub Pool, which runs entirely over the tailnet you set up here

Benefits

  • Access from anywhere — Securely reach your Hub from any location
  • Connect all devices — Link Windows, Mac, Linux, iOS, and Android devices
  • Automatic NAT traversal — No port forwarding needed
  • End-to-end encryption — Encrypt all traffic between devices
  • Free for personal use — Tailscale offers a free Personal plan

Setup options

Companion Hub offers two ways to use Tailscale. Both end in the same place — your Hub on your tailnet with a 100.x.y.z address — and differ only in where the Tailscale daemon runs and how the Hub container reaches it:

Private VPN works on a Linux Hub. On macOS and Windows, Hub can’t use the Tailscale app on your computer, because the Hub runs inside Docker Desktop’s virtual machine, and the sidecar route there is untested. Treat Private VPN as unsupported on those systems for now, and reach your Hub through Public Web or on your own network instead.

Option 1: Hub sidecar

Companion Hub’s stack defines a Tailscale container, hub-tailscale, that connects your Hub to your Tailscale network. Hub starts it only when it has something to sign in with: a pre-auth key (TAILSCALE_AUTHKEY) or a Tailscale login saved by an earlier session. A Hub you start with cihub also keeps the sidecar off when its .env holds PRIVATE_VPN_USER_DISABLED=true; the desktop app ignores that setting. On a fresh install with neither a key nor a saved login, no sidecar runs. The wizard then reads Tailscale needs to be installed on this computer, and Settings → Network says The Hub could not access Tailscale (no host CLI/socket and no hub-tailscale sidecar). In that case, install Tailscale on the host (Option 2), which is the reliable route on a fresh install, or start the sidecar with a pre-auth key. If Tailscale is already installed on the Hub’s host, Hub uses that instead.

The steps below apply once Hub can reach Tailscale, through the sidecar or the host client.

Enable during onboarding

When you first set up your Hub, the onboarding wizard includes a Private VPN step:

  1. Click Log In with Tailscale
  2. Authenticate in the popup window (create a free account if needed)
  3. Your Hub automatically joins your Tailscale network
  4. Continue with the wizard

The onboarding wizard polls connection status in real-time, so you’ll see when your Hub connects successfully.

Enable in Settings

If you skipped Tailscale during onboarding, you can set it up later:

  1. Go to Settings → Network
  2. Find the Private VPN (Tailscale) section
  3. Select Log In with Tailscale
  4. Authenticate in the new browser tab

To sign in without a browser, use a pre-auth key instead.

Settings, Network tab: a Private VPN (Tailscale) card marked Inactive with the daemon state NeedsLogin and a Log In with Tailscale button, above a Hub Pool card marked Local only, with a note that Tailscale is not connected, pooling controls, and a Save buttonSettings, Network tab: a Private VPN (Tailscale) card marked Inactive with the daemon state NeedsLogin and a Log In with Tailscale button, above a Hub Pool card marked Local only, with a note that Tailscale is not connected, pooling controls, and a Save button
Settings → Network: the Private VPN (Tailscale) card, here still Inactive with a Log In with Tailscale button.

Access your Hub

Once connected, your Hub gets a Tailscale IP address (e.g., 100.x.y.z) and a tailnet hostname. Settings → Network shows the Tailscale IP, the Hostname, and the Daemon state under Private VPN (Tailscale). For the full <device>.<tailnet>.ts.net name, open the device in your Tailscale admin console.

Install Tailscale on your other devices:

  • Download from tailscale.com/download 
  • Join the same tailnet (use the same sign-in identity or an invited account)
  • Open the Hub dashboard at https://<device-name>.<tailnet>.ts.net/

Hub publishes its own dashboard on the tailnet with Tailscale Serve, so this address needs MagicDNS and HTTPS Certificates enabled for your tailnet — the same requirement as Private VPN app links.

With the default sidecar, the Hub dashboard is not reachable at http://<tailscale-ip>:5002. The sidecar is a separate container and forwards nothing on its own; only the Tailscale Serve addresses are published. The direct-port form works only with a host installation (Option 2).

Option 2: Host installation

If Tailscale is already installed on the Hub’s host, Hub uses that client instead of the sidecar. The stock Compose file mounts the host’s Tailscale socket directory and CLI into the ci-hub container, so there is nothing to configure. Hub uses the host client when the CLI and the tailscaled socket both answer, and falls back to the sidecar otherwise.

Install Tailscale on host

curl -fsSL https://tailscale.com/install.sh | sh sudo tailscale up

Check the socket mount

The stock Compose file mounts ${TAILSCALE_SOCKET_DIR:-/var/run/tailscale} and ${TAILSCALE_BINARY:-/usr/bin/tailscale} into the ci-hub container. Set TAILSCALE_SOCKET_DIR or TAILSCALE_BINARY in the Hub’s .env if your distribution puts them somewhere else. The Hub container user must be able to read and write the socket. If it cannot, Hub falls back to the sidecar.

The host’s tailscaled accepts changes only from root or the host’s Tailscale operator. If the account the Hub runs as is neither, which is the usual case on Linux, Tailscale refuses the Hub’s changes and Hub can’t publish its dashboard or any Private VPN app. Settings → Network then shows Tailscale refused the Hub’s changes with the command to run, and each affected app’s Access points card reads Refused. See Tailscale refused the Hub’s changes.

Access your Hub

Open the Hub dashboard at https://<device-name>.<tailnet>.ts.net/. With a host client you can also use http://<tailscale-ip>:5002. Apps still need their own Hub exposure setting; use Private VPN for the managed HTTPS links described below.

Accessing apps over Private VPN

When you enable Private VPN for an individual app (App → Settings → set exposure to Private VPN → Save), the Hub automatically publishes that app on your Tailscale node using Tailscale Serve . Each app gets its own HTTPS port on your Hub’s Tailscale hostname:

https://<your-hub>.<tailnet>.ts.net:<app-port>

For example, a code-server app on port 8138 becomes:

https://hub-tailscale.tail-scale.ts.net:8138

The Hub creates and removes these mappings for you whenever you toggle Private VPN, start/stop the app, or change its configuration — no manual tailscale serve commands required. Hub keeps port 443 of your computer’s Tailscale Serve settings for its own dashboard and one HTTPS port for each Private VPN app, and replaces anything you serve on those ports. It removes only the entries it published.

One-time setup: enable HTTPS certificates for your tailnet. Private VPN publishing uses Tailscale Serve , which requires HTTPS certificates for the tailnet. If they are not enabled when you pick Private VPN, the Hub shows an inline warning in the app’s exposure settings and a toast, both with an Enable HTTPS Certificates link to your tailnet’s DNS settings.

Enable HTTPS certificates and MagicDNS

Tailscale Serve needs HTTPS Certificates and MagicDNS on your tailnet. Select Enable HTTPS Certificates in the Hub’s toast or warning, or open the DNS page of the Tailscale admin console yourself:

Enable HTTPS in Tailscale

Enabling HTTPS allows Tailscale to provision certificates for your tailnet’s *.ts.net names. Tailscale’s consent screen explains that machine and tailnet names are recorded in public certificate-transparency logs. This only needs to be enabled once by a tailnet owner or admin.

Approve Tailscale Serve, if Tailscale asks

If Private VPN still fails after HTTPS is enabled, Tailscale may be waiting for you to approve Serve for the Hub’s node. Check from the CLI. With the sidecar:

docker exec hub-tailscale tailscale serve status

With a host installation, run tailscale serve status on the host.

If Serve is not enabled, Tailscale prints a link like https://login.tailscale.com/f/serve?node=.... Open that URL (tailnet admin required) and approve the requested tailnet settings:

Enable Tailscale Serve

The button opens Tailscale’s Serve consent flow. If you already have a node-specific link from the CLI output, use that instead — it skips straight to the right node.

Re-trigger the Hub sync

After enabling HTTPS (and approving Serve if needed), Hub notices within a minute and checks again every five minutes. To force a check now, toggle the app’s Private VPN setting off and back on (or restart the app) so the Hub re-creates the serve mapping. The app link then resolves.

You’ll find the generated https://<your-hub>.<tailnet>.ts.net:<port> URL on the app’s page. Make sure the device you’re browsing from is connected to the same tailnet.

Next: Follow the agent mobile apps guide to install OpenClaw on iOS or Android, pair it with CI-OpenClaw, or open CI-Hermes securely from an iPhone.

How it works

  1. Mesh Network — Tailscale creates a peer-to-peer mesh between all your devices
  2. NAT Traversal — Works behind firewalls and routers without configuration
  3. Private IPs — Each device gets a private IP (100.x.y.z range)
  4. Encrypted — All traffic is encrypted end-to-end using WireGuard

Troubleshooting

Sidecar not available

If Settings → Network shows “The Hub could not access Tailscale (no host CLI/socket and no hub-tailscale sidecar)”:

The sidecar starts only when Hub has a pre-auth key or a saved Tailscale login, so a fresh install has no hub-tailscale container:

  1. Install Tailscale on the Hub’s host (Option 2). Hub uses the host client, and needs no sidecar.

  2. Or set TAILSCALE_AUTHKEY in the Hub’s .env file and restart with cihub up --detached. See Pre-auth keys.

  3. Check whether the hub-tailscale container is running:

    docker ps | grep hub-tailscale cihub status # shows the Tailscale IP when connected

A Hub you start with cihub never starts the sidecar when its .env holds PRIVATE_VPN_USER_DISABLED=true. Hub still publishes through the Tailscale client on the host. See Turning Private VPN off.

Connection not working

If the login button doesn’t connect:

  1. Complete the authentication in the popup window
  2. Wait 5-10 seconds for the connection to establish
  3. Refresh the Settings page to see updated status

Can’t access Hub from other devices

  1. Verify Tailscale is running on both devices:

    tailscale status
  2. Ensure both devices show “Running” in Tailscale

  3. Open the Hub’s tailnet address: https://<device-name>.<tailnet>.ts.net/ (read the device name from Settings → Network, and the tailnet name from your Tailscale admin console). This needs MagicDNS and HTTPS Certificates enabled for your tailnet

  4. With a host installation only, you can also try http://100.x.y.z:5002 or http://your-hub-name:5002. The default sidecar does not forward port 5002, so these addresses do not work there

If an app has Private VPN enabled but its https://<hub>.<tailnet>.ts.net:<port> link doesn’t load, Tailscale Serve’s HTTPS prerequisites may not be enabled for your tailnet yet. Hub reports the missing prerequisites:

  • A toast appears — “Couldn’t publish <app> over Private VPN: HTTPS is not enabled on your tailnet” — with an Enable HTTPS Certificates link to your tailnet’s DNS settings.
  • The app’s exposure settings show an inline warning the moment you choose Private VPN.

Enable HTTPS Certificates and MagicDNS on your tailnet:

Enable HTTPS in Tailscale

If links still fail, confirm from the CLI on your Hub. With the sidecar:

docker exec hub-tailscale tailscale serve status

With a host installation, run tailscale serve status on the host. When Serve isn’t enabled, Tailscale prints:

Serve is not enabled on your tailnet. To enable, visit: https://login.tailscale.com/f/serve?node=...

Open that node-specific link and approve Serve for your Hub:

Enable Tailscale Serve

Then toggle the app’s Private VPN setting off and on (or restart the app) so the Hub re-creates the serve mapping. See Accessing apps over Private VPN for details.

Tailscale refused the Hub’s changes

If an app’s Access points card reads Refused, with Tailscale refused this change. Open Network settings to fix it, or Settings → Network shows Tailscale refused the Hub’s changes, the Hub is using the Tailscale client on your computer and Tailscale won’t take its changes. The host’s tailscaled accepts changes only from root or the computer’s Tailscale operator, and the account the Hub runs as is neither.

The Private VPN (Tailscale) card in Settings, Network, marked Active with a Tailscale IP, a hostname, and the daemon state Running, above a warning that reads Tailscale refused the Hub's changes, explains that the account the Hub runs as is neither root nor the computer's Tailscale operator, shows a command to run once on the computer with a copy button, and says Refused since a date and timeThe Private VPN (Tailscale) card in Settings, Network, marked Active with a Tailscale IP, a hostname, and the daemon state Running, above a warning that reads Tailscale refused the Hub's changes, explains that the account the Hub runs as is neither root nor the computer's Tailscale operator, shows a command to run once on the computer with a copy button, and says Refused since a date and time
The refusal message in Settings → Network. The Tailscale address, device name, and time are example data.

Run the command once on the computer that runs the Hub. Select the copy button next to it to copy it. For example, when the Hub runs as user ID 1000:

u="$(id -nu 1000)" && sudo tailscale set --operator="$u"

Use the command your Hub shows, because the account differs between computers. The command makes that account the computer’s Tailscale operator, and replaces any operator you set before. The Hub tries again every five minutes, and the message and the Refused badges clear by themselves after Tailscale accepts a change.

Hub Pool needs the same thing: one Hub can pair with another only when Tailscale Serve publishes it at its tailnet name. cihub pool doctor is a read-only check that reports whether Serve publishes the Hub (see Before you start and the command reference in Hub Pool). Once Serve works on both Hubs, Pool two Hubs walks through the pairing and proves it with a model that exists on only one of them.

Advanced configuration

Custom routes

By default, the sidecar advertises the Docker bridge networks (172.18.0.0/16 and 172.19.0.0/16) and accepts routes advertised by other nodes. This is separate from Hub-managed Tailscale Serve links and is only needed when you want tailnet clients to route directly to container addresses. Tailscale may require a tailnet admin to approve the advertised subnet route.

To customize this, set HUB_TAILSCALE_EXTRA_ARGS in your .env file. Keep an explicit --login-server=https://controlplane.tailscale.com unless you intentionally run your own control plane:

HUB_TAILSCALE_EXTRA_ARGS=--login-server=https://controlplane.tailscale.com --accept-routes --advertise-routes=172.18.0.0/16,172.19.0.0/16,192.168.1.0/24

Turning Private VPN off

Two settings in the Hub’s .env file turn off different parts of Private VPN. Set either one to true and restart the stack.

VariableWhat it turns offRead by
PRIVATE_VPN_USER_DISABLEDThe hub-tailscale sidecar. Hub still publishes itself and your Private VPN apps through the Tailscale client on the host, if the host has one.cihub. The desktop app ignores it and removes the line when it starts.
TAILSCALE_SERVE_USER_DISABLEDTailscale Serve. Hub publishes neither its dashboard nor any app, removes nothing it published before, and no longer offers Private VPN as an app’s exposure mode.The Hub itself. The desktop app keeps it across restarts.

Use PRIVATE_VPN_USER_DISABLED on a computer that runs its own Tailscale and doesn’t need the sidecar. Use TAILSCALE_SERVE_USER_DISABLED when you manage the computer’s Tailscale Serve settings yourself.

With TAILSCALE_SERVE_USER_DISABLED=true, Hub leaves existing Serve entries in place and stops repairing its own entry after a device rename or tailscale serve reset. Hub Pool peers lose the Hub until someone publishes it again; the Hub log then prints the tailscale serve command to run.

Pre-auth keys (automated setup)

For headless or automated deployments, you can use a pre-authentication key instead of browser login:

  1. Generate a key at login.tailscale.com/admin/settings/keys 
  2. Add it to your .env file:
    TAILSCALE_AUTHKEY=tskey-auth-...
  3. Start the Hub with cihub up --detached. Hub starts the sidecar because it now has a key, and the sidecar connects on startup

The desktop app rewrites the Hub’s .env file every time it starts the stack. It keeps TAILSCALE_AUTHKEY and TAILSCALE_SERVE_USER_DISABLED, but not HUB_TAILSCALE_EXTRA_ARGS, so a key survives restarts and custom routes don’t. With the desktop app, add the key to .env.dev in the Hub’s data folder (.env on Windows) and restart the Hub from the app. On Linux you can install Tailscale on the machine instead.

Pre-auth keys should be kept secret and rotated regularly. Prefer browser login for interactive setups so you do not need to store a reusable key.

Comparison with Cloudflare

FeatureTailscaleCloudflare
PrivacyPrivate mesh, no public exposurePublic URLs (can be secured with Access)
SetupBrowser login or pre-auth keyRequires CI Account registration
Device RequirementTailscale client on each deviceAny browser works
Use CasePersonal, private accessSharing with others, public apps
CostFree Personal plan availableFree tier available

For public access to your apps, use the Cloudflare Gateway instead. You can use both Tailscale and Cloudflare simultaneously.

New to this? Reach your Hub from your phone walks the whole path end to end, including how to prove it works away from your home Wi-Fi.

Next steps

Last updated on