DIY stack
tmux, mosh and Tailscale: the DIY stack for coding agents on your phone
The classic way to run Claude Code or Codex from a phone is a terminal app, a private network, a connection that survives roaming, and a session that survives everything else. Each piece is free and well understood. Here's the setup with exact commands, and an honest look at where it gets painful.
Quick answer
Install Tailscale on the server and your phone, then turn on tailscale set --ssh so the server is reachable only over your private tailnet. Run the agent inside tmux new -A -s main so it outlives your connection. Add set -g allow-passthrough on and the extended-keys lines to ~/.tmux.conf for Claude Code. Connect with mosh (mosh dev@server -- tmux new -A -s main) from Blink, Termius or Termux. It works well. Its weak spots are a full-screen TUI on a small screen and no push notifications unless you add hooks.
If you've searched for how to use Claude Code from a phone, you've probably seen this stack in a dozen blog posts. That's because it works. Tailscale gives your phone a private, encrypted path to the server with no open ports. mosh keeps the connection alive when you switch from Wi-Fi to 4G or lock the phone. tmux keeps the agent running when the connection does drop. Here's how to put the three together properly.
The stack
| Layer | Tool | What it solves | Skip it if… |
|---|---|---|---|
| Network | Tailscale (Tailscale SSH) | Reach the server privately, even behind NAT; no public SSH port; SSO-backed access | The server already has hardened public SSH and you're happy with it |
| Transport | mosh | Survives roaming, sleep and bad signal; local echo hides latency | You only connect from a stable network |
| Session | tmux | The agent keeps running when you disconnect; several windows per project | Never. This is the layer that matters most. |
| Client | Blink, Termius, Termux… | A terminal on the phone | — |
tmux setup
Install it and start a named session that you can re-attach to from anywhere:
sudo apt install tmux # Debian/Ubuntu (dnf / apk elsewhere)
tmux new -A -s main # attach to "main", or create it
cd ~/src/my-app && claude # or: codex, agy, opencode…
# detach with Ctrl-b then d — the agent keeps running
-A makes the same command work the first time and every time after, which makes it a good one to save as a snippet in your phone's terminal app. Then give tmux the settings agents need. Anthropic's terminal configuration docs say that inside tmux, Shift+Enter submits instead of adding a newline, and notifications never reach the outer terminal, unless you add these lines:
# ~/.tmux.conf
set -g allow-passthrough on
set -s extended-keys on
set -as terminal-features 'xterm*:extkeys'
# quality of life on a phone
set -g mouse on # scroll and pick panes with your finger
set -g history-limit 50000 # agents print a lot
Apply it with tmux source-file ~/.tmux.conf. Even with extended keys, many phone keyboards can't send Shift+Enter at all. Claude Code also accepts Ctrl+J, or \ followed by Enter, for a newline, and both work in any terminal.
Use one tmux window per project or per agent. Ctrl-b c opens a new window and Ctrl-b n moves to the next. For several sessions on the same repository, give each its own git worktree. The 24/7 guide covers that and what happens on reboot. tmux sessions don't survive a reboot.
mosh vs ssh
Plain SSH runs over one TCP connection. When your phone changes network, or iOS suspends the app for a while, that connection dies, and you re-connect and re-attach. mosh logs in over SSH, starts mosh-server on the server, and then switches to its own UDP protocol, which carries on through IP changes and sleep. It also echoes your typing locally, so a 200 ms link feels responsive.
# on the server
sudo apt install mosh # Fedora: sudo dnf install mosh · Alpine: apk add mosh
# from a client
mosh dev@my-server -- tmux new -A -s main
mosh uses UDP ports 60000–61000. Over a public IP you'd have to open those in your firewall, for example with sudo ufw allow 60000:61000/udp plus your cloud provider's firewall. Over Tailscale the traffic stays inside the tailnet, so no public port is needed. One limit: mosh only syncs the visible screen, so there's no scrollback through mosh itself. mosh's own docs recommend tmux or screen for history, which is one more reason to run both.
Tailscale SSH
Tailscale puts your server and phone on a private WireGuard network (a tailnet). Tailscale SSH goes a step further: Tailscale handles SSH authentication with your tailnet identity, so you don't distribute SSH keys at all.
# on the server (Linux)
curl -fsSL https://tailscale.com/install.sh | sh
sudo tailscale up # log in to your tailnet
sudo tailscale set --ssh # enable Tailscale SSH
According to Tailscale's docs, tailscale set --ssh makes tailscaled take over port 22 for traffic coming from your tailnet. Any normal SSH client then connects with ssh dev@my-server, using the machine's MagicDNS name. Some details:
- Check mode. The default policy uses
"action": "check", so you're asked to re-authenticate in a browser from time to time. A login URL appearing in the terminal is expected. - Server platforms. Linux is fully supported. On macOS, only the open-source
tailscale+tailscaledCLI build can act as a Tailscale SSH server, so a Mac mini with the App Store app should use regular SSH over the tailnet. - Close the public port. Once you've confirmed you can reach the box over the tailnet, close public port 22 in your provider's firewall. Do it in that order, with a second session open, so you don't lock yourself out.
On the phone, install the Tailscale app, sign in to the same tailnet and leave it connected. Your terminal app then reaches my-server as if it were on your local network.
iOS and Android clients
| Client | Platforms | mosh | Notes |
|---|---|---|---|
| Blink Shell | iPhone, iPad | Yes | Built around mosh; strong hardware-keyboard support on iPad. $19.99/year after a two-week trial, per blink.sh. |
| Termius | iOS, Android, desktop | Yes | Free Starter tier includes SSH and mosh; cross-device sync is on Pro ($10/month billed annually, per termius.com/pricing) |
| Termux | Android | Yes (pkg install openssh mosh) | A full Linux userland on the phone; free and open source |
| JuiceSSH | Android | Yes | Listed as a mosh client on mosh.org |
Whatever client you pick, set up an extra key row with Esc, Ctrl, Tab and arrows. Claude Code uses Esc to interrupt and Shift+Tab to cycle permission modes, and neither is on a stock phone keyboard.
Where it breaks
The stack is reliable. The friction is everything around reliability.
- A desktop TUI on a 6-inch screen. Claude Code, Codex and agy are built for 100+ columns. On a phone you're reading wrapped diffs, scrolling tool output with your thumb and hunting for the input line.
- No push notifications. When the agent finishes or needs approval, nothing tells you unless you add a hook. The terminal only notifies you while the app is in front. Our guide to approving prompts from your phone covers the ntfy hooks people bolt on.
- Approvals buried in scrollback. A permission prompt is a few lines in a busy pane. If you come back after an hour, you have to find it, read it and answer it with arrow keys.
- The background problem. iOS suspends terminal apps soon after you leave them. mosh recovers when you return, but the app can't watch the session for you while it's in the background.
- Copy and paste. Selecting text across tmux, mosh and a phone terminal is painful. Long URLs, such as login links, are the worst case.
- Several servers, several agents. Every new box means another Tailscale node, another host entry and another tmux layout to remember.
None of this is a reason to avoid the stack. It's free, it works with every agent, and you control every piece. It's a reason to know what you're signing up for. Our comparison of SSH terminal apps and Maude goes into the trade-off in detail.
Or use an app built for it
Maude replaces the client and session layers for agent work. A small daemon on the server owns the sessions, so they keep running without tmux, and the app shows them as chat, with tool cards, diffs, push notifications with Allow/Deny, and an inbox. You can keep Tailscale: Maude works with tailnet and LAN servers because the server connects out to Maude's relay, with SSH as the fallback. And when you need a shell, each session has a real terminal. It works with Claude Code, Codex, OpenCode, Grok Build and Antigravity.
Frequently asked questions
tmux or screen for Claude Code?
allow-passthrough and extended-keys), it splits and scripts more easily, and most phone-terminal guides assume it.