Not a member of Pastebin yet?
Sign Up,
it unlocks many cool features!
- # Remote Claude Code Access via Tmux + Tailscale + Termius
- ## Overview
- Access running Claude Code sessions from iPhone (Termius) by combining:
- - **Tailscale** — Mesh VPN connecting Mac and iPhone over private network
- - **tmux** — Terminal multiplexer keeping sessions alive across disconnects
- - **Termius** — iOS SSH client with mobile-friendly keyboard
- ## Architecture
- ```
- Mac (Claude Code) iPhone (Termius)
- ┌─────────────────────┐ ┌──────────────┐
- │ tmux session │ │ Termius app │
- │ ┌───────────────┐ │ SSH over │ │
- │ │ Claude Code │──┼──Tailscale──▶│ tmux attach │
- │ │ (running) │ │ │ │
- │ └───────────────┘ │ └──────────────┘
- └─────────────────────┘
- ```
- ## Components
- ### 1. Tailscale (Mesh VPN)
- - Installed via `brew install --cask tailscale`
- - Creates private network between devices
- - No port forwarding or firewall configuration needed
- - Sign-in with Apple ID (most privacy-friendly option)
- **Aliases in `.zshrc`:**
- ```bash
- alias ts_status='tailscale status'
- alias ts_ip='tailscale ip -4'
- alias ts_up='tailscale up'
- alias ts_down='tailscale down'
- alias ts_devices='tailscale status | grep -v "^$"'
- ```
- ### 2. macOS Remote Login (SSH)
- - Enabled via `sudo systemsetup -setremotelogin on`
- - Required for SSH access from Termius
- ### 3. tmux Configuration
- File: `~/.tmux.conf` (outside repo — not managed by master-template)
- Key settings:
- - **Mouse support** — Essential for phone/tablet interaction
- - **OSC 52 clipboard** — Enables clipboard sync over SSH
- - **vi copy mode** — Mouse drag auto-copies to system clipboard via `pbcopy`
- - **50k scrollback** — Large history buffer
- - **escape-time 10** — Reduce latency over SSH
- - **destroy-unattached off** — Keep sessions alive when client disconnects
- ### 4. tmux Auto-Wrapping in `_claude()` and `cr()`
- Every Claude Code session is automatically wrapped in a tmux session:
- ```bash
- # Creates unique session name per project directory
- local base_name=$(basename "$PWD" | tr '.' '-')
- # Auto-increment if session name exists: marstek, marstek-2, marstek-3
- while tmux has-session -t "$session_name" 2>/dev/null; do
- session_name="${base_name}-${n}"
- n=$((n + 1))
- done
- # Session self-destructs when Claude exits
- tmux send-keys -t "$session_name" "$claude_cmd; tmux kill-session -t $session_name" Enter
- ```
- **Key design decisions:**
- - Sessions auto-kill when Claude exits (prevents stale sessions)
- - Unique session names allow multiple Claude instances per project
- - If already inside tmux (e.g., from phone SSH), runs directly without nesting
- - Zero visible difference on Mac — tmux wrapping is transparent
- ### 5. Unified Session Picker (`_tmux_pick`)
- Mobile-friendly numbered menu combining running sessions and project launcher:
- ```
- 1) protest-upgrade ← Running tmux sessions
- 2) marstek-2
- 3) protest-upgrade ← Available projects
- 4) swiss-sense
- 5) cameraland
- ...
- 0) sleep
- # _ ← Number input
- ```
- After selecting a project, accepts full alias syntax:
- ```
- co cs ch cr (+ 1/2/3 -d -c)
- > co3 -d -c ← Opus, think high, dangerous, chrome
- ```
- **Aliases:** `ta` and `cc` both map to `_tmux_pick`
- **Stale session cleanup:** Before showing menu, kills unattached tmux sessions where the foreground process is NOT `claude` (meaning Claude exited and left a shell).
- ### 6. SSH Auto-Attach with Menu Loop
- When SSHing in from Termius:
- 1. Prompts for keychain unlock (Claude Code stores API creds in macOS keychain)
- 2. Shows `_tmux_pick` menu in a loop
- 3. After a tmux session ends, returns to menu
- 4. Empty input breaks the loop → drops to regular shell
- ```bash
- if [[ -n "$SSH_CONNECTION" ]] && [[ -z "$TMUX" ]]; then
- echo "Unlock keychain for Claude Code:"
- security unlock-keychain ~/Library/Keychains/login.keychain-db
- while _tmux_pick; do
- echo ""
- done
- fi
- ```
- ### 7. `/sleep` Command
- Puts Mac to sleep remotely from phone. Runs `pmset sleepnow`.
- - Available in all projects (symlinked to all commands directories)
- - Also accessible as option `0)` in `_tmux_pick` menu
- - Permission added to all 9 `settings.local.json` files
- ## Termius Setup (iPhone)
- 1. Install Termius from App Store
- 2. Add new host:
- - **Address:** Tailscale IP of Mac
- - **Username:** Mac username
- - **Auth:** SSH key or password
- 3. Connect → keychain prompt → session menu
- ## Solved Problems
- ### macOS Keychain Lock on SSH
- Claude Code stores OAuth credentials in macOS keychain, which is locked for SSH sessions. Solution: `security unlock-keychain` prompt on SSH login — user enters Mac password once per session.
- ### Session Name Collisions
- Multiple Claude sessions for same project would collide on `basename $PWD`. Solved with auto-incrementing suffix: `marstek`, `marstek-2`, `marstek-3`.
- ### Stale Session Accumulation
- Sessions created before auto-kill code persisted indefinitely. Solved with:
- 1. Auto-kill on Claude exit: `$claude_cmd; tmux kill-session -t $session_name`
- 2. Stale detection in `_tmux_pick`: kills unattached sessions not running `claude`
- ### Menu Loop for Mobile
- On phone, exiting a Claude session would drop to a bare shell. Solved by wrapping `_tmux_pick` in a `while` loop (SSH only). After each session ends, the menu reappears. Enter with no input to get a shell.
- ## Sources
- - Reddit discussion: r/ClaudeCode — "Tmux + Tailscale + Termius"
- - rogs.me guide on remote Claude Code access
- - anurajrp.io guide on Tailscale + tmux setup
- ## Files Modified
- | File | Changes |
- |------|---------|
- | `~/.tmux.conf` | Created (not in repo) |
- | `.zshrc` | `_claude()`, `cr()`, `_tmux_pick()`, SSH auto-attach, Tailscale aliases |
- | `projects/_overall/.claude/commands/sleep.md` | New `/sleep` command |
- | All 9 `settings.local.json` | Added `pmset sleepnow` permission |
Advertisement
Add Comment
Please, Sign In to add comment