SSD Nodes Learn 8GB RAM — $66/yr
Guides Matt ConnorBy Matt Connor

Use Claude Code from your phone

Claude Code runs in tmux on a VPS and your phone is only the window. SSH keys, mosh for flaky mobile data, tmux attach, and the keyboard fixes that matter.

Claude Code from your phone: how it actually works

Claude Code from your phone is not a mobile app. Claude Code runs on a VPS (virtual private server), inside a tmux session that stays open, and your phone opens an SSH (secure shell) connection to that session for as long as you are looking at it. Close the app and the agent keeps working, because the process never lived on the phone.

That split is the whole design. A phone operating system suspends an app seconds after you switch away from it, so any long job started on the phone stops. It also gets a new network address every time you walk from wifi onto mobile data. Both problems go away when the process runs on a server and the phone only draws the screen.

You need four things on the server: tmux to hold the session, SSH keys to get in, mosh for the network changes, and Claude Code itself. The phone side is one terminal app with a key row you can reach.

What you need on the VPS

A small Ubuntu 24.04 box is enough for the SSH and tmux parts. Claude Code asks for more. The official requirements as of July 2026 are Ubuntu 20.04 or newer on an x64 or ARM64 processor, with 4 GB or more of RAM. A 1 GB plan installs it and then loses the process to the kernel under load. Claude Code also needs a paid Claude account (Pro, Max, Team or Enterprise) or a Console account with API access, since the free Claude.ai plan does not include it.

Set the box up as an ordinary user with sudo, not as root. If the server is new, work through the first ten minutes on a new VPS first, because the SSH changes later in this guide are easier once the user and the firewall exist.

sudo apt update && sudo apt install -y tmux mosh
curl -fsSL https://claude.ai/install.sh | bash
claude --version

The installer puts the binary at ~/.local/bin/claude, and claude --version prints a line like 2.1.211 (Claude Code). If it prints command not found, that directory is not on your PATH yet: log out, log back in, then check with command -v claude. claude doctor prints installation and settings diagnostics without starting a session.

Log in once now, from a laptop, before you depend on the phone. Run claude in a project directory and follow the login prompt. The flow asks you to open a URL in a browser and bring a code back to the terminal, and juggling two apps on a phone screen to do that is slow. Do it once on a real keyboard and the credentials stay on the server.

Start Claude Code inside tmux so a dropped connection cannot kill it

tmux new -s claude
cd ~/projects/api
claude

Detach with Ctrl-b and then d. tmux prints [detached (from session claude)] and hands you back the shell. Now close the app, lose signal, or put the phone in your pocket. The pane keeps running.

tmux ls
tmux attach -t claude

tmux ls prints one line per session, such as claude: 1 windows (created Thu Jul 30 09:14:02 2026). tmux attach -t claude puts you back exactly where you left, including the half-finished edit.

This works because tmux runs a server process of its own, and your shell and Claude Code are children of that server rather than of sshd. When the SSH connection ends, the kernel sends the hangup signal, SIGHUP, to the processes attached to that connection, and the tmux server is not one of them. Without tmux, the same screen lock that drops your connection stops Claude Code in the middle of a tool call. Running Claude Code on a VPS inside tmux covers the session layout in more depth.

Run tmux on the server, never on the phone. Typing tmux inside a session you are already attached to prints sessions should be nested with care, unset $TMUX to force, and forcing it gives you two prefix keys to fight over.

Attach automatically on every login

Typing the attach command on a touch keyboard gets old. Put this at the end of ~/.profile on the server:

if command -v tmux >/dev/null 2>&1 && [ -z "$TMUX" ] && [ -t 1 ]; then
  exec tmux new-session -A -s claude
fi

new-session -A -s claude attaches to the session named claude if it exists and creates it if it does not, so one command covers both cases. exec replaces the login shell with tmux, so leaving tmux closes the connection instead of dropping you at a bare prompt. When you need a plain shell, skip the file: ssh you@server -t "bash --noprofile".

Put it in ~/.profile and not in ~/.bashrc. ~/.bashrc also runs for non-interactive sessions, so file transfers break: scp and sftp read the unexpected output as protocol data and fail with Received message too long. ~/.profile runs for login shells only, which is what an interactive SSH session is.

~/.profile is also where Ubuntu adds ~/.local/bin to PATH. If claude works right after login but a shell inside tmux says command not found, that ordering is the reason, so start tmux from a login shell as above rather than from a script that skips the profile.

Both apps speak SSH and mosh and both store keys in the app. The difference is the interface.

Blink Shell is command driven. At its prompt you type ssh you@server or mosh you@server, the same syntax as a desktop terminal. Settings open by typing config, and the Keys section creates a pair for you.

Termius is form driven. You fill in a host entry, then switch that host from SSH to Mosh in the host details. Termius ships its own mosh implementation and supports mosh 1.3.0 and newer, so the server still needs the mosh package installed.

Generate the key inside the app in both cases, and never copy an existing private key onto the phone. The app shows you the public half, which is the single line you add to ~/.ssh/authorized_keys on the server. Per device SSH keys and how to revoke one covers the naming and the revoke step, which matters more for a phone than for a laptop.

Turn on the terminal app's own biometric or passcode lock. Without it, an unlocked phone is an open shell on your server for as long as the screen stays awake.

Android: Termux

pkg upgrade
pkg install openssh mosh
ssh-keygen -t ed25519 -C "pixel"
cat ~/.ssh/id_ed25519.pub

Termux packages OpenSSH and mosh in its own repository, so ssh, ssh-keygen and mosh behave the way they do on a desktop. Add the printed public key line to ~/.ssh/authorized_keys on the server, then connect with mosh you@server.

The Android on-screen keyboard has no Esc key and no Ctrl key, and Claude Code needs both. Termux can draw its own key row. Put one line in ~/.termux/termux.properties:

extra-keys = [['ESC','|','/','HOME','UP','END','PGUP'],['TAB','CTRL','ALT','LEFT','DOWN','RIGHT','PGDN']]

Then run termux-reload-settings and the row appears above the keyboard. The same reload picks up a monospace TrueType font dropped at ~/.termux/font.ttf.

Android may stop Termux while it sits in the background, and here that costs you nothing but a reconnect. The session and the agent are on the server.

Why does the terminal freeze when I leave wifi, and what does mosh fix?

An SSH connection is a TCP (transmission control protocol) connection, and a TCP connection is identified by both addresses and both ports. Walk out of wifi range and the phone gets a new address from the mobile network, so the old connection matches nothing on either end. Nothing announces this. The terminal simply stops responding until TCP gives up, and then ssh prints client_loop: send disconnect: Broken pipe. To kill a frozen session at once, press Enter, then ~, then ..

mosh (mobile shell) removes that failure mode. It uses SSH once to log in and start a mosh-server process, reads back the UDP (user datagram protocol) port that server picked, and closes the SSH connection. After that the two sides exchange UDP datagrams authenticated with a shared session key, so the session is identified by that key and not by your address. A new address just carries on. mosh also echoes your typing locally and repaints when the server disagrees, which is why it stays usable on a slow mobile link.

mosh uses a UDP port between 60000 and 61000, so open that range:

sudo ufw allow 60000:61000/udp
sudo ufw status

Opening ports with ufw has the rest of the firewall picture. If your provider offers a separate network firewall in its control panel, add the same range there too, because a ufw rule cannot affect a filter that sits in front of the machine.

Two mosh failures are common. A login that succeeds and then hangs, showing Nothing received from server on UDP port 60001., means that UDP range is blocked somewhere between the phone and the server. A connection that reports mosh-server not found means the package is missing on the server or is absent from the login PATH. Install it, or point at it directly with mosh --server=/usr/bin/mosh-server you@server.

mosh also refuses to run when the login locale is not UTF-8, and says so: mosh-server needs a UTF-8 native locale to run. Fix the locale on the server, not on the phone.

locale
sudo locale-gen en_US.UTF-8
sudo update-locale LANG=en_US.UTF-8

Two things mosh does not do. Its README states that mosh does not support X forwarding or the non-interactive uses of SSH, including port forwarding, so previewing a web app that Claude Code just started still needs plain ssh -L 8080:127.0.0.1:8080 you@server. It also synchronises only the visible screen, so it has no scrollback of its own. That second limit costs nothing here, because tmux keeps the scrollback: Ctrl-b then [ enters copy mode, a drag or the arrow keys scroll, and q leaves.

Make a phone screen usable

Four lines in ~/.tmux.conf on the server do most of the work:

set -g mouse on
set -g status-position top
set -g default-terminal "tmux-256color"
set -g history-limit 20000

mouse on turns a touch drag into a scroll and a tap into a pane or window selection, which replaces most of the prefix keys that are awkward to type. status-position top moves the tmux status line off the bottom edge, where the on-screen keyboard and its suggestion bar cover it. default-terminal matters because tmux otherwise announces a screen terminal to Claude Code, and colours and box drawing come out worse than they need to. If tmux then refuses to start with missing or unsuitable terminal: tmux-256color, the terminfo entry is missing: sudo apt install ncurses-term.

Learn four keys and the rest is comfortable.

  • Esc interrupts Claude mid-response and keeps the work already done, so it is the key you want closest to your thumb.
  • Ctrl+C interrupts a running operation as well. At an idle prompt the first press clears the input and a second press exits Claude Code, so it is the blunter tool.
  • Esc twice clears a draft prompt, and at an empty prompt it opens the rewind menu instead.
  • For a multi-line prompt, type \ and then Enter. That form works in every terminal. Shift+Enter is native only in a short list of desktop terminals, and the mobile clients are not in it.

Avoid split panes. A phone in portrait is around 40 columns wide, so a vertical split leaves 20 columns per pane and every diff wraps into noise. Use tmux windows instead: Ctrl-b c creates one and Ctrl-b n moves to the next. Turn the phone sideways when you need to read a diff properly.

A long session on a small screen is mostly a context problem, so managing the Claude Code context window is worth reading before you try to run a full day of work from a train.

Lock it down: keys only, no passwords

The phone now holds a key to a machine that edits your code and runs commands. Turn password authentication off. A drop-in file is safer than editing sshd_config directly, because Ubuntu's sshd_config includes /etc/ssh/sshd_config.d/*.conf at the top and the first value found for a setting is the one used.

sudo tee /etc/ssh/sshd_config.d/99-phone.conf >/dev/null <<'EOF'
PasswordAuthentication no
KbdInteractiveAuthentication no
PubkeyAuthentication yes
PermitRootLogin no
EOF
sudo sshd -t && sudo systemctl reload ssh

sshd -t parses the config and prints nothing when it is valid. Skip it and one typo means sshd fails on reload. Keep your working session open and test from a second connection before you close anything, because a wrong key now gives you Permission denied (publickey). and, with passwords off, no fallback. The recovery path at that point is your provider's console.

Give every device its own key. Losing the phone then means deleting one line from ~/.ssh/authorized_keys, and your laptop keeps working. One shared key means changing the key on every device you own.

If you move SSH to another port on Ubuntu 24.04, note that the listener belongs to ssh.socket, so a Port line on its own changes nothing. Run sudo systemctl edit ssh.socket, clear the default with an empty ListenStream=, then set your port on the next line. Hardening SSH on a VPS covers that and the rest of the surface.

fail2ban for SSH adds little security once passwords are off, because a guessed password cannot be accepted at all. What it does add is quiet logs, which makes a real login attempt easy to spot.

The stronger option is to keep SSH off the public internet. Put the server behind a WireGuard VPN you host yourself, bring the tunnel up on the phone on demand, and give sshd a ListenAddress on the tunnel only. mosh works over the tunnel because both sides are UDP. One caveat: the tunnel adds packet overhead, so if large transfers stall, lower the MTU (maximum transmission unit) in the phone's WireGuard config.

One last point about working this way. From a phone you approve permission prompts on a screen showing a few lines of diff at a time. That is a reason to keep the guardrails rather than to switch them off. Running Claude Code safely on a VPS covers the user and directory limits worth setting before your main way in is a touchscreen.

When you reattach and something is wrong

tmux attach printing no server running on /tmp/tmux-1000/default means the tmux server is gone, which nearly always means the machine rebooted. Check with uptime. Kernel updates from automatic security updates reboot the box, and a rebooted box has no tmux session, so treat any Claude Code run as something you can restart.

can't find session: claude is different. The tmux server is running but that name is not there. tmux ls shows what does exist.

If you attach and find a plain shell prompt where Claude Code used to be, the process ended without the session ending. Look at dmesg -T | tail for a line like Out of memory: Killed process 4821 (claude), which is what a box below the 4 GB requirement does during a large edit. No such line means Claude Code exited on its own, and the shell's scrollback above the prompt holds the reason.

A window that comes back tiny, with unused space around it, means two clients are attached at different sizes, because tmux sizes a window to fit the smallest attached client. Your laptop is still holding the session at 200 columns wide while the phone asks for 40. Detach the others as you attach: tmux attach -d -t claude.

FAQ

Can I run Claude Code on the phone itself instead of on a VPS?

No. The supported platforms as of July 2026 are macOS, Windows, Ubuntu 20.04 or newer, Debian 10 or newer, and Alpine 3.19 or newer, with 4 GB or more of RAM. Android and iOS are not on that list. A phone also sleeps its apps and changes network address constantly, which is what a long agent run cannot tolerate. Run it on a server and use the phone as a display.

Does the session survive if I close the app or lose signal?

Yes, and two separate pieces do that work. tmux keeps the process running on the server, so nothing dies when the connection ends. mosh keeps the connection itself alive across an address change, so switching from wifi to mobile data does not even cost you a reconnect. With plain SSH and no tmux, a dropped connection sends SIGHUP and Claude Code stops mid-task.

Why does mosh connect and then show nothing?

A login that succeeds and then hangs with Nothing received from server on UDP port 60001. means UDP 60000 to 61000 is not open. Add the range in ufw, and add it again in your provider's network firewall, which is a separate control on most panels. If mosh instead reports that mosh-server was not found, the server is missing the package: sudo apt install mosh.

How do I interrupt Claude Code from a keyboard with no Esc key?

Add a key row. Termux configures one with extra-keys in ~/.termux/termux.properties, and Termius and Blink both ship a row you can edit in settings. Esc interrupts a running response and keeps the work already done. Ctrl+C also interrupts, but pressing it twice at an idle prompt exits Claude Code, so reach for Esc first.

Is opening SSH to the internet safe enough for this?

With password authentication off, the only credential that can succeed is a key that never leaves your devices, which is a reasonable risk for a machine you can rebuild. Give each device its own key so a lost phone costs you one line in authorized_keys. If you would rather not answer on a public port at all, put the box behind WireGuard and let sshd listen on the tunnel address.