Guide 10 of 27
For your agent: .md · all guides
On this page
Remote access: fix things from your phone
Runs on: your box, your Mac and your phone.
This guide puts your box, your Mac and your phone on one private network. You can then reach the box from anywhere without opening a port to the internet, and ask your coding agent to do the devops work while you are away from the desk.
If you already know Tailscale, skip to Your coding agent as your devops person.
What it is and what it costs
A mesh VPN gives each of your devices a private address that works from any network: home Wi-Fi, a café, mobile data. Traffic goes directly between your devices when it can, and is encrypted end to end.
| Tool | Free plan (checked 2026-09-28) | Pick it when |
|---|---|---|
| Tailscale (recommended) | Personal plan: up to 6 users, unlimited devices | You want names like box.your-tailnet.ts.net and an iPhone app that just works |
| ZeroTier | New accounts: 10 devices, 1 network | You already use it, or you want to self-host the controller |
Both have iOS, macOS and Linux apps. The steps below use Tailscale. ZeroTier works the same way; see ZeroTier instead.
The setup
phone ──┐ Claude app (Remote Control), Termius
│
├── tailnet ──── Mac Claude Code, Xcode, your repos
│
└──────────────── box Docker, your API, backups
- The box runs your services. Its SSH port is only reachable over the tailnet.
- The Mac runs Claude Code and does iOS builds. It reaches the box with
ssh box. - The phone drives Claude Code on the Mac, or opens a terminal on the box.
Steps
1. Install Tailscale on all three
- Box:
curl -fsSL https://tailscale.com/install.sh | sh, thensudo tailscale up. Open the link it prints and sign in. - Mac: install the Tailscale app from the Mac App Store or tailscale.com/download, and sign in with the same account.
- Phone: install Tailscale from the App Store and sign in.
Run tailscale status on the box. It lists all three devices.
2. Names and key expiry
In the Tailscale admin console:
- DNS: check that MagicDNS is on. It usually is for new tailnets. Your
box is then reachable as
<machine-name>.<your-tailnet>.ts.net. Rename the machine to something short, such asbox. - Machines → the box → Disable key expiry. Device keys expire after 180 days by default. On a phone that means a login prompt. On the box, which nobody logs into, it means the box silently drops off the tailnet.
3. One SSH alias on the Mac
Put this in ~/.ssh/config on the Mac:
Host *
UseKeychain yes
AddKeysToAgent yes
IdentityFile ~/.ssh/id_ed25519
Host box
HostName box.your-tailnet.ts.net
User alice
Then run this once, and enter your key’s passphrase:
ssh-add --apple-use-keychain ~/.ssh/id_ed25519
Why this matters:
ssh boxworks at home and away. Tailscale finds the direct path on your LAN when you are home, so there is no need for a second “LAN” alias.- The passphrase lives in the macOS Keychain. An agent that runs
ssh boxorgit pushin a non-interactive shell cannot answer a passphrase prompt. Without the Keychain entry, the command just hangs. - Skills use the alias. Set
"box": { "ssh": "box" }in~/.config/onebox/config.json(see CONFIG.md). Every box skill then reaches the box the same way you do.
4. Close SSH to the internet (VPS only)
A mini PC at home behind your router needs nothing here. A VPS has a public IP, so allow SSH only on the Tailscale interface.
Keep your VPS provider’s web console open while you do this, in case you lock yourself out:
sudo ufw allow in on tailscale0 to any port 22 proto tcp
sudo ufw delete allow 22/tcp
sudo ufw status
box:box-setup does the same with its --ssh-tailscale-only flag. It refuses
to run if Tailscale is not up yet, so you cannot lock yourself out that way.
5. A terminal on the phone
Use any SSH app. Termius is a common choice on iOS.
- In the app, create a new SSH key and copy its public key.
- On the Mac, add it to the box:
ssh box 'cat >> ~/.ssh/authorized_keys', paste the key, then press Ctrl-D. - Add a host in the app: address
box.your-tailnet.ts.net, useralice, the key from step 1. - Turn Wi-Fi off and connect over mobile data to prove it works away from home.
Alternative: Tailscale SSH (sudo tailscale up --ssh on the box). It uses
your tailnet login instead of SSH keys, so there are no keys to copy to the
phone. It is fine for a personal tailnet. With plain keys you have one less
moving part.
Your coding agent as your devops person
Once the three devices can reach each other, you can hand the terminal work to your coding agent from your phone. There are two ways, and you can use both. Way A uses Claude Code’s Remote Control. Way B works with any agent that runs in a terminal.
A. Drive Claude Code on your Mac from the phone
Start or open a Claude Code session on the Mac, in the folder with your repos,
and turn on Remote Control for it. Then open that session in the Claude app on
the phone. The session runs on the Mac, so it has everything: your repos, the
box alias, your secrets tool, Xcode and the onebox skills.
Ask it things like:
- “Check the API logs on the box for errors in the last hour.”
- “The site is down. Find out why and fix it.”
- “Deploy main and tell me when the health check is green.”
Keep the Mac awake while you are away: turn on the keep-awake setting in the
Claude desktop app, or run caffeinate -dis in a terminal. A sleeping Mac
drops the session.
B. Run Claude Code on the box itself
For when the Mac is off. SSH to the box from the phone, then run Claude Code
inside tmux, so a dropped connection does not kill the session:
tmux new -As ops # attach to "ops", or create it
claude
Log in to Claude Code once on the box. Next time, tmux attach -t ops puts you
back where you left off. Another terminal agent works the same way: start it
inside tmux instead of claude. The box skills work here too, with box.ssh set to
localhost in the box’s own config.
What the agent should not do from the phone
- Sign iOS builds over SSH. See the next section.
- Anything destructive without asking you first: deleting volumes, dropping databases, force-pushing. A phone screen makes it easy to approve without reading. Read before you tap.
iOS signing over SSH: the keychain wall
If an agent (or you) starts a local signed iOS build on the Mac over SSH, it can fail with:
errSecInternalComponent
or security unlock-keychain answers “User interaction is not allowed”.
The signing certificate is present, but macOS refuses to let codesign use
its private key until a person at the Mac approves it once.
The fix:
- Sit at the Mac and run one signed build in your own Terminal
(
ship-ios:expo-local-buildprints the command). - When macOS asks “codesign wants to use the key …”, enter your login password and click Always Allow.
After that, remote and agent-driven builds sign without asking. If you are
away and have not done this yet, build on EAS instead
(expo.buildMode: "cloud"). It costs build credits, but needs no keychain.
Where the values go
| Value | Where |
|---|---|
| SSH alias for the box | box.ssh in ~/.config/onebox/config.json, e.g. "box" |
| The box’s tailnet name | HostName in ~/.ssh/config on the Mac, and in your phone’s SSH app |
| Phone SSH key | the box’s ~/.ssh/authorized_keys |
No secret goes in the onebox config. Tailscale’s own login lives in the Tailscale apps.
Check it works
tailscale statuson the box shows the Mac and the phone.- On the Mac:
ssh box uptimeworks at home, and again from a phone hotspot. - On the phone, with Wi-Fi off: the SSH app connects to the box.
- On a VPS: from a machine outside the tailnet,
nc -vz <public-ip> 22fails. - From the Claude app: ask the Mac session to run
ssh box docker ps, and it answers.
Common errors
- The box vanished from the tailnet after a few months. Key expiry. Log in
on the box (
sudo tailscale up), then disable key expiry for it (step 2). box.your-tailnet.ts.netdoes not resolve on the Mac. Tailscale’s DNS is off in the Mac app’s settings (“Use Tailscale DNS”), or another VPN is overriding DNS.ssh boxhangs in an agent session but works in your terminal. The key passphrase is not in the Keychain. Run thessh-add --apple-use-keychaincommand from step 3.- The Remote Control session is gone. The Mac went to sleep. Turn on keep-awake.
- Locked out of a VPS after changing ufw. Use the provider’s web console,
run
sudo ufw allow 22/tcp, and fix the tailnet first.
ZeroTier instead
- Create a network at my.zerotier.com and copy its network ID.
- Install ZeroTier on the box (
curl -s https://install.zerotier.com | sudo bash), the Mac and the phone, and join the network:sudo zerotier-cli join <network-id>on the box, the “Join network” button in the apps. - Authorize each device in the network’s member list.
- Give the box a fixed managed IP there, and use that IP as
HostNamein~/.ssh/config. ZeroTier has no MagicDNS-style names by default. - Allow SSH only on the ZeroTier interface on a VPS
(
sudo ufw allow in on <zt-interface> to any port 22 proto tcp; find the interface withip link, it starts withzt).
Everything from step 3 of the Tailscale steps onward is the same.