Guide

Run Codex CLI From Your Phone: Device Auth, tmux, and Read-Only Mode

Codex CLI runs on your server, not your phone — your phone is the terminal. Here's the setup that actually works over SSH: device-code login instead of the broken port-1455 browser flow, tmux so nothing dies when you lock the screen, and a read-only sandbox for phone-sized reviews.

CC Chen Chen· Founder·2026-08-07·10 min read

The short answer

Codex CLI does not run on your phone. It runs on a machine that has your repo and your toolchain — a Mac, a home server, a VPS — and your phone is the terminal attached to it over SSH.

Three things make that setup work, and two of them are Codex-specific:

  1. Log in with device auth, not the browser flow. codex login starts a local listener on port 1455 and waits for a browser on the same machine to hit the callback, which a headless server does not have. codex login --device-auth prints a short code you approve from any browser instead.
  2. Start it inside tmux, so locking your phone or hopping from Wi-Fi to LTE doesn’t SIGHUP the run.
  3. Keep the sandbox on. Codex ships with a real OS-level sandbox — Seatbelt on macOS, Landlock plus seccomp on Linux — and a phone is the worst possible screen for reviewing a change you can’t undo.

The rest of this is the same SSH plumbing you’d use for any remote work: Tailscale so the box is reachable without opening a port, and a client with a real Ctrl key. If you’ve already done this for Claude Code, skip to the login problem — that section and the sandbox one are where the two tools genuinely diverge.

Three routes

There are three different things people mean by “Codex from my phone,” and they solve different problems.

Codex in the ChatGPT appSSH + tmux to your boxcodex exec one-shot
Where the code livesCloud container, or a connected Mac hostYour machineYour machine
Start work from the phoneYesYesYes
Full-screen TUI on a 6-inch screenNo — native app UIYesNo — plain output
Read logs, systemctl, git log in the same sessionNoYesNot interactively
Works against a headless VPSCloud onlyYesYes
Needs a desktop app runningFor the local-host modeNoNo

Codex in the ChatGPT mobile app. OpenAI brought Codex into the ChatGPT iOS and Android apps on 14 May 2026 (9to5Mac). You can start tasks, steer threads, and approve commands from the phone. Connecting it to your own machine is done by scanning a QR code generated by the Codex desktop app, and at announcement that host-connection path was Mac-only, with Windows “coming soon.” Check OpenAI’s Codex cloud docs for the current state rather than trusting any blog post, including this one — this area has moved every few weeks.

SSH + tmux. The route this guide covers end to end. It’s the only one that puts the agent in the same session as journalctl, docker ps, and git diff, which is what you actually want when you’re out of the house and something is broken.

codex exec. Underrated on mobile, and covered below. No TUI to fight with.

These aren’t exclusive. Most people who use both end up keeping SSH, because a bridge to a desktop app can’t help you when the thing that’s down is the server.

The login problem

This is the step that stops people, and it has nothing to do with phones — it’s that your server is headless.

codex login opens a browser-based OAuth flow and spins up a local HTTP server on port 1455 to catch the redirect. On your laptop that’s invisible. On a VPS over SSH there’s no browser to open, and pasting the URL into your phone’s browser doesn’t help either: the callback goes to localhost:1455, which on your phone is your phone.

The fix is device auth:

codex login --device-auth

Codex prints a URL and a short one-time code. Open the URL on your phone or laptop, sign in to ChatGPT, type the code, done — the CLI collects its tokens over the network and stores them in ~/.codex/. Same pattern a TV app uses. Documented under OpenAI’s Codex auth docs.

One catch worth knowing before you’re stuck at a train station: device-code login can be disabled in personal ChatGPT security settings or by a workspace admin, in which case the flow is rejected outright (openai/codex #9253). If that happens, tunnel the port instead. From your laptop:

# terminal 1 — keep this open, closing it kills the tunnel
ssh -L 1455:localhost:1455 you@your-server

# terminal 2 — same host
ssh you@your-server
codex login

Copy the URL Codex prints into your local browser. The redirect to localhost:1455 now travels back down the tunnel to the CLI process on the server. If the mechanics of -L are fuzzy, SSH tunnels explained covers it properly.

You can also authenticate with an API key, which bills per-token against your API account rather than using a ChatGPT plan. Fine for CI, usually not what you want for interactive work.

Do this login step once, from a laptop, before you ever need it from a phone. Approving a device code on the same phone you’re SSHed in from works, but doing it for the first time at 1am during an incident is not the moment to discover your workspace has device codes turned off.

The SSH + tmux setup

Install on the server, not the phone:

npm install -g @openai/codex
# or: brew install --cask codex
codex --version

Version churn is fast — @openai/codex on npm was at 0.146.x in early August 2026. Since v0.128.0 there’s a built-in codex update, so you can upgrade from the phone without remembering which package manager you used.

You also need:

  • A machine that stays awake, with tmux installed.
  • Tailscale on the machine and the phone, so it’s reachable without port forwarding or dynamic DNS — this also works behind CGNAT, which is every mobile carrier. Setup is identical to the walkthrough in Run Claude Code from your phone; auth trade-offs are in Tailscale SSH, explained.
  • An SSH key, not a password. See SSH key vs password.
  • A phone SSH client with a real modifier row. The Codex TUI needs Ctrl, Esc, and arrows; without them it’s unusable, and there is no server-side workaround. (TermAI has Tailscale built in, so the phone side is one app rather than two.)

Then, once, from anywhere:

ssh you@your-server
cd ~/code/my-project
tmux new -As codex     # attach if it exists, create if it doesn't
codex

Detach with Ctrl+b then d. From the phone later:

tmux attach -dt codex

The -d matters. tmux renders every window at the size of the smallest attached client, so attaching from a phone while your desktop is still attached collapses the desktop to phone width. -d detaches the other client as you attach.

Two more lines that pay for themselves, in ~/.tmux.conf on the server:

set -g mouse on
set -g history-limit 50000

Mouse mode is the single biggest quality-of-life win on a phone — you scroll Codex’s output with a finger instead of entering copy mode. The scrollback size means the start of a long run is still there when you get back. Alternatives to tmux (nohup, screen, systemd) are compared in keeping a process running after SSH disconnects.

codex resume vs tmux

Codex has something worth knowing about before you over-engineer the session handling: first-class session resumption.

codex resume --last          # reopen the most recent session
codex resume                 # pick from a list
codex exec resume --last "now add error handling"

Sessions are written as JSONL under ~/.codex/sessions/YYYY/MM/DD/. Worth understanding what that actually restores: the model’s in-context state isn’t saved, so resuming replays the transcript to rebuild context. Close enough for continuity, not identical to never having left.

This does not replace tmux, and the distinction bites people on mobile. resume recovers the conversation; tmux keeps the process running. If your phone locks mid-turn and the agent isn’t inside tmux, the turn dies partway through — possibly with files half-written — and resume gives you back the chat, not the completed work. Use both:

  • tmux so a run that’s in flight when your screen locks keeps going.
  • resume for the “pick this up tomorrow morning” case, or after the server reboots and tmux is gone.

Inside the TUI, /resume does the same thing without dropping to a shell.

Sandbox and approvals

Codex’s default posture is meaningfully different from most agents, and it happens to suit phones well. Rather than asking you to confirm each command, it confines the agent at the OS level: sandbox-exec with a Seatbelt profile on macOS, and Landlock (kernel 5.13+) layered over seccomp-bpf on Linux, where seccomp blocks outbound network syscalls and Landlock restricts writes outside the workspace (agent approvals & security docs).

Three presets, switchable mid-session with /permissions (called /approvals in older builds):

PresetSandboxWhat it means on a phone
Read Onlyread-onlyReads and explains; asks before any change. The right default for triage.
Autoworkspace-write + on-request approvalsEdits and runs commands inside the working directory; asks for anything outside it or needing network.
Full Accessdanger-full-accessNo sandbox, no prompts. Not from a phone.

Or from the command line:

codex --sandbox read-only
codex --sandbox workspace-write --ask-for-approval on-request

The mobile recommendation is read-only, and it isn’t timidity. The reason isn’t that a phone is a riskier device — it’s that your review quality is worse on it. You’re skimming a diff in a 40-column viewport, one-handed, probably walking. That’s precisely when you want the machine enforcing a boundary rather than your attention. Read-only mode is genuinely useful on its own: “why is nginx returning 502,” “what changed in this file last week,” “explain this stack trace” are all read operations, and they’re most of what you do from a phone anyway.

Then there’s --dangerously-bypass-approvals-and-sandbox. It exists for disposable containers and CI runners. OpenAI’s own guidance is to use full access only when the surrounding host is disposable and externally guarded. A production box you’re SSHed into from a train is neither.

One environment note: on distributions where Landlock is unavailable — some containers, older kernels — Codex falls back to Bubblewrap (bwrap) and warns at startup if it can’t find it at /usr/bin/bwrap. If you’re running inside Docker on a VPS and the sandbox warnings look alarming, that’s what they’re about.

This is the same principle behind TermAI’s own AI assistant: it drafts the command, you read it, you hit run. On a production server at 2am, “suggest and confirm” beats “act and apologise”. More on the distinction in AI agent terminal vs AI assistant and trusting AI shell suggestions.

One-shot runs with codex exec

The TUI is a full-screen app designed for a laptop. codex exec isn’t, which is exactly why it works on a phone:

codex exec "summarise the last 200 lines of /var/log/nginx/error.log and tell me what's failing"

It runs one session to completion, streams progress to stderr, writes the final message to stdout, and exits. No panes, no modal state, no arrow-key navigation on a touchscreen keyboard. Useful flags (non-interactive mode docs):

codex exec --json "..."              # JSONL event stream, pipe to jq
codex exec -o summary.md "..."       # write the final message to a file
codex exec --ephemeral "..."         # don't persist the session to disk
codex exec resume --last "and now?"  # follow up on the previous run

A pattern that works well when you’re mobile and impatient: run codex exec -o /tmp/out.md "..." inside tmux, detach, and read /tmp/out.md later over SFTP or less. You get the agent’s work without keeping a TUI attached over a flaky cellular link.

Pair it with a shell alias on the server so the phone side is short:

alias cx='cd ~/code/my-project && codex --sandbox read-only'
alias cxe='cd ~/code/my-project && codex exec --sandbox read-only'

Typing long commands on a phone keyboard is the real friction in all of this. Aliases fix more of it than any client feature.

Get notified instead of watching

Sitting on a cellular connection watching a TUI is a waste of battery and attention. Codex has two notification mechanisms, both configured in ~/.codex/config.toml:

# external hook — fires on agent-turn-complete, receives a JSON payload
notify = ["/bin/bash", "/home/you/.codex/hooks/notify.sh"]

# in-terminal alerts when the TUI isn't focused
[tui]
notifications = ["agent-turn-complete", "approval-requested"]
notification_method = "osc9"

The important asymmetry: the external notify hook fires on turn completion but not on approval-requested. So if you rely on it alone and the agent stops to ask permission, nothing pings you — the run just sits there while you assume it’s working. If you’re using approvals from a phone, either watch the session or set the sandbox so it doesn’t need to ask.

Point the hook script at whatever reaches your phone: a Telegram bot, an ntfy topic, a Pushover call. The payload is JSON containing the last assistant message, so a two-line curl is usually enough.

When it breaks

SymptomCauseFix
codex login hangs or the callback never landsBrowser flow needs localhost:1455 on the same machinecodex login --device-auth, or ssh -L 1455:localhost:1455 and complete it through the tunnel
Device auth rejectedDevice-code login disabled in ChatGPT security settings or by a workspace adminEnable it, or use the port-forward route
Session dies when you lock the phoneSSH sent SIGHUP; the agent wasn’t in tmuxtmux new -As codex; reattach with tmux attach -dt codex
Work lost mid-turn even though you can codex resumeresume replays the transcript, not an in-flight processAlways run inside tmux; resume is for continuity, not crash recovery
codex: command not found over SSHNon-interactive SSH doesn’t load your full PATH (common with nvm, Homebrew on Apple Silicon)Export the path in ~/.zshenv, not only ~/.zshrc
Sandbox warnings about bwrap on a VPSLandlock unavailable in that container/kernel; fallback missingInstall bubblewrap, or run on a host with kernel 5.13+
Agent refuses a network commandworkspace-write blocks outbound network by defaultApprove it when prompted, or run that one command yourself
Desktop terminal shrinks to phone widthtmux sizes to the smallest attached clientAttach with -d: tmux attach -dt codex
TUI renders as garbage boxesTERM mismatchexport TERM=xterm-256color; check the client’s terminal-type setting
Host key verification failed after a rebuildNew host key on the same namehost key verification failed — find out why it changed before deleting the entry

Also worth knowing: SSH re-handshakes on every network change, mosh doesn’t. Use mosh with tmux, not instead of it — mosh keeps the link alive, tmux keeps the session alive when the link dies anyway. See mosh vs SSH.

FAQ

Can Codex CLI run directly on an iPhone or Android phone? No. It needs a shell, a filesystem, and your repo checked out, so it runs on a Mac, a home server, or a VPS while the phone connects over SSH. Codex in the ChatGPT mobile app is a separate product that drives a cloud environment or a connected Mac host — not the CLI running on your phone.

Why does codex login fail on my server? The browser flow listens on port 1455 and expects a browser on the same machine. A headless VPS has none. Use codex login --device-auth, or tunnel with ssh -L 1455:localhost:1455 you@host and finish the flow in your local browser.

Does codex resume mean I don’t need tmux? No. resume replays a saved transcript from ~/.codex/sessions/; tmux keeps the process alive. If the connection drops mid-turn without tmux, you get the conversation back but not the finished work.

What’s the safest way to run Codex CLI from a phone? Start in --sandbox read-only. Triage, logs, and explanations are read operations, and read-only removes the temptation to approve a diff you can’t properly read on a 6-inch screen.

Can I run Codex without an interactive terminal at all? Yes — codex exec "prompt" runs once and exits. Add -o out.md to write the result to a file you read later, or --json for a parseable event stream.

Can Codex CLI and Claude Code share the same phone setup? Yes. One tmux window per agent. What differs is login (Codex needs device auth on a headless box) and permissions (Codex sandboxes by default; Claude Code prompts by default). Side-by-side in AI terminal tools compared.


Two commands are the whole difference between “Codex doesn’t work over SSH” and a working phone setup: codex login --device-auth and tmux new -As codex. Everything after that is the ordinary business of having a real terminal in your pocket — which, when the server is down and you’re nowhere near a laptop, turns out to be the part that matters.

Try TermAI

Free on iOS and Android. 5 AI requests/day on the free tier, plus unlimited SSH/SFTP and built-in Tailscale.

CC
Chen Chen — Founder of TermAI

Writes about mobile DevOps, terminal UX, and the surprising depth of "boring" infrastructure.