Running Claude Code locally is a seamless experience. However, when you migrate long-running tasks—such as refactoring an entire codebase or executing a batch of tests—to a cloud-based VPS, two recurring issues often arise: processes are killed when an SSH connection drops, or tasks are abruptly terminated by the OOM (Out-of-Memory) Killer when memory is exhausted. These are not merely occasional "glitches"; they represent a structural conflict between traditional SSH sessions/virtualized resource models and the specific demands of AI-driven coding workloads.
Understanding the root cause of these conflicts is the key to configuring your environment correctly.
I. SSH Disconnections: Why do processes die along with the terminal?
A traditional SSH session is bound to a terminal (TTY). As a foreground process, Claude Code’s lifecycle is tightly coupled to this terminal. If a network fluctuation causes the SSH connection to drop, the system sends a `SIGHUP` signal to all processes within that session—the default behavior being to terminate them immediately.
This means that a long-running task—one that may have been executing for half an hour and consuming a significant number of tokens—can be completely wiped out by something as trivial as a Wi-Fi network switch. The solution is not to "ensure the network never drops," but rather to decouple the process from the terminal so it can persist independently.
Option 1: `tmux` — A "disconnection-proof shell" for interactive sessions
If your task requires you to occasionally check progress or intervene with new prompts, `tmux` is the ideal choice. Its core value lies in maintaining a virtual terminal that remains independent of any specific, active SSH connection.
The workflow is straightforward. After logging into your VPS via SSH, create a named session:
tmux new -s claude_agent
Launch Claude Code as usual within the `tmux` environment. When you need to step away—or if you anticipate network instability—press `Ctrl+B`, release the keys, and then press `D` (to "detach"). You will return to your standard command line, while Claude Code continues to run in the `tmux` background. The next time you connect to the VPS, simply run `tmux attach -t claude_agent` to return to your previous session, with all your progress fully preserved. Option 2: systemd User Service — A Persistent, Unattended Solution
If Claude Code needs to run in a completely unattended manner—such as monitoring a queue or executing automated tasks—the "manual attach/detach" approach offered by `tmux` is insufficient. In such cases, you should configure it as a `systemd` user service. A crucial detail: it must be a *user* service (`systemctl --user`), not a *system* service. Claude Code requires access to your home directory and OAuth credentials; running it as `root` or as a system-level service would break these dependencies.
First, enable "lingering" to ensure that user services remain active even after you log out:
loginctl enable-linger $USER
Create a file at `~/.config/systemd/user/claude.service` and, within the `[Service]` section, set `Restart=always` and `RestartSec=10`. This ensures that if Claude Code exits due to an intermittent error, the system will automatically restart it after 10 seconds.
II. OOM: Why Does Claude Code’s Memory Usage Seem to "Spiral Out of Control"?
Official Claude Code documentation explicitly requires a separate memory limit for each session. The reason is that when multiple sessions share a single memory ceiling, a memory spike in one session can cause all other sessions to be terminated—as the kernel does not distinguish between individual sessions when deciding which processes to kill.
Users on GitHub have reported that the RSS (Resident Set Size) memory of a single Claude Code session can climb steadily—from around 300MB to a defined `MemoryMax` limit—within 8 to 13 minutes, eventually triggering termination by `systemd-oomd`. This is not a "bug" in the code, but rather an inherent characteristic of AI-driven coding workloads: context accumulates continuously, tool processes remain resident, and build or test steps often trigger transient memory spikes.
Core Principle: Assign a dedicated memory limit to each session.
Within a `systemd` user service, you can establish a hard boundary for Claude Code using the `MemoryMax` directive:
ini
[Service]
MemoryMax=8G
MemorySwapMax=5%
`MemoryMax` triggers precise termination at the cgroup level—the kernel kills only the processes contained within that specific service, without affecting other tasks or services running on the host machine. The role of `MemorySwapMax` is equally critical: without a limit on swap space, a process reaching its memory cap would simply spill over into swap rather than being terminated—effectively rendering the memory limit meaningless.
When running Claude Code in a Docker container, this corresponds to the `--memory` flag or the `mem_limit` setting in a Compose file. The principle remains the same: one session per container, with a defined memory limit for each. The sum of these limits across all containers should be less than the host machine's total available memory, ensuring sufficient headroom for the host's own processes.
An additional safeguard involves limiting the number of processes or threads. During build and test phases, Claude Code may spawn a large number of sub-processes. If the process limit is reached, new commands or build tasks will fail with an `EAGAIN` error ("Resource temporarily unavailable"). Setting an upper limit via `TasksMax` in a systemd service, or using `--pids-limit` in Docker, helps prevent this hidden bottleneck.
III. The Underlying Prerequisite: Network Quality Sets the Ceiling for "Connection Stability"
While `tmux` and `systemd` ensure that processes remain alive, they cannot eliminate timeouts and retries caused by network issues. Claude Code operates by frequently calling cloud-based APIs, with each request relying on an SSH tunnel or a persistent direct connection. If the return path (inbound to your VPS) experiences significant packet loss—common during evening peak hours—API requests will repeatedly time out. This forces Claude Code into a cycle of retries, leading to increased token consumption and longer task execution times.
Running Claude Code in the cloud is not merely about "getting the service started"; it is about establishing an execution environment that is decoupled from the interactive terminal and aligned with defined resource constraints. `tmux` ensures the survival of interactive sessions, `systemd` user services facilitate unattended, persistent operation, and the combination of `MemoryMax` and `MemorySwapMax` prevents uncontrolled memory usage. Ultimately, a high-quality, low-packet-loss network connection—such as a CN2 GIA route—is what ensures that all these configurations remain effective under real-world network conditions.