The problem
If you run Claude Code in a browser-based terminal (like Cockpit), your session lives inside a WebSocket connection. When that connection drops — browser tab closed, laptop lid shut, phone screen locked, network hiccup — everything dies. Claude stops mid-task. Your context is gone. You start over.
Cockpit compounds this with a 15-minute idle session timeout. If Claude is thinking quietly — running tools, processing files — and you're not clicking around in the Cockpit UI, your session gets terminated automatically, taking Claude with it.
The solution
tmux is a terminal multiplexer that runs on the server, not in your browser. Your Claude session runs inside tmux. The browser terminal just shows you a view of it — like a window into a room that exists independently of whether you're looking.
Without tmux
Claude process is a child of the browser terminal. Close the tab → kill the process. One device, one session, no recovery.
With tmux
Claude runs inside a server-side tmux session. Close the tab, switch devices, lose network — tmux keeps running. Reconnect and attach.
Setup
tmux runs on the server — the always-on machine where Claude Code lives. Your laptop, phone, or tablet is just the client connecting to it. Everything in this Setup section is configured on the server. See Installing tmux if you don't have it yet, and Connecting from different devices for the client side.
Configure tmux
Create ~/.tmux.conf on your server. This sets up mouse support, better scrollback, a readable status bar, and a built-in help popup at Ctrl+B H.
Full config available in the GitHub repository.
Auto-attach on terminal open
Add this to ~/.bashrc (or ~/.zshrc on macOS, where zsh is the default). It attaches to (or creates) a tmux session named main whenever you open a new terminal on the server. Use whichever condition matches how you connect:
Pick one — or keep both, since the conditions don't overlap. The -z "$TMUX" guard prevents nested tmux sessions when you re-attach.
Fix the Cockpit idle timeout (Cockpit only)
Skip this step if you connect over SSH. By default, Cockpit terminates idle web sessions after 15 minutes — exactly long enough to time out while Claude is working quietly. Disable it:
Then restart Cockpit: sudo systemctl restart cockpit.service
Installing tmux on the server
Check whether it's already there with tmux -V. You want 3.2 or newer for the display-popup help binding; older versions still work if you remove that one block from .tmux.conf.
| Server OS | Install command |
|---|---|
| Debian / Ubuntu / Raspberry Pi OS | sudo apt update && sudo apt install tmux |
| Fedora / RHEL 8+ / Rocky / AlmaLinux | sudo dnf install tmux |
| CentOS 7 / older RHEL | sudo yum install tmux |
| Arch / Manjaro | sudo pacman -S tmux |
| openSUSE | sudo zypper install tmux |
| Alpine | apk add tmux as root (Alpine has no sudo by default — use doas if configured) |
| macOS (as the server) | brew install tmux (needs Homebrew) |
| FreeBSD | sudo pkg install tmux |
| Windows (WSL2 Ubuntu/Debian) | sudo apt install tmux inside the WSL shell |
Native Windows has no tmux. tmux is POSIX-only. On a Windows server, run Claude Code and tmux inside WSL2, or use a separate Linux/macOS box as your always-on host. PowerShell and CMD can be SSH clients, but they can't host the tmux session.
macOS as a server: works fine, but enable Remote Login in System Settings → General → Sharing so you can SSH in, and disable App Nap on Terminal so the box doesn't throttle background work. A Mac mini or always-plugged-in laptop with "prevent sleep when display is off" is a reasonable host.
Connecting from different devices
Once tmux is set up on the server, anything that can open a shell on it — SSH, mosh, or Cockpit's web terminal — works as a client. The auto-attach snippet drops you straight into the running session, so the client doesn't need to know anything about tmux.
macOS
Built-in Terminal.app or iTerm2 + ssh user@server. OpenSSH ships with macOS — no install needed.
Tip: set up ~/.ssh/config with a Host alias so you can run ssh box from any folder.
Windows
Windows Terminal with the built-in OpenSSH client (ssh user@server) is the modern path. PuTTY works too. WSL gives you a Linux shell that can both SSH out and host tmux.
Linux desktop
Any terminal emulator + ssh. Same pattern as macOS. GNOME Terminal, Konsole, Alacritty, Kitty, Wezterm — all fine.
iOS / iPadOS
Blink Shell (paid, polished, mosh support) and Termius (free tier) are the two solid choices. Both handle the on-screen Ctrl key needed for tmux's Ctrl+B prefix.
Android
Termux (free, install from F-Droid — the Play Store version is unmaintained) gives you a real shell with pkg install openssh. Termius is the easiest GUI option.
ChromeOS
Enable the Linux container (Settings → Developers → Linux development environment), then sudo apt install openssh-client and use ssh like any Linux desktop. The Secure Shell extension also works without enabling Linux.
Browser (Cockpit)
Open https://yourserver:9090 and use the Terminal app. Works from any device with a browser, including phones, but apply the Cockpit timeout fix above.
Flaky networks (any device)
Install mosh on both the server and the client (apt/dnf/brew install mosh; Blink Shell has it built in), then use mosh user@server instead of ssh. Mosh survives network changes and sleep — a good companion to tmux on cellular or while moving between Wi-Fi networks.
Mosh also needs UDP ports 60000–61000 open inbound to the server — open them in your firewall (and any cloud security group) or you'll see "mosh: connect failed".
Phone keyboards and the Ctrl key: tmux's prefix is Ctrl+B, which most mobile SSH apps expose via a software toolbar above the keyboard. If you'd rather use a different prefix, add set -g prefix C-a (and unbind C-b / bind C-a send-prefix) to ~/.tmux.conf — Ctrl+A is a common alternative that's easier on some layouts.
Key bindings
All tmux commands start with the prefix Ctrl+B — press and release it, then press the next key. Ctrl+B H shows this as a popup in your terminal.
| Ctrl+B then C | New window |
| Ctrl+B then , | Rename current window |
| Ctrl+B then W | List all windows (interactive) |
| Ctrl+B then 1–9 | Switch to window by number |
| Ctrl+B then N / P | Next / previous window |
| Ctrl+B then % | Split left/right |
| Ctrl+B then " | Split top/bottom |
| Ctrl+B then ↑↓←→ | Move between panes |
| Ctrl+B then Z | Zoom pane to full screen (toggle) |
| Ctrl+B then [ | Enter scroll mode (use arrows/PgUp, Q to exit) |
| Ctrl+B then D | Detach — session keeps running |
| Ctrl+B then H | Help popup (from this config) |
| Ctrl+B then ? | Full built-in keybinding list |
Suggested window layout
Name your windows so the status bar tells you what's running at a glance. Use Ctrl+B , to rename.
1: claude
Your active Claude Code session. This is where you work.
2: logs
journalctl -f or tail -f on scheduler or app logs.
3: shell
Free shell for quick commands, file checks, or running builds.
Coexisting with scheduled Claude sessions
If you run automated Claude sessions (cron-based check-ins, email processing, transcript analysis), they can conflict with your interactive session — competing for CPU and trying to process the same data at the same time.
Add this function to your scheduler to detect an active interactive session and skip the automated wake:
The pane_current_command tmux format string returns the name of the running process — no need to parse ps aux.
Getting notified when a session needs input
tmux can highlight a tab when the process in it goes quiet — a reliable signal that something has finished and is waiting for you. This uses monitor-silence, which fires after a window has produced no output for a set number of seconds.
Add these lines to your ~/.tmux.conf:
The monitor-silence 20 value is seconds. Bump it up if it fires too often during normal processing pauses.
Why silence, not activity? monitor-activity fires on every byte of output — too noisy for Claude sessions that stream continuously. monitor-silence fires only when output stops, which is a much better proxy for "waiting for you." While a session is running it outputs constantly; when it hits a prompt or finishes, it goes quiet.
Common pitfalls
The first session after setup won't be in tmux
The .bashrc change only applies to new terminal sessions opened after saving the file. Close your current terminal tab and open a fresh one to get tmux.
display-popup requires tmux 3.2+
Check your version with tmux -V. If you're on an older version, remove the bind H display-popup ... block from .tmux.conf and use Ctrl+B ? for help instead.
Name your windows
Use Ctrl+B , to name each window. The status bar shows all window names at once — without names, you'll end up with a row of identical bash entries.
tmux survives, but the server has to stay on
Sessions persist across browser disconnects, not server reboots. A Pi or always-on server works perfectly for this; a laptop that gets shut down does not.
Related skills
Claude that keeps working after you close the tab
A few config changes. Runs on any headless Linux, macOS, or BSD server with tmux. Connect from a Mac, Windows, Linux, ChromeOS, iOS, or Android client.
View on GitHub