iTranslated by AI
How to Control Claude Code from Your iPhone: A Setup Guide with Termius, Tailscale, and tmux
What I Found After Discarding the GUI
In my previous article, I wrote about switching from Cursor to Zed. It was a story about making my editor lighter to resolve the discomfort of having "heavy containers for light content."
This time, I'm taking another step forward: a story about letting go of the editor itself and creating an environment to run Claude Code from the black screen of an iPhone.
The motivation was simple: I want to be able to give instructions to Claude Code even when I'm on the go. That's all.
Premise: I'm a developer who only reads code
It's the same premise as my previous article, but let's recap.
My development flow consists of only three steps:
- Read code (review)
- Give instructions to Claude Code
- Verify the generated code
The only thing I ask of an editor is to "display code quickly." I don't use code completion or snippets.
Following this premise to its logical conclusion leads to a question:
Can't I even "read" code on my iPhone screen?
The first mistake: Chrome Remote Desktop
My first thought was to remotely control my Mac screen from my iPhone. Chrome Remote Desktop seemed like a free and viable option.
I searched the App Store. Nothing came up.
According to Gemini, Google ended their native iOS app and shifted to a Web App (PWA). It seems I could use it by accessing remotedesktop.google.com from Safari.
It worked, technically, but then I stopped and thought: Do I really need to transmit the entire video feed of my screen just to control Claude Code?
Sending a black terminal screen as "video" is a waste of bandwidth. The text gets blurry, and input latency is a concern. Plus, if I display a Mac desktop on a tiny iPhone screen, the text becomes microscopic.
Gemini's suggestion was as follows:
"Remote Desktop," which transmits the screen as video, is not the optimal method for CLI operations. An SSH connection, which sends only text data, uses less than 1/100th of the bandwidth and keeps the text crisp.
I see. I just need to send text, not video.
The blueprint drawn by Gemini
Gemini proposed the following architecture:
Mac (at home, always on)
├─ Tailscale (VPN)
├─ SSH (remote login)
├─ tmux (session persistence)
└─ Claude Code
iPhone (on the go)
├─ Tailscale (VPN)
└─ Termius (SSH client)
Tailscale is a zero-config VPN. It connects the iPhone and Mac directly via a virtual LAN cable. No port forwarding required, and it's free.
Termius is an iOS-compatible SSH client. It connects to the Mac terminal from the iPhone.
tmux is a session persistence tool. Even if the signal drops, the processes on the Mac stay alive, and the screen is restored exactly as it was upon reconnection.
The cost is $0 per month. No VPS needed. I just use my home Mac as is.
The blueprint was beautiful. The problem was the implementation that followed.
In reality, it took me a week to reach this specific configuration.
February 7: First attempt and retreat
I first tried Termius on February 7.
I connected the VPN with Tailscale and performed an SSH connection to my Mac from Termius. Things were smooth until then. When I launched Claude Code, it said, "Please authenticate in your browser."
But the browser wouldn't open. Obviously—since it's an SSH connection, the browser would open on the remote Mac. Nothing appeared on my iPhone.
Since it displayed c to copy on the screen, I pressed the c key. It displayed "Copied." I switched to Safari on my iPhone and tried to paste. Nothing.
I asked Gemini:
c to copycopies to the clipboard of the remote Mac, not the iPhone's clipboard.
It taught me the pbpaste command to output the Mac's clipboard content to the terminal, but that meant I had to manually select the URL by long-pressing, which added unnecessary steps.
"This is too complicated," I thought.
I retreated for the day. Gemini's conclusion was clear:
Log in by running
claudeonce while you're in front of your Mac. After that, you can use it in an authenticated state from Termius.
However, that doesn't solve the scenario of "using it for the first time while away."
February 12-13: Second attempt
Five days later, I tried again. This time, I had Gemini draw the blueprint from scratch and decided to proceed systematically.
7 stumbling blocks
1. Node.js is missing
Claude Code works in the Cursor extension, but it doesn't work when I type claude in the terminal. Why?
According to Gemini, the answer was simple:
Cursor has its own internal Node.js environment. Node.js is not installed in your system terminal.
When I tried to run npm install -g @anthropic-ai/claude-code, it said zsh: command not found: npm. I didn't even have npm.
brew install node
npm install -g @anthropic-ai/claude-code
With this, the claude command became available. The dependencies hidden inside Cursor were exposed in the terminal.
2. Browser won't open for OAuth authentication
When I launched Claude Code and tried to log in, it said, "Please authenticate in your browser." Usually, a browser opens to show the authentication page.
But this is a remote connection via Termius. The browser opens on the remote Mac side. Nothing appears on the iPhone.
I had to manually copy the URL displayed in the terminal and open it in Safari on my iPhone.
3. URL is too small to copy
This was where the problem started. The OAuth URL is a long string of over 100 characters. The iPhone Termius screen is small, and it was difficult to select accurately with my fingers.
I had Gemini read the URL from a screenshot. I tapped the link to open it in Safari and logged in.
It returned an error: "Invalid Auth Request."
Maybe the OCR by Gemini was off by a character, or the URL expired. Since OAuth URLs contain encrypted data, a single wrong character causes an error. Eventually, I reissued it with /login and solved it by using Termius's long-press copy function.
The fundamental solution to authentication issues: Troubles with OAuth authentication can be completely avoided using the "tmux method" described later. Log in once on the Mac side and create a tmux session. You won't have to touch the authentication flow on the iPhone side at all.
4. Tailscale is green, but no connection
When I opened the Tailscale app, both my iPhone and Mac were green and "Connected." The VPN tunnel was open.
Yet, when I tried connecting from Termius, it said "Connection timed out."
It wasn't that "the iPhone couldn't find the Mac on the network," but rather "I reached the front door, but it was locked."
The culprit was the Mac firewall. SSH (TCP 22) was blocked.
In System Settings > Network > Firewall > Options, I enabled "Remote Login (SSH)."
5. Mac goes to sleep while away
I left before fixing the firewall settings. Even though I left the MacBook lid open, it went to sleep after a while.
The final resort suggested by Gemini:
Send "Play Sound" to the Mac from the "Find My" app; this will force it to wake up from sleep. Connect via SSH during that window.
In the end, I gave up and went home that day. These are the lessons I learned:
-
System Settings > Displays > Advanced > Prevent automatic sleeping on power adapter when the display is off→ ON - Before leaving: Keep the Mac lid open, connect the power cable, and lock it with
Ctrl + Cmd + Q. - SSH/Tailscale works perfectly even on the lock screen.
Note: Regarding the "API Usage Billing" display
I panicked when I saw "API Usage Billing" on the Claude Code startup screen. However, this is default text displayed even on the Max plan. The actual usage was within the Max plan limit; checking with the/costcommand showed $0.
6. Re-login required every time SSH connects
I succeeded in connecting. But a new problem emerged: every time I launched Claude Code via SSH, I was asked for OAuth login.
Gemini told me this was a macOS Keychain issue.
Claude Code's OAuth tokens are stored in the macOS Keychain. Keychain is automatically unlocked when logged in locally, but SSH connections do not pass through a GUI login session, so Keychain remains locked.
As a countermeasure, I added a wrapper function for Keychain unlocking to .zshrc.
claude() {
if [ -n "$SSH_CONNECTION" ] && [ -z "$KEYCHAIN_UNLOCKED" ]; then
security unlock-keychain ~/Library/Keychains/login.keychain-db
export KEYCHAIN_UNLOCKED=true
fi
command claude "$@"
}
A password input screen appeared. But the cursor wouldn't move. No text appeared.
This is a security specification; nothing is displayed on the screen while entering the password. You just type it and hit Enter.
It returned, The user name or passphrase you entered is not correct.
Whether it was an unintended character typed from the Termius keyboard or not, it wouldn't pass no matter how many times I tried.
7. tmux solved everything
Gemini's suggestion was a shift in perspective.
If you launch Claude Code within a tmux session while logged in locally on the Mac side once, you only need to attach to that session from the iPhone. Re-authentication is not required.
In other words, skip unlocking the Keychain itself.
# Execute once locally on the Mac side
tmux new -s cc
claude
# iPhone side (as many times as you want)
tmux attach -t cc
Claude Code is already running locally. The iPhone is just peeking into that "window." Keychain doesn't matter.
"So, can't I launch a new session? Sometimes I want to reset the context."
Exit with
/exitwithin tmux and restart withclaude; a new session with a new context will begin. Since tmux is just a container, you can swap the contents freely.
I see. tmux is a terminal box that keeps running on the Mac. The iPhone is just controlling what's inside that box. I can do exactly the same thing as touching it directly locally.
"Can't you launch Cursor?"
After the connection was successful, I asked Gemini on a whim:
"Can't I launch Cursor?"
It replied:
Termius can only handle characters (CLI). Cursor is a GUI (video). Even if you type
cursor .via SSH, it only opens Cursor on your home Mac's screen; nothing appears on your iPhone.
I see. So, how do I read code without Cursor?
Claude Code itself acts as a file viewer. If you say "show me the content of main.swift," it will display it, and you can verify diffs as well.
"Well, I guess I'm doing the same thing."
After replying that, I thought a bit more and said:
"After all, both are just looking at text." This is the core of this matter.
I open a file in Cursor and read the code. I ask Claude Code to "show me this file." What I'm looking at is the same text. The difference between giving instructions in the terminal next to Cursor and giving them in the SSH terminal is negligible.
GUI is nothing more than "decoration (skin)." Text is the substance.
On the small screen of an iPhone, a CLI that is just text has higher information density than a GUI that occupies the screen with buttons and windows.
The completed environment
Here is the final configuration and operational rules.
Configuration
| Layer | Tool | Role |
|---|---|---|
| VPN | Tailscale (Free) | Encrypted connection between iPhone and Mac |
| SSH Client | Termius (Free) | Connect to Mac from iPhone |
| Session Management | tmux | Maintain processes even if disconnected |
| Development Tool | Claude Code | Code generation, review, and execution |
Routine before leaving home
- Connect the power cable to the Mac
- Lock the screen with
Ctrl + Cmd + Q - Leave the house with the lid open
iPhone connection procedure
# Tap "My mac" in Termius → Automatic tmux attach (Startup Snippet)
# If a session exists, it restores. If not, it creates a new one.
# New Claude Code session
/exit # Terminate current session
claude # New launch (no re-authentication needed)
Termius setup tips
-
Startup Snippet: Set
tmux attach -t cc || tmux new -s cc. Enter tmux immediately upon connection. - Live Activities: Recommended to turn OFF. With tmux, notifications for connection maintenance are unnecessary. Saves battery.
- Mosh: OFF initially. Switch to ON if unsatisfied with SSH + tmux.
Cost
| Item | Monthly |
|---|---|
| Tailscale | $0 |
| Termius | $0 |
| VPS | Unnecessary ($0) |
| Claude Code | Max Plan (Existing) |
| Total | $0 (excluding Claude Max Plan) |
SSH vs Mosh — SSH is still enough
I asked Gemini, "Should I switch to Mosh?"
Mosh is a connection-maintenance protocol that automatically recovers when signal is lost and resolves input lag with local echo. Theoretically, it's a superior substitute.
However, it uses UDP ports (60000-61000), so it requires additional firewall settings. Having suffered enough with firewalls during setup, I don't want to break an environment that is currently working.
Gemini's advice was spot on:
Try operating with SSH + tmux for a few days first. It's smartest to move to Mosh only when you feel "Reconnecting is a pain!" or "The input latency is bothering me!"
Upgrade after being dissatisfied. That was the right decision.
Honest opinion: iPhone is a "Remote Controller"
I'll write honestly after operating it for a few days.
Terminal operation on an iPhone is quite a challenging experience.
Because the screen width is narrow, you can't see the big picture of the code. Typing long prompts via flick input is also tough.
Scrolling also takes some effort. Swipe on the iPhone doesn't work inside tmux; you have to enter copy mode with Ctrl+b → [ and then operate with arrow keys. If you enable mouse mode, you can scroll with touch, but the fundamental narrowness of the screen doesn't change.
# Enable touch scrolling
echo "set -g mouse on" >> ~/.tmux.conf
tmux source-file ~/.tmux.conf
However, it was practical enough if you keep the purpose simple:
- Checking progress of Claude Code
- Pressing y to continue at approval prompts
- Sending short additional instructions
Serious reviews should be done after returning to the Mac. The iPhone is just a "remote controller."
The "GUI-less" trilogy
Looking back, these three articles are connected by a single thread: "escaping from the GUI."
| Article | What I let go of | What remains |
|---|---|---|
| ECC Journey | Coding itself | Instructions to Claude Code |
| Cursor → Zed | Heavy editor | Lightweight editor + Terminal |
| Termius + Claude Code (This article) | Editor GUI | Terminal only |
At first, it was about "no need to write code in the AI era." Then, "no need for a heavy editor." And this time, "no need for a GUI."
What remains is the black background and white text on the iPhone screen. And the dialogue with Claude Code.
After all, both are just looking at text.
If so, the environment that can transmit and receive text most efficiently is the optimal solution. That was SSH.
Bonus: Getting help from Gemini
I proceeded with this environment setup while consulting Gemini the entire time.
Consulting Gemini to set up Claude Code—it's a meta composition, but in reality, this was the most efficient way. Claude Code isn't running yet, so troubleshooting until launch has to be done by another AI.
When I had it read the OAuth URL from a screenshot and it was off by one character, or when it taught me the trick to wake up the Mac using the "Find My" app... it was also Gemini that explained the essential difference between GUI and CLI in a single sentence.
GUI is video (video call), CLI is text (phone call). The reason CLI is optimal for the iPhone + SSH environment is that video is unnecessary for transmitting text.
AI helping build the AI environment. This is the state of development in 2026.
Summary
- To operate Claude Code on a Mac from an iPhone, the trio of Tailscale + Termius + tmux is sufficient.
- No VPS required. Just use your home Mac for $0 monthly.
- The essence of GUI and CLI is the same: "passing text to AI to have it rewritten."
- If you forget the firewall and sleep settings, you're stuck. Check before leaving.
- Start with SSH first, and upgrade to Mosh if you have complaints.
Open the black screen of the iPhone on the go and give instructions to Claude Code. Projects move forward while on the train.
What I found after throwing away all the GUI decorations was the lightest and fastest development environment possible.
Discussion