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:
- Log in with device auth, not the browser flow.
codex loginstarts a local listener on port1455and waits for a browser on the same machine to hit the callback, which a headless server does not have.codex login --device-authprints a short code you approve from any browser instead. - Start it inside
tmux, so locking your phone or hopping from Wi-Fi to LTE doesn’tSIGHUPthe run. - 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 app | SSH + tmux to your box | codex exec one-shot | |
|---|---|---|---|
| Where the code lives | Cloud container, or a connected Mac host | Your machine | Your machine |
| Start work from the phone | Yes | Yes | Yes |
| Full-screen TUI on a 6-inch screen | No — native app UI | Yes | No — plain output |
Read logs, systemctl, git log in the same session | No | Yes | Not interactively |
| Works against a headless VPS | Cloud only | Yes | Yes |
| Needs a desktop app running | For the local-host mode | No | No |
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
tmuxinstalled. - 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.
resumefor 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):
| Preset | Sandbox | What it means on a phone |
|---|---|---|
| Read Only | read-only | Reads and explains; asks before any change. The right default for triage. |
| Auto | workspace-write + on-request approvals | Edits and runs commands inside the working directory; asks for anything outside it or needing network. |
| Full Access | danger-full-access | No 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
| Symptom | Cause | Fix |
|---|---|---|
codex login hangs or the callback never lands | Browser flow needs localhost:1455 on the same machine | codex login --device-auth, or ssh -L 1455:localhost:1455 and complete it through the tunnel |
| Device auth rejected | Device-code login disabled in ChatGPT security settings or by a workspace admin | Enable it, or use the port-forward route |
| Session dies when you lock the phone | SSH sent SIGHUP; the agent wasn’t in tmux | tmux new -As codex; reattach with tmux attach -dt codex |
Work lost mid-turn even though you can codex resume | resume replays the transcript, not an in-flight process | Always run inside tmux; resume is for continuity, not crash recovery |
codex: command not found over SSH | Non-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 VPS | Landlock unavailable in that container/kernel; fallback missing | Install bubblewrap, or run on a host with kernel 5.13+ |
| Agent refuses a network command | workspace-write blocks outbound network by default | Approve it when prompted, or run that one command yourself |
| Desktop terminal shrinks to phone width | tmux sizes to the smallest attached client | Attach with -d: tmux attach -dt codex |
| TUI renders as garbage boxes | TERM mismatch | export TERM=xterm-256color; check the client’s terminal-type setting |
Host key verification failed after a rebuild | New host key on the same name | host 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.
Free on iOS and Android. 5 AI requests/day on the free tier, plus unlimited SSH/SFTP and built-in Tailscale.