Skip to content

Paperclip-Dev-Umgebung auf Proxmox (VM) ​

Anleitung und Skripte zum Aufsetzen einer VM mit Paperclip, Claude Code, GitHub CLI, Codex CLI, Gemini CLI und Headless-Chrome auf einem Proxmox-VE-Host. Stand: 2026-10-04, durchgeführt für VM 110 paperclip-dev.

Ergebnis (Ist-Zustand) ​

PunktWert
Proxmox-Hostpve, 192.168.178.10, PVE 8.4.1, Zugriff ssh root@192.168.178.10 per Key
VM110 paperclip-dev, q35/SeaBIOS, CPU-Typ host, Autostart (onboot=1), qemu-guest-agent
OSUbuntu 24.04 LTS, offizielles Cloud-Image (noble-server-cloudimg-amd64.img, SHA256 geprüft) + cloud-init
Ressourcen8 Kerne, 16 GB RAM (kein Ballooning), 64 GB auf local-lvm (discard/ssd)
Netzstatisch 192.168.178.12/24, GW/DNS 192.168.178.1, Suchdomäne fritz.box, Bridge vmbr0
Benutzersysadmin: Admin, volles sudo, SSH-Key (cloud-init) · paperclip: Dienst und Agenten, SSH-Key, eingeschränktes sudo (s.u.)
Paperclip2026.1001.0, systemd-User-Dienst paperclipai.service (linger), authenticated/private, bind lan, Port 3100, eingebettete PostgreSQL (Port 54329)
Web-UIhttp://192.168.178.12:3100
ToolsNode 24.21 / npm 11.21 / pnpm 12.9, gh 2.102, Google Chrome 154, Claude Code 2.1.289, Codex CLI 0.160, Gemini CLI 0.62, build-essential, jq, ripgrep, tmux, htop, python3
Claude-Code-MCPchrome-devtools (npx -y chrome-devtools-mcp@latest --headless --isolated), user scope von paperclip

Entscheidungen (mit dem Auftraggeber geklärt) ​

  • VM statt LXC: Im LXC blockierte das Ubuntu-AppArmor-Profil chrome den Netzwerkzugriff von Chrome (siehe Archiv). In der VM läuft Chrome ohne Workaround.
  • Cloud-Image + cloud-init statt ISO-Installer: komplett per Skript, wiederholbar.
  • Feste IP außerhalb des FritzBox-DHCP-Bereichs: .12. Vorher in der FritzBox prüfen: Heimnetz → Netzwerk → Netzwerkeinstellungen → IPv4-Einstellungen.
  • Autostart mit dem Proxmox-Host.
  • Paperclip über die npm-CLI als Dienst, eingebettete DB, LAN-Zugriff mit Login.
  • Eigener Admin-User sysadmin, der Agenten-User paperclip bekommt nur eingeschränktes sudo.
  • Chrome stable + chrome-devtools-mcp, dazu Codex und Gemini CLI.

Eingeschränktes sudo für paperclip ​

Paperclip startet Claude Code mit --dangerously-skip-permissions, Agenten führen also alles aus, was paperclip darf. Deshalb sind nur drei root-eigene Wrapper in /usr/local/sbin per sudo ohne Passwort freigegeben (/etc/sudoers.d/90-paperclip):

BefehlErlaubt
sudo pc-apt update / upgrade / install <paket>…Paketnamen per Regex geprüft, keine Optionen, keine Pfade/.deb, nur Repo-Pakete
sudo pc-systemctl start|stop|restart|reload|status <unit>genau eine Unit, Name per Regex geprüft, --no-pager
sudo pc-power reboot|poweroffVM neu starten/herunterfahren

Alles andere fragt nach einem Passwort, und paperclip hat keins, also ist alles andere gesperrt. Warum Wrapper statt sudoers-Wildcards: apt-get install * ließe sich über -o APT::…::Pre-Invoke=… oder lokale .deb-Pakete zu root ausweiten, systemctl status öffnet als root einen Pager mit Shell-Escape. Restrisiko: Wer Repo-Pakete installieren darf, kann Dienste mit root-Rechten nachrüsten. Das ist bewusst akzeptiert. Getestet: erlaubte Aufrufe funktionieren, -o, ./x.deb, systemctl edit und Optionen als Unit-Namen werden abgewiesen, sudo id verlangt ein Passwort.

Ablauf ​

Alle Skripte liegen hier im Ordner und werden vom Windows-PC (Git Bash) per SSH ausgeführt.

bash
cd /c/work/docs/paperclip-dev
PUBKEY="$(cat ~/.ssh/id_ed25519.pub)"

# 1. VM auf dem Proxmox-Host anlegen (Image laden/prüfen, cloud-init, Start, wartet auf SSH)
ssh root@192.168.178.10 "SSH_PUBKEY='$PUBKEY' bash -s" < 01-create-vm.sh
#    Danach warten, bis cloud-init fertig ist (anfangs wird der Key abgelehnt, bis der User existiert):
ssh sysadmin@192.168.178.12 'cloud-init status --wait'

# 2. System, Tools, Guest-Agent, Benutzer + sudo-Wrapper, Claude Code
ssh sysadmin@192.168.178.12 "sudo APP_USER=paperclip SSH_PUBKEY='$PUBKEY' bash -s" < 02-provision.sh

# 3. Paperclip-Dienst, erlaubte Hosts, PATH, MCP, CEO-Einladung (als paperclip)
ssh paperclip@192.168.178.12 "ALLOWED_HOSTS='192.168.178.12' bash -s" < 03-paperclip.sh

Die Parameter in 01-create-vm.sh (VMID, NAME, CORES, MEMORY_MB, DISK_SIZE, IP_CIDR, GATEWAY, ADMIN_USER, ONBOOT …) lassen sich per Umgebungsvariable überschreiben. Vorher prüfen: freie ID (pvesh get /cluster/nextid), Storage (pvesm status), Bridge (ip -br addr), IP außerhalb des DHCP-Bereichs.

Manuelle Schritte nach der Installation ​

  1. Paperclip-Admin anlegen: Einladungslink öffnen (gültig 72 h). Jeder Dienst- oder VM-Neustart vor dem Anlegen des Admins macht den Link ungültig. Den aktuellen Link holen (als paperclip): journalctl --user -u paperclipai.service | grep "Invite URL" | tail -1 oder neu erzeugen: paperclipai auth bootstrap-ceo --base-url http://192.168.178.12:3100
  2. Claude Code anmelden: ssh paperclip@192.168.178.12, dann claude starten und dem Login folgen.
  3. GitHub CLI anmelden: gh auth login.
  4. Optional codex login und gemini (beim ersten Start) anmelden.
  5. Claude-Verbindung auf Langzeit-Token umstellen (sonst stehen alle Agenten nach 8 h): Verbindung in Paperclip einmal normal herstellen, dann als paperclip claude setup-token ausführen und ~/bin/pc-rotate-claude-connection.sh (aus diesem Ordner nach ~/bin/ kopieren) mit dem sk-ant-oat…-Token aufrufen.

Stolperfallen und Lösungen ​

ProblemUrsacheLösung
cloud-init: useradd: group admin exists, SSH-Key wird abgelehntUbuntu hat eine Systemgruppe adminAdmin-User nicht admin nennen (hier sysadmin)
SSH-Key direkt nach dem VM-Start abgelehntsshd läuft schon, bevor cloud-init den User anlegteinige Minuten warten, dann cloud-init status --wait
Diagnose ohne LoginDas Cloud-Image hat anfangs keinen Guest-AgentVM stoppen, Disk read-only auf dem Host einhängen (losetup -P -r /dev/pve/vm-<id>-disk-0, mount -o ro,noload …p1), /var/log/cloud-init.log lesen
IP-Prüfung meldet fälschlich „belegt“alter ARP-Eintrag (STALE) einer gelöschten VMEintrag mit ip neigh flush to <IP> leeren, nur REACHABLE werten (im Skript umgesetzt)
paperclipai install: npm returned an unexpected version response: [ "…" ]npm 12 gibt npm view … version --json als Array zurückbeim mit Node 24 gelieferten npm 11 bleiben, nicht npm@latest
npm-Warnung install scripts not yet covered by allowScriptsVorankündigung in npm 11.21nur eine Warnung, Skripte laufen noch (native Module geprüft). In npm 12 werden sie blockiert
Web-UI vom LAN: HTTP 403 hostname is not allowedOnboarding erlaubt nur Loopbackpaperclipai allowed-hostname <IP/Name>, dann paperclipai service restart
Agenten finden claude nichtDer systemd-User-Dienst hat ~/.local/bin nicht im PATHDrop-in ~/.config/systemd/user/paperclipai.service.d/path.conf
Einladungslink: Seite lädt, aber Einladung „nicht gefunden“ (API GET /api/invites/<token> → 404)Solange kein Admin existiert, erzeugt jeder Dienststart einen neuen Bootstrap-Link und macht den alten ungültigaktuellen Link aus dem Journal holen (s.o.), danach nicht mehr neu starten
CEO-Agent fehlt agents:configure (Agent bittet das Board um das Recht)Paperclip gibt agents:configure + skills:create nur dem Root-Agenten (ohne reportsTo) mit Rolle ceo; ein Agent namens „CEO“ mit Rolle general bekommt sie nichtRolle setzen: paperclipai agent update <id> --payload-json '{"role":"ceo"}', dann paperclipai service restart (Abgleich beim Start). Prüfen: paperclipai agent get <id> --json | jq .access.grants
Alle Claude-Agenten scheitern nach ~8 h mit ACP agent reported a terminal access failure (Kategorie access = auth_required)Paperclip speichert beim Subscription-Login nur den Claude-Access-Token (8 h gültig, kein Refresh-Token). AI-Verbindung zeigt trotzdem connectedLangzeit-Token: claude setup-token (ca. 1 Jahr) und damit das Credential der Verbindung rotieren: ~/bin/pc-rotate-claude-connection.sh (Skript hier im Ordner, Token verdeckt eingeben). Ein Token in adapterConfig.env hilft nicht: Paperclip entfernt Auth-Variablen bei verwalteten Verbindungen, und Agenten-Updates scheitern, solange die Verbindung abgelaufen ist
Agent darf nach manuellem Wecken keine Kommentare/Status schreiben (403)agent wake ohne Ticketbezug erzeugt einen Run ohne Issue-Bindung; Schreibzugriffe auf Issues verlangen einen gebundenen RunFehlgeschlagenen Run exakt wiederholen: POST /api/agents/<id>/wakeup mit {"failedRunId":"<run>","reason":"retry_failed_run","source":"on_demand","triggerDetail":"manual"}, oder per Kommentar mit paperclipai issue comment <issue> --resume wecken
paperclipai doctor: Service version: Running unknownDie Health-API liefert kein Versionsfeldkosmetisch
paperclip-dev.fritz.box löst nicht aufDie FritzBox lernt Namen nur über DHCPIP verwenden oder den Namen in einem eigenen DNS pflegen
(nur LXC) Chrome ERR_INTERNET_DISCONNECTED / CreatePlatformSocket() failed: Permission deniedDas AppArmor-Profil chrome aus Ubuntu 24.04 blockiert verschachtelt im LXC das Anlegen von SocketsVM verwenden. Altes LXC-Skript liegt unter archiv/

Nützliche Befehle ​

bash
# als paperclip
paperclipai service status | logs | restart
paperclipai doctor
paperclipai update
paperclipai db:backup

# auf dem Proxmox-Host
qm status 110; qm shutdown 110; qm start 110
qm snapshot 110 <name>          # vor größeren Änderungen
qm guest cmd 110 network-get-interfaces
qm terminal 110                 # serielle Konsole

Für die Produktivumgebung (Hostinger-VPS) später zu beachten ​

  • Dort authenticated + public mit expliziter Public-URL, bind loopback hinter einem Reverse-Proxy (TLS).
  • 02-provision.sh und 03-paperclip.sh sind weitgehend übertragbar (Ubuntu 24.04), ebenso npm 11, PATH-Drop-in und sudo-Wrapper.