sshai docs
Everything from first install to daily use. If you'd rather follow along visually, the walkthrough covers setup in five short steps.
Getting started
The shape of the thing: a small server (sshai) runs on your machine and exposes your tmux sessions — where your coding agent lives — to your phone, only over your private Tailscale network. Setup is four steps and about five minutes.
What you need
- Your license — shown after checkout; retrievable anytime by signing in.
- A server— any Ubuntu or Debian machine: a $5/month VPS (Hetzner, Hostinger, DigitalOcean…), a spare Mac, a Raspberry Pi. 1 GB RAM is enough for sshai; your agent sets the real requirement.
- Tailscale account— free. Created in step 1 if you don't have one.
- Agent account — Claude subscription or API key for Claude Code, ChatGPT for Codex, and so on.
1 · Phone: install Tailscale
Install Tailscale from the App Store and sign in with Google, GitHub, or Apple. That creates your tailnet — a private network between your devices. Leave its VPN toggle on; it costs effectively no battery.
2 · Server: run your install command
SSH into the server and paste the one-liner from your account. It looks like this, with your own key:
ssh you@your-vps
curl -fsSL https://sshai.co/install | SSHAI_LICENSE=SSHAI-XXXX-XXXX-XXXX-XXXX bashHere's the whole run, so you know what to expect:
==> Checking license
license ok · saved to ~/.config/sshai/license
==> Installing system packages (tmux, build tools)
==> Installing Tailscale
==> Connecting this machine to your tailnet — approve the login link below
To authenticate, visit:
https://login.tailscale.com/a/8f3c21ab94e7 ← open this on your phone
==> Installing Node 22 (NodeSource)
Which coding agent will this server run?
1) Claude Code (claude)
2) OpenAI Codex (codex)
3) OpenCode (opencode)
4) Gemini CLI (gemini)
5) Kimi Code (kimi)
6) other — I'll type the command myself
Choice [1-6]: 1
==> Installing claude (@anthropic-ai/claude-code)
==> Downloading sshai
==> Installing the sshai service
==> One more step: log claude in (opens now — finish its login, then quit it)
sshai is running.
2. On your iPhone: install Tailscale + the sshai app, then set the
server address to: 100.84.12.7Three things worth knowing about what just happened:
- Your key is saved to
~/.config/sshai/licenseand your agent choice to~/.config/sshai/agent— future runs of the same command update sshai without asking anything. Better: the server checks for new releases daily, and when one exists the app shows an update button next to that machine — one tap updates it (or all your machines at once). Your sessions survive the restart. - sshai lives in
~/sshaiand runs as the systemd servicesshai: starts on boot, restarts on failure, and always keeps a session namedmainready. - The address it prints (
100.x.y.z) is a tailnet address — it only exists inside your private network.
3 · Agent: log in once
If the installer just installed your agent, it opened its login for you. If you skipped it, run the agent's command once and finish its sign-in:
claude # or codex / opencode / gemini — whatever you chose
# … complete the login it shows, then quit (ctrl-c) …Every sshai session on this server shares that credential from now on.
4 · Connect the app
- Install the sshai iPhone app.
- Settings (gear) → Add server→ name it ("vps") and enter the address from step 2 — just the IP:
Name vps
Address 100.84.12.7 ← http:// and port 7423 are filled in for you
Token (leave empty unless you set one — see Token lock)- Back on the list you'll see the
mainsession waiting under your server's name. Tap it — that's your terminal. - Type your agent's command (or create an agent session with +) and you're coding from your phone.
Using sshai
Sessions
A session is a tmux session on your server. It survives disconnects, phone reboots, flights, and weekends — whatever is running inside keeps running. The rhythm that works: one session per project.
- Create — tap +. Pick a name, a directory, and what to run:
Server vps
Name veca-api
Directory ~/code/veca-api
Run claude ← the server's agent is the default;
"claude --continue" resumes its last conversation- Switch — go back, tap another. Instant; nothing is interrupted.
- Rename — long-press the row.
- Kill — swipe left. This ends whatever is running in it.
- The green dot = a client is attached to that session right now.
Windows
Inside a session, tmux windows are tabs. The classic setup for a project: agent in window 1, tests in 2, dev server in 3.
- Tap ⧉ (in the key bar or the top bar) to open the windows sheet.
- Tap a window to switch; + creates one in the same directory; swipe left to rename or kill.
- The check mark shows the active window; the row shows what's running in it.
Key bar
The row above the keyboard. Defaults: esc · tab · ⇧tab · ctrl · shift · arrows · ^C · ^R · paste · A- · A+, with ⧉ and hide-keyboard pinned at the right.
- ctrl and shift are one-shot modifiers: tap the modifier (it lights up), then the key.
ctrl+cfrom the keyboard sends ^C;shift+entergives a newline without submitting — the way to write multi-line prompts to your agent. - Customize everything — Settings → Action keys: add keys from the catalog (home/end, pgup/pgdn, ^D ^Z ^L ^A ^E ^K ^U ^W, enter…), remove, reorder, and choose what stays pinned.
Scrolling
Drag anywhere in the terminal. sshai drives the scroll on the server through tmux, so it always does the right thing: your agent's conversation scrolls the transcript, a shell scrolls its history, vim scrolls the buffer. Scroll back down to the bottom and live output resumes.
Multiple servers
Add every machine you own — Settings → Add server. Each becomes its own named section in the list with its sessions under it, fetched independently, so one machine being offline never blocks the rest. The + sheet gets a server picker, and each server's configured agent is its default.
office mac 100.94.190.55
● sshai claude · ~/sshai · 1h
scratch zsh · ~ · 2d
vps · hetzner 100.111.166.103
● veca-api claude · ~/code/veca-api · 4h
deploy zsh · /var/www · 6d
homelab pi 100.87.4.21
● sensors python · ~/iot · 12dWeb terminal
Every server also serves a browser terminal — http://<tailnet-ip>:7423from any device on your tailnet, Android included. Same sessions, same scrolling. On iPhone, "Add to Home Screen" gives it an app icon, but the native app is the better experience.
Maintenance
Updating
Re-run your install command on the server:
curl -fsSL https://sshai.co/install | bash
# ==> Using saved license from ~/.config/sshai/license
# ==> Using saved coding agent: claude
# … downloads the new version, restarts the service …Sessions survive the restart — your agent keeps working; the app reconnects within a second.
Token lock (optional)
Tailscale already restricts access to devices you've signed in. If you share your tailnet with other people, add a second lock:
sudo systemctl edit sshai
# in the editor that opens, add:
[Service]
Environment=SSHAI_TOKEN=pick-something-long-and-random
sudo systemctl restart sshaiThen put the same token in the app: Settings → your server → Token. Requests without it get 401.
Uninstall
sudo systemctl disable --now sshai
sudo rm /etc/systemd/system/sshai.service && sudo systemctl daemon-reload
rm -rf ~/sshai ~/.config/sshai
# tmux/node/tailscale stay — remove them only if nothing else uses themSecurity model
- Invisible by construction — sshai binds your Tailscale address (100.x.y.z) and loopback, never
0.0.0.0. Port scanners on the internet find nothing because there is nothing. - WireGuard end to end— Tailscale encrypts all traffic; that's why plain http inside the tunnel is fine.
- No phoning home — the only time your server talks to sshai.co is license validation during install/update. Terminal traffic never leaves your tailnet; there is no telemetry.
- Agent power is your policy— sshai doesn't expand what your coding agent can do; it changes where you can supervise it from. Run the agent with whatever permissions you'd give it over SSH.
Your license
- Sign in with GitHub (the username from checkout) or Google (your payment email) — your key and install command are always there.
- Your post-checkout confirmation link never expires.
- One license covers every server you personally run — Mac, VPS, Pi, all of them.
Troubleshooting
App can't connect. In order: is Tailscale toggled on, on the phone? Then on the server:
tailscale status # both devices listed and not "offline"?
systemctl status sshai # active (running)?
journalctl -u sshai -n 20"No tmux session named …" — it was killed. The service recreates main on restart:
sudo systemctl restart sshaiLicense rejected at install. Copy the key exactly from your account — the format is SSHAI- plus four groups of four. Refunded licenses are revoked by design.
Agent misbehaves inside a session.Run the agent's command directly over SSH first. If it fails there too, it's an agent/account issue; if it works over SSH, it works in sshai — try killing and recreating the session.
Anything else — reply to your Stripe receipt with the output of journalctl -u sshai -n 50and we'll dig in.