Claude Code Stops When I Disconnect from SSH — How to Fix It

Claude Code exits on SSH disconnect because the OS sends SIGHUP to all foreground processes. tmux is the permanent fix — here's how to set it up and recover a crashed session.

When an SSH connection drops, the SSH server sends SIGHUP to all processes in the session's process group. Claude Code receives SIGHUP and exits — it has no built-in handler for it. The fix is tmux: always start Claude Code inside a tmux session on the remote server so disconnects are irrelevant. If you want to monitor the session from your phone without staying SSHed in, Grass handles that.

TL;DR

  • SSH disconnect sends SIGHUP to foreground processes; Claude Code exits immediately
  • Permanent fix: always use tmux new -s session-name before starting Claude Code
  • Detach: Ctrl+B D — reconnect: ssh back in, tmux attach -t session-name
  • Session history is preserved in ~/.claude/projects/<cwd>/ even when the process dies
  • Resume with claude --continue
  • Optional: install Grass for phone monitoring without staying SSHed in

Why Claude Code stops when you disconnect from SSH

When an SSH connection ends — whether due to a network interruption, idle timeout, or manual disconnect — the SSH server sends SIGHUP (hangup signal) to all processes in the session. SIGHUP is the OS's way of telling foreground processes that their controlling terminal is gone.

Claude Code runs as a foreground interactive process with no SIGHUP handler. It exits immediately. The remote coding session history is preserved in ~/.claude/projects/<cwd>/<session-id>.jsonl, but the running process is gone — any task in progress stops at that point.

The permanent fix: tmux

tmux creates terminal sessions that live on the server, detached from any SSH connection. Processes inside tmux receive no SIGHUP when SSH disconnects — they keep running regardless.

Step 1: Install tmux on the server

sudo apt install tmux -y  # Ubuntu/Debian

Step 2: Always start Claude Code inside tmux

ssh user@your-server
tmux new -s claude-session
cd ~/project
claude

Step 3: Detach before disconnecting

# Ctrl+B D (hold Ctrl, press B, release both, press D)

Your terminal returns to the shell. Close the SSH connection — Claude Code keeps running inside tmux on the server.

Step 4: Reconnect any time

ssh user@your-server
tmux attach -t claude-session

You're back inside the running session. If Claude Code exited while you were away, resume it:

claude --continue

claude --continue restores the full conversation from the transcript file. Use claude --resume <session-id> to resume a specific past session by ID. See the Claude Code CLI reference for all session management flags.

If Claude Code already crashed (you forgot to use tmux)

Check the session transcripts:

ls ~/.claude/projects/

Navigate to your project directory and resume:

cd ~/project
claude --continue

Claude Code reads the .jsonl transcript file and restores the conversation. It won't know exactly where the task stopped, but the full conversation history up to the crash is available. Re-describe what you need it to do next.

If Claude Code is still running but SSH dropped (advanced recovery)

In rare cases, the process may still be running — for example, if SIGHUP was delayed or ignored. Use reptyr to re-parent it into a new tmux session:

# Find the PID
ps aux | grep claude

# Start a new tmux session
tmux new -s rescue

# Inside tmux, re-parent the process
reptyr <PID>

Note: reptyr requires ptrace permissions. Check /proc/sys/kernel/yama/ptrace_scope — it must be 0 or 1. On many hardened systems it's set to 2, which blocks reptyr. This is an edge case; the standard fix (tmux from the start) avoids the need for it entirely.

Preventing SSH timeouts

Idle SSH connections time out when there's no traffic. Add keepalives to your SSH client config to prevent this:

# ~/.ssh/config
Host *
  ServerAliveInterval 60
  ServerAliveCountMax 3

This sends a keepalive packet every 60 seconds and disconnects after 3 missed responses (~3 minutes without a reply). Prevents idle-timeout disconnects that would otherwise kill a Claude Code session you forgot to put in tmux.

This only addresses idle timeouts — not network interruptions. tmux remains the right fix for surviving actual disconnects.

Running multiple Claude Code sessions on the server

Each project gets its own tmux session:

tmux new -s project-a
tmux new -s project-b
tmux ls  # see all running sessions
tmux attach -t project-a

See the Claude Code running tasks documentation for guidance on parallel sessions and context management.

Going further: monitoring without SSH at all

tmux means reconnecting takes seconds — SSH back in, tmux attach. But you still need SSH to check on the session.

If you want to monitor Claude Code output, handle agent approval gates, and send instructions from your phone without an SSH client or terminal:

npm install -g @grass-ai/ide

On the server, in a second tmux window:

grass start --network tailscale
# or: grass start --network remote-ip

A QR code appears. Scan it from the Grass iOS or Android app. Your phone becomes the interface to the running session — live output, approval modals, file browser, prompt input. No SSH required.

For mobile coding agent access to a server, this eliminates the need for SSH entirely once the initial setup is done.

Frequently asked questions

Why does Claude Code stop when I disconnect from SSH?

SSH disconnect sends SIGHUP to all foreground processes in the session. Claude Code has no SIGHUP handler — it exits immediately. Session history is preserved in ~/.claude/projects/ but the process is gone.

How do I prevent Claude Code from stopping on SSH disconnect?

Always start Claude Code inside a tmux session. Run tmux new -s name before claude, then detach with Ctrl+B D. tmux sessions run on the server independently of SSH connections.

How do I reconnect to Claude Code after an SSH timeout?

SSH back into the server, then tmux attach -t session-name. If Claude Code exited: claude --continue to resume from the last transcript.

How do I recover a Claude Code session that was interrupted?

Run claude --continue in the project directory. Claude Code reads the .jsonl transcript from ~/.claude/projects/<cwd>/ and restores the conversation history up to the point of interruption.

Does Claude Code save progress when it crashes?

Yes. Claude Code writes conversation history to .jsonl transcript files continuously — not just at session end. When a session crashes, the transcript up to the crash is preserved and can be resumed with claude --continue.

How do I prevent SSH timeout when running Claude Code?

Add ServerAliveInterval 60 and ServerAliveCountMax 3 to ~/.ssh/config. This sends keepalive packets every 60 seconds and prevents idle-timeout disconnects. For actual network interruptions, tmux is the fix — keepalives don't help if the connection genuinely drops.

How do I run Claude Code on a server without keeping SSH open?

Use tmux to start Claude Code, detach with Ctrl+B D, and close SSH. For monitoring without re-opening SSH at all: install Grass (npm install -g @grass-ai/ide), run grass start --network tailscale, and scan the QR code from the Grass mobile app.