Run Claude Code or Codex over SSH from your phone
Put the coding agent on a server, start it in a session that survives disconnects, and check on it from your phone whenever you like. Here is a setup that is quick to build and safe to leave running.
Quick answer. On a Linux server, create a user, log in with an SSH key, install Node.js and the
agent CLI, and start the agent inside tmux. Detach, lock your phone, and reattach later from any SSH
client to see how far it got.
npm install -g @anthropic-ai/claude-code # or: npm install -g @openai/codex
tmux new -A -s agent
cd ~/projects/app && claude # or: codex
Why run the agent on a server
Coding agents such as Anthropic's Claude Code and OpenAI's Codex CLI work in a terminal: they read your repository, edit files, run commands and tests, and ask before risky steps. A long task can take many minutes. On a laptop that means keeping the lid open and the network up. On a server, the agent keeps working while you are on a train, and your phone becomes the window you check through.
The setup has three parts: a server you can reach over SSH with a key, the agent running in a session that does not end when you disconnect, and an SSH client on your phone that can draw the agent's full-screen interface.
Step 1: a server and a dedicated user
Any Linux machine works: a small VPS, a cloud VM, or a computer at home. The agent itself is light because the model runs at the provider; size the machine for your project's builds and tests. Create a separate user for the agent's work, without sudo, so its commands cannot touch the rest of the system:
sudo adduser dev
sudo mkdir -p /home/dev/.ssh
sudo cp ~/.ssh/authorized_keys /home/dev/.ssh/
sudo chown -R dev:dev /home/dev/.ssh
sudo chmod 700 /home/dev/.ssh && sudo chmod 600 /home/dev/.ssh/authorized_keys
Copying your own authorized_keys is a shortcut; you can also add only the key of the device you will
use, as in Add an SSH key to a server.
Step 2: key login, passwords off
Use an SSH key for every device you connect from, ideally a separate key for your
phone with a passphrase. Create one with ssh-keygen -t ed25519 or the
generator on this site, and confirm that key login works for the new user before you change anything
else:
ssh [email protected]
Then turn off password logins and direct root logins, so bots guessing passwords get nowhere:
sudo tee /etc/ssh/sshd_config.d/00-hardening.conf <<'EOF'
PasswordAuthentication no
KbdInteractiveAuthentication no
PermitRootLogin no
EOF
sudo sshd -t && sudo systemctl reload ssh # sshd on Fedora and RHEL
Keep your current session open and test a new login from a second terminal before closing it. Some cloud images set
PasswordAuthentication yes in a file of their own inside sshd_config.d; check with
sudo sshd -T | grep -i passwordauthentication.
Step 3: install the agent CLI
Both CLIs below are distributed through npm and need a current Node.js. Install Node.js from your distribution, from
NodeSource or with nvm; nvm installs into your home folder, so global packages do not need sudo. Log in as the
dev user and run:
# Claude Code
npm install -g @anthropic-ai/claude-code
claude
# Codex CLI
npm install -g @openai/codex
codex
The first start asks you to sign in or to provide an API key. On a server without a browser, the CLI shows a link or code to complete in a browser on another device; follow its prompts. The vendors also publish other installers and change details between releases, so check their current documentation if a step looks different.
Clone the project the agent will work on. Give the server its own deploy key or SSH key for the git host instead of copying your laptop's key there, as described in deploy keys.
ssh-keygen -t ed25519 -C "dev@agent-server" -f ~/.ssh/id_ed25519
cat ~/.ssh/id_ed25519.pub # add as a deploy key or to a machine account
git clone [email protected]:owner/app.git ~/projects/app
Step 4: keep it running when you disconnect
A program started in a plain SSH session is tied to it. When the connection drops, because you locked the phone or changed networks, the shell is hung up and the agent usually exits mid-task. There are three ways around it.
tmux: the interactive session lives on the server
tmux new -A -s agent # attach, or create if missing
cd ~/projects/app && claude # or codex
# detach with Ctrl+b, then d; the agent keeps working
tmux attach -t agent # later, from any device
This is the most flexible option and works with any client. Make it automatic with
ssh -t [email protected] tmux new -A -s agent. More on tmux, screen and keepalives in
SSH connection keeps dropping.
nohup: a non-interactive run with a log
Both CLIs have a non-interactive mode that takes a prompt and exits when done: claude -p and
codex exec. Combined with nohup it survives the disconnect and writes everything to a file:
cd ~/projects/app
nohup claude -p "Run the test suite and fix the failing tests" > ~/agent.log 2>&1 &
tail -f ~/agent.log
In this mode the agent cannot ask you questions, so what it may do without approval depends on its settings. Read the CLI's documentation on permissions before you leave it alone.
A client that keeps the session
The third way needs no setup on your side. Termphin, an SSH client from the team behind this site, uploads a small open-source helper to the server that keeps the shell running when the connection drops and reattaches you with the screen as it was. You start the agent as usual, lock the phone, and come back to the same view.
Step 5: private access with a mesh VPN
An SSH port on the internet with key-only login is reasonable. Closing it is better. A mesh VPN such as Tailscale, or your own WireGuard, gives the server and your phone private addresses that only your devices can reach:
- Install the VPN on the server and on your phone, and sign both into the same network.
- Connect to the server's private address or name instead of its public IP, and check that it works.
- Only then restrict SSH to the VPN interface in the firewall.
sudo ufw allow in on tailscale0 to any port 22 proto tcp
sudo ufw delete allow OpenSSH
sudo ufw enable
sudo ufw status verbose
Keep the cloud provider's web console at hand in case you lock yourself out. Your SSH client sees nothing special: just a different host name.
Checking on a long run from your phone
Connect, reattach and look around:
tmux attach -t agent # the agent's screen, as you left it
git -C ~/projects/app status
git -C ~/projects/app diff --stat
tail -n 50 ~/agent.log # for nohup runs
A few things make this pleasant on a small screen:
- A client that draws full-screen programs correctly. Coding agents use colours, box characters, spinners and constant redraws. Clients that handle the alternate screen and resizing badly turn that into noise.
- Easy special keys. You will press Esc, Ctrl+C, Tab and the arrow keys often to interrupt, accept or move through choices. A toolbar with these keys beats hunting for them on an on-screen keyboard.
- Sessions that survive a locked screen. You check, lock the phone, and check again an hour later without logging in and reattaching every time.
Termphin was built for this case: the terminal is drawn by the app rather than a web view, so agents and programs like htop and vim render correctly, the special-keys toolbar is yours to arrange, and its helper keeps the session alive across a locked screen or a network switch. It also has an SFTP file browser for a quick look at the files the agent changed.
Security checklist
- A dedicated user without sudo for the agent's work.
- Key-only SSH login, root login off, and a passphrase on the keys of your laptop and phone.
- A separate key on the server for the git host, limited to the repositories it needs.
- No production credentials or customer data on the machine. Treat it as something an automated tool controls.
- Keep the agent's approval prompts on unless the machine is disposable.
- Updates:
sudo apt update && sudo apt upgraderegularly, or unattended upgrades.
Troubleshooting
"command not found" after npm install
npm's global folder is not on your PATH. Run npm prefix -g and add its bin
subfolder to PATH in ~/.bashrc. With nvm, open a new shell or run
source ~/.nvm/nvm.sh.
"EACCES: permission denied" during npm install -g
Global installs are trying to write to a system folder. Do not use sudo with npm; install Node.js with nvm, or set a
prefix in your home folder with npm config set prefix ~/.npm-global and add
~/.npm-global/bin to PATH.
Garbled boxes or question marks on screen
The server's locale is not UTF-8 or TERM is wrong. Check locale and
echo $TERM; inside tmux it should be tmux-256color or screen-256color, outside
usually xterm-256color. Install a UTF-8 locale with sudo locale-gen en_US.UTF-8 on Debian
and Ubuntu.
The agent stopped when I locked the phone
It was running directly in the SSH session. Start it inside tmux next time, or use a client that keeps the session
alive. To find out what it finished, check git status and the log.
"Permission denied (publickey)" for the new user
The key is not in /home/dev/.ssh/authorized_keys or the permissions are too open. The folder must be
700, the file 600, both owned by dev.
FAQ
Can I run Claude Code or Codex on a server without a desktop?
Yes. Both are command-line programs that run in a terminal, so any Linux server you can reach over SSH works. The sign-in step may ask you to open a link in a browser on another device; follow the prompts the CLI prints.
Does the agent stop when my SSH connection drops?
If it runs directly in your SSH session, usually yes: the shell gets a hangup signal and its programs exit. Run it inside tmux or screen, or use a client that keeps the session alive on the server, and it carries on.
How big a server does a coding agent need?
The model runs at the provider, so the CLI itself is light. Size the server for your project instead: its build, tests and dependencies. A small VPS with 2 GB of memory is enough for many projects; heavy builds want more.
Should I open SSH to the internet for this?
You can, with key-only login and passwords turned off. A mesh VPN such as Tailscale or plain WireGuard lets you close port 22 to the public entirely, which removes the background noise of bots trying to log in.
Is it safe to let the agent run commands without asking?
Only in a place where its mistakes are cheap: a dedicated user without sudo, a disposable VM or container, and no production credentials. The approval prompts exist for a reason; flags that skip them trade safety for speed.
Why does the agent's screen look broken in my terminal?
Coding agents draw a full-screen interface with colours, box characters and redraws. A client that mishandles the alternate screen, Unicode or resizing garbles it. Check echo $TERM and your locale first, then try a different client.