Claude Code auf VPS mit tmux nutzen
Verhindern Sie den Abbruch der Claude Code Session bei SSH-Verbindungsabbruch. Nutzen Sie tmux auf einem Linux-VPS, um SIGHUP-Signale sicher zu ignorieren.
Das Problem ist der Laptop-Deckel, nicht das CLI
Claude Code funktioniert auf Ihrem Laptop einwandfrei, bis Sie ihn zuklappen: Die SSH-Sitzung wird beendet, die Shell erhält ein SIGHUP und der Agent stirbt drei Minuten nach Beginn eines Testlaufs mit. Führen Sie das CLI auf einem Gerät aus, das nicht in den Energiesparmodus wechselt, innerhalb eines Terminal-Multiplexers, dessen Prozesse keine Kinder Ihrer SSH-Sitzung sind. Das ist der entscheidende Punkt — tmux ist der wesentliche Bestandteil, nicht die Installation.
Diese Seite beschreibt den Betrieb eines Systems, auf dem Agenten laufen. Wenn Sie keinen Linux-Server haben, den Sie eingeschaltet lassen können, trifft nichts davon zu. Das ist die einzige Voraussetzung.
Was tmux tatsächlich bewirkt
Nach dem SSH-Login führt sshd einen Shell-Prozess aus und weist ihm ein Pseudo-Terminal zu; alle Prozesse, die Sie in dieser Shell starten, sind deren Unterprozesse. Wenn die Verbindung unterbrochen wird, schließt der Kernel das pty, die Shell erhält SIGHUP und beendet daraufhin ihre Unterprozesse. Prozesse, die im Vordergrund laufen, werden dadurch beendet.
tmux kehrt diese Hierarchie um. Der Befehl tmux kommuniziert über einen Unix-Socket mit einem tmux server, der unabhängig von Ihrem Terminal läuft. Shells innerhalb einer Session sind Unterprozesse dieses Servers und nicht von sshd. Wenn die SSH-Verbindung getrennt wird, wird der Client beendet, während der Server, die Session und der Agent die laufenden Aufgaben fortsetzen. Nach einer erneuten Verbindung via tmux attach befinden Sie sich wieder in derselben Shell mit demselben Scrollback. nohup überlebt einen Verbindungsabbruch ebenfalls, bietet aber keine Möglichkeit zur Rückkehr – ein Re-Attach an eine im Hintergrund laufende TUI ist nicht möglich. Claude Code ist interaktiv; tmux (oder screen) ist das richtige Werkzeug.
Dimensionierung des Systems
Die CLI ist ein Node-Prozess; sie verbraucht nicht die Ressourcen der Maschine. Die Ressourcen werden durch die Prozesse belegt, die der Agent in Ihrem Auftrag ausführt: ein Build, eine vollständige Testsuite, tsc, ein Language Server oder eine Datenbank in Docker. Dimensionieren Sie das System für die Toolchain, nicht für die CLI. Fügen Sie Swap hinzu, auch wenn Sie diesen nicht verwenden möchten — dies verwandelt einen harten OOM-Kill in einen langsamen Build:
sudo fallocate -l 4G /swapfile
sudo chmod 600 /swapfile
sudo mkswap /swapfile
sudo swapon /swapfile
echo '/swapfile none swap sw 0 0' | sudo tee -a /etc/fstabAchten Sie auch auf den Festplattenspeicher: Repositories, node_modules und Docker-Images nehmen schnell an Platz zu. Falls die Toolchain über Container hinaus auf vollständige virtuelle Maschinen zugreift — etwa ein KVM-Gast oder ein lokaler Kubernetes-Node — prüfen Sie vor der Buchung, ob der Plan CPU-Virtualisierungserweiterungen unterstützt. Das Ausführen von Nested Virtualization auf einem VPS muss vom Anbieter aktiviert werden; es kann nicht innerhalb des Gastsystems eingeschaltet werden.
Ein Benutzer ohne Root-Rechte zuerst
Erstellen Sie einen dedizierten Benutzer mit einem eigenen Home-Verzeichnis und hinterlegen Sie Ihren Public Key:
sudo adduser --disabled-password --gecos "" agent
sudo install -d -m 700 -o agent -g agent /home/agent/.ssh
sudo cp ~/.ssh/authorized_keys /home/agent/.ssh/authorized_keys
sudo chown agent:agent /home/agent/.ssh/authorized_keys
sudo chmod 600 /home/agent/.ssh/authorized_keysBewusst ist agent nicht in der Gruppe sudo. Falls ein Systempaket benötigt wird, installieren Sie dieses. Diese Entscheidung verhindert die meisten Möglichkeiten, durch einen fehlerhaften Shell-Befehl den Host zu beschädigen.
SSH-Hygiene für dauerhaft laufende Systeme
Die Passwort-Authentifizierung auf einem Gerät, das dauerhaft im öffentlichen Internet steht und einen Agent sowie Ihren Quellcode enthält, stellt ein unnötiges Risiko dar. Deaktivieren Sie diese Funktion. Auf Ubuntu 24.04 und Debian 13 enthält /etc/ssh/sshd_config /etc/ssh/sshd_config.d/*.conf. Erstellen Sie daher eine separate Datei, anstatt die Hauptkonfiguration zu bearbeiten:
# /etc/ssh/sshd_config.d/10-hardening.conf
PasswordAuthentication no
KbdInteractiveAuthentication no
PermitRootLogin noValidieren und neu laden — lassen Sie Ihre aktuelle Sitzung offen, während Sie eine neue Sitzung in einem zweiten Terminal testen:
sudo sshd -t && sudo systemctl restart sshEin Detail zu Ubuntu 24.04: sshd wird per Socket aktiviert. Authentifizierungseinstellungen gelten für systemctl restart ssh, aber eine Änderung am zu überwachenden Port erfordert zudem systemctl daemon-reload und einen Neustart von ssh.socket.
Danach die Firewall. Erlauben Sie SSH, bevor Sie die Passwort-Authentifizierung deaktivieren, sonst sperren Sie sich selbst aus:
sudo ufw allow OpenSSH
sudo ufw default deny incoming
sudo ufw default allow outgoing
sudo ufw enableInstallieren Sie fail2ban mit Bedacht: Sobald die Passwort-Authentifizierung deaktiviert ist, können Brute-Force-Angriffe ohnehin nicht erfolgreich sein. Das Tool verhindert lediglich, dass fehlgeschlagene Versuche das Journal füllen.
# /etc/fail2ban/jail.local
[sshd]
enabled = true
backend = systemd
maxretry = 5
bantime = 1hNutzen Sie abschließend sudo apt install unattended-upgrades und sudo dpkg-reconfigure -plow unattended-upgrades für automatische Updates. Beachten Sie die Wechselwirkung mit tmux: Wenn Unattended-Upgrade::Automatic-Reboot aktiviert ist, führt ein Kernel-Update zu einem Neustart des Systems, wodurch alle Sitzungen beendet werden. Lassen Sie die Funktion deaktiviert und führen Sie Neustarts manuell durch, wenn keine Prozesse laufen.
Node.js und Claude Code auf Ubuntu installieren
Claude Code ist ein Node CLI. Sie benötigen daher eine aktuelle Node-Version. Das Paket der Distribution ist oft veraltet. NodeSource ist der übliche Weg unter Ubuntu und Debian; es stellt ein signiertes Repository bereit (kein apt-key — dieses Tool existiert nicht mehr):
curl -fsSL https://deb.nodesource.com/setup_24.x | sudo -E bash -
sudo apt install -y nodejs
node --versionEin häufiger Fehler: Installieren Sie das CLI als Ihr agent-Benutzer und niemals mit sudo npm -g. Ein globaler Prefix unter Root führt später zu Berechtigungsfehlern und hinterlässt Dateien mit Root-Besitz im npm-Cache. Setzen Sie den npm-Prefix zuerst auf das Home-Verzeichnis des Benutzers:
mkdir -p ~/.npm-global
npm config set prefix ~/.npm-global
echo 'export PATH="$HOME/.npm-global/bin:$PATH"' >> ~/.bashrc
source ~/.bashrc
npm install -g @anthropic-ai/claude-code
claude --versionDer Export gehört in ~/.bashrc, nicht in ~/.profile. Er muss vor der Bedingung "If not running interactively, don't do anything" stehen, die sich am Anfang der Datei befindet. tmux startet eventuell Non-Login-Shells, welche ~/.bashrc lesen und ~/.profile überspringen — ~/.profile wird nur für Login-Shells ausgeführt. Ein benutzerbezogenes Node via eines Version-Managers wie nvm erreicht das gleiche Ergebnis; das Ziel ist in jedem Fall, dass npm install -g niemals sudo benötigt. npm funktioniert weiterhin einwandfrei, oder nutzen Sie das native Installationsskript von Anthropic, welches aktuell als Standard dokumentiert ist. Prüfen Sie die Installationsdokumentation von Anthropic vor dem Einfügen — Installationsmethoden ändern sich.
Führen Sie claude innerhalb eines Repositories aus, um es zu starten. Der erste Durchlauf führt Sie durch die Authentifizierung. Ein Headless-System hat keinen Browser; der Prozess gibt Ihnen daher eine URL zur Öffnung auf Ihrem eigenen Rechner und einen Code zur Rückgabe im Terminal aus. (Ein API-Key in den Umgebungsvariablen ist ein alternativer Weg.) In beiden Fällen wird die Anmeldedaten nun auf dem Server gespeichert — dies führt zu dem Punkt, den viele überspringen.
Das Thema Blast Radius
Ein Agent mit Shell-Zugriff ist eine Shell. Er kann alles lesen, was der ausführende Benutzer lesen kann, und Daten überall dorthin pushen, wohin dieser Benutzer pushen kann. Das ist keine Kritik am Tool, sondern dessen Definition – und deshalb ist das verwendete Konto wichtiger als jede einzelne Einstellung.
- Dedizierter, unprivilegierter Benutzer. Keine
sudo-Gruppe, kein Home-Verzeichnis, das mit Ihrem eigenen Konto geteilt wird. - Keine Produktions-Credentials auf dem System. Kein
~/.aws/credentialsmit Prod-Keys, keine von Produktion kopierten.env, keine Datenbank-Passwörter mit Schreibzugriff auf kritische Systeme. Geben Sie dem Agenten ein Staging- oder Read-only-Credential. - Scoped Tokens. Ein feingranulares GitHub-Token, das auf ein Repository beschränkt ist; ein Deploy Key, wenn Lesezugriff ausreicht.
Claude Code enthält eine Flag, die alle Berechtigungsabfragen überspringt. Auf einem Laptop oder in einem temporären Projekt liegt die Entscheidung bei Ihnen. Auf einem Server, der Tokens speichert, entfernt diese Flag die letzte Barriere zwischen einer falsch interpretierten Anweisung und einem git push --force. Was die Flag tatsächlich bewirkt und wie man einen Agenten, der mit dieser Flag läuft, begrenzt – von der integrierten Sandbox bis hin zu einem disposable VPS – wird in sicheres Ausführen von Claude Code auf einem Server behandelt.
Deploy Key vs. SSH Agent Forwarding
Es ist verlockend, ssh -A zu nutzen, damit git den Key auf Ihrem Laptop verwenden kann. Verstehen Sie, was dies gewährt: Agent Forwarding stellt den Socket Ihres lokalen SSH-Agents Prozessen zur Verfügung, die als dieser Benutzer auf dem System laufen. Alles, was als agent läuft – einschließlich des Agenten –, kann Ihren Key anfordern, um für jeden erreichbaren Host zu signieren, solange Sie verbunden bleiben. Das ist weit mehr als nur "git pull für dieses eine Repo".
Generieren Sie stattdessen einen Key auf dem Server, registrieren Sie ihn als Repository-spezifischen Deploy Key (Schreibzugriff nur, wenn der Agent pushen muss) und setzen Sie eine git-Identität, damit Commits vom System aus erkennbar sind:
ssh-keygen -t ed25519 -C "agent deploy key" -f ~/.ssh/id_ed25519_repo
cat ~/.ssh/id_ed25519_repo.pub # paste into the repo's Deploy Keys
git config --global user.name "Agent (build box)"
git config --global user.email "agent@example.com"Der tmux-Workflow
Installieren Sie tmux (sudo apt install tmux) und erstellen Sie anschließend eine minimale Konfiguration (~/.tmux.conf):
set -g mouse on
set -g history-limit 50000
set -g default-terminal "tmux-256color"Diese vier Befehle werden im Alltag benötigt:
tmux new -A -s claude # attach to session "claude", creating it if absent
# ...run `claude` inside it, work normally...
# Ctrl-b then d -> detach; everything keeps running
tmux ls # list sessions
tmux attach -t claude # reattach, from this machine or any other
tmux kill-session -t claudetmux new -A -s claude ist der wichtigste Befehl. Er verbindet sich mit einer bestehenden Session oder erstellt eine neue, falls keine existiert. Ein Befehl deckt somit sowohl den Arbeitsbeginn als auch die Wiederaufnahme nach einer Unterbrechung ab. Erstellen Sie dafür ein Alias. Innerhalb einer Session öffnet Ctrl-b c ein Fenster, Ctrl-b n und Ctrl-b p wechseln zwischen den Fenstern, und Ctrl-b [ wechselt in den Copy-Mode zum Scrollen (q beendet diesen Modus).
Ein wichtiger Hinweis zu dauerhaft laufenden Sessions: Der Agent sendet bei jeder Interaktion den gesamten Gesprächsverlauf erneut. Lesen Sie daher wobei Claude Code bei lang laufenden Sessions Tokens verbraucht, bevor Sie eine Session eine Woche lang offen lassen.
Fehlerursachen
"My session is gone." tmux ls gibt no server running on /tmp/tmux-1000/default aus. Dies bedeutet fast immer, dass der Prozess nie innerhalb von tmux lief — Sie haben sich per SSH eingeloggt, claude direkt ausgeführt, und die Trennung hat den Prozess beendet. Es gibt nichts wiederherzustellen. Die Gewohnheit zur Vermeidung: tmux new -A -s <project> ist der erste Befehl nach jedem Login.
Das Pane schrumpft zu einem winzigen Feld. tmux passt die Session-Größe an den kleinsten verbundenen Client an. Ein veralteter Client, der noch von einem anderen Rechner aus verbunden ist, verkleinert die Anzeige. Trennen Sie andere Verbindungen beim Verbinden mit: tmux attach -d -t claude.
Ein Build gibt Killed aus. Nur ein Wort, kein Stacktrace. Bestätigen Sie dies mit sudo dmesg -T | grep -i -E 'out of memory|killed process' — der Kernel OOM-Killer hat den größten Prozess ausgewählt. Bei Node sehen Sie stattdessen eventuell FATAL ERROR: Ineffective mark-compacts near heap limit Allocation failed - JavaScript heap out of memory. Lösungen in der Reihenfolge: Swap hinzufügen (siehe oben), Test- und Compiler-Parallelität begrenzen, den Node-Heap mit NODE_OPTIONS=--max-old-space-size=... erhöhen oder den VPS aufrüsten. Der OOM-Killer kann auch den tmux server statt des Builds auswählen, wodurch die Session verloren geht; wenn systemd-oomd läuft, kann ein ganzer User-Slice mit demselben Effekt beendet werden.
npm error code EACCES / permission denied, mkdir '/usr/lib/node_modules/...'. Eine globale Installation in einen Root-geschützten Prefix. Verwenden Sie den ~/.npm-global Prefix von oben. Wenn Sie bereits sudo npm ausgeführt haben, sehen Sie eventuell auch Your cache folder contains root-owned files — beheben Sie dies mit sudo chown -R $(id -u):$(id -g) ~/.npm.
claude: command not found — aber nur manchmal. Ihr PATH Export befindet sich in ~/.bashrc unterhalb der Bedingung "If not running interactively, don't do anything", weshalb nicht-interaktive Shells ihn überspringen. Verschieben Sie den Export oberhalb dieser Bedingung und speichern Sie ihn in ~/.bashrc statt in ~/.profile: tmux kann Non-Login-Shells starten, die ~/.bashrc lesen, aber ~/.profile niemals anfassen.
Fehlerhafte Farben nach dem Verbinden. Ein TERM Mismatch — die default-terminal Zeile oben ist die Lösung.
Sessions verschwinden nach einem Reboot. Kein Bug: Der tmux server ist ein Prozess, und ein Reboot beendet ihn. Prüfen Sie uptime.
Probleme bei steigender Komplexität
Mehr Projekte. Nutzen Sie pro Repository eine tmux-Session, benannt nach dem jeweiligen Repo; tmux ls dient dann als Dashboard. Ohne diese Benennungsdisziplin entstehen Sessions wie 0, 1 und 2. Ports verbreitern sich auf die gleiche Weise — wenn sechs Repositories alle :3000 benötigen, sollten Sie die manuelle Zuweisung aufgeben. Lassen Sie einen Traefik Reverse Proxy mehrere Apps unter Docker Compose über den Hostnamen routen.
Mehr Benutzer. tmux-Sockets sind pro Benutzer; zwei Entwickler auf demselben System erhalten jeweils einen eigenen tmux-Server und können die Sessions des jeweils anderen nicht sehen. Das Teilen einer Session über einen gemeinsamen Socket bedeutet, dass alle Benutzer in derselben Shell als derselbe Unix-Benutzer tippen. Dies hat entsprechende Konsequenzen für das Audit-Logging und die Berechtigungen. Separate Benutzer sind die einfache und korrekte Lösung.
Unbeaufsichtigte Prozesse. tmux ist für interaktive Sessions gedacht, an die man sich anbindet. Aufgaben, die nach einem Zeitplan ohne Benutzerinteraktion laufen, gehören in eine systemd unit und einen Timer. Dort erhalten sie automatisch Logging, eine Restart-Policy und Boot-Resilienz. Die Verwendung von tmux für Cron-ähnliche Aufgaben deutet darauf hin, dass die Aufgabe als Service ausgeführt werden sollte.
Ein letzter Hinweis: Binden Sie Dev-Server so, dass der Agent sie unter 127.0.0.1 statt 0.0.0.0 erreicht. Nutzen Sie einen SSH-Tunnel (ssh -L 3000:127.0.0.1:3000 agent@your-server), anstatt Ports in ufw zu öffnen. Wenn Sie eine Vielzahl von Ports weiterleiten müssen oder mehrere Geräte gleichzeitig auf eine Vorschau zugreifen wollen, schalten Sie stattdessen ein selbst gehostetes WireGuard VPN auf dem VPS vor: Die Dev-Server binden an ein privates Interface, und ufw blockiert weiterhin alle Anfragen über das öffentliche Interface. Eine Firewall ist nur dann hilfreich, wenn man keine Löcher mehr in sie bohrt.
Claude Code ist nicht die einzige Option: das Ausführen eines Coding-KI-Agents auf einem VPS umfasst auch Aider und Goose.
FAQ
Läuft Claude Code weiter, wenn meine SSH-Verbindung abbricht?
Nur wenn Sie es innerhalb von tmux gestartet haben. Ein Prozess, der direkt aus der SSH-Shell gestartet wurde, ist ein Kindprozess dieser Shell und wird beendet, sobald die pty durch den Verbindungsabbruch verloren geht. Innerhalb von tmux gehört die Shell zum getrennten tmux-Server. Der Agent arbeitet die Aufgabe weiter aus und tmux attach setzt Sie wieder in den ursprünglichen Scrollback ein. Machen Sie tmux new -A -s <project> zum ersten Befehl nach jedem Login, um dieses Problem zu vermeiden.
Sollte ich das CLI mit sudo npm install -g installieren?
Nein. Ein globaler Prefix unter Root-Rechten führt bei späteren Installationen zu EACCES-Fehlern und zu Root-besitzenden Dateien im npm-Cache. Setzen Sie den npm-Prefix auf ~/.npm-global (oder nutzen Sie einen Version-Manager wie nvm), installieren Sie als unprivilegierter agent-Benutzer und exportieren Sie ~/.npm-global/bin nach PATH aus ~/.bashrc, oberhalb der interaktiven Absicherung. Falls Sie sudo npm bereits einmal ausgeführt haben, reparieren Sie den Cache mit sudo chown -R $(id -u):$(id -g) ~/.npm.
Ist ssh -A Agent Forwarding auf einem System sicher, auf dem ein Agent läuft?
Es gewährt deutlich mehr Berechtigungen, als für die Aufgabe benötigt werden. Das Forwarding legt den Socket Ihres lokalen SSH-Agents für jeden Prozess offen, der als dieser Benutzer läuft. Daher kann jeder Prozess auf dem System Ihren Schlüssel nutzen, um Signaturen für jeden erreichbaren Host zu erstellen, solange die Verbindung besteht. Generieren Sie einen ed25519-Schlüssel auf dem Server und registrieren Sie ihn als Repository-spezifischen Deploy-Key, wobei Schreibzugriff nur bei Bedarf für Push-Operationen gewährt werden sollte.
Warum gibt mein Build nur Killed aus?
Ein einzelnes Wort ohne Stacktrace deutet auf den Kernel OOM-Killer hin. Bestätigen Sie dies mit sudo dmesg -T | grep -i -E 'out of memory|killed process'; unter Node.js sehen Sie eventuell JavaScript heap out of memory. Arbeiten Sie die Fehlerbehebungen der Reihe nach ab: Fügen Sie eine Swapfile hinzu, begrenzen Sie die Parallelität von Test und Compiler, erhöhen Sie NODE_OPTIONS=--max-old-space-size=... und skalieren Sie anschließend den VPS hoch. Beachten Sie, dass der OOM-Killer den tmux-Server statt des Build-Prozesses auswählen kann, wodurch die gesamte Session verloren geht.
tmux oder ein systemd Service?
tmux eignet sich für interaktive Sessions, an die man sich anbindet, die man überwacht und in die man tippt; genau das ist eine Agent-Session. Aufgaben, die nach einem Zeitplan ohne menschliche Überwachung laufen, gehören in eine systemd Unit und einen Timer. Dort sind Logging, eine Restart-Policy und Boot-Resilienz standardmäßig enthalten. Wenn Sie tmux verwenden möchten, um einen Cron-ähnlichen Job auszuführen, sollte dieser Job als Service konfiguriert werden.