Appearance
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)
| Punkt | Wert |
|---|---|
| Proxmox-Host | pve, 192.168.178.10, PVE 8.4.1, Zugriff ssh root@192.168.178.10 per Key |
| VM | 110 paperclip-dev, q35/SeaBIOS, CPU-Typ host, Autostart (onboot=1), qemu-guest-agent |
| OS | Ubuntu 24.04 LTS, offizielles Cloud-Image (noble-server-cloudimg-amd64.img, SHA256 geprüft) + cloud-init |
| Ressourcen | 8 Kerne, 16 GB RAM (kein Ballooning), 64 GB auf local-lvm (discard/ssd) |
| Netz | statisch 192.168.178.12/24, GW/DNS 192.168.178.1, Suchdomäne fritz.box, Bridge vmbr0 |
| Benutzer | sysadmin: Admin, volles sudo, SSH-Key (cloud-init) · paperclip: Dienst und Agenten, SSH-Key, eingeschränktes sudo (s.u.) |
| Paperclip | 2026.1001.0, systemd-User-Dienst paperclipai.service (linger), authenticated/private, bind lan, Port 3100, eingebettete PostgreSQL (Port 54329) |
| Web-UI | http://192.168.178.12:3100 |
| Tools | Node 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-MCP | chrome-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
chromeden 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-Userpaperclipbekommt 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):
| Befehl | Erlaubt |
|---|---|
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|poweroff | VM 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.shDie 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
- 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 -1oder neu erzeugen:paperclipai auth bootstrap-ceo --base-url http://192.168.178.12:3100 - Claude Code anmelden:
ssh paperclip@192.168.178.12, dannclaudestarten und dem Login folgen. - GitHub CLI anmelden:
gh auth login. - Optional
codex loginundgemini(beim ersten Start) anmelden. - Claude-Verbindung auf Langzeit-Token umstellen (sonst stehen alle Agenten nach 8 h): Verbindung in Paperclip einmal normal herstellen, dann als paperclip
claude setup-tokenausführen und~/bin/pc-rotate-claude-connection.sh(aus diesem Ordner nach~/bin/kopieren) mit demsk-ant-oat…-Token aufrufen.
Stolperfallen und Lösungen
| Problem | Ursache | Lösung |
|---|---|---|
| cloud-init: useradd: group admin exists, SSH-Key wird abgelehnt | Ubuntu hat eine Systemgruppe admin | Admin-User nicht admin nennen (hier sysadmin) |
| SSH-Key direkt nach dem VM-Start abgelehnt | sshd läuft schon, bevor cloud-init den User anlegt | einige Minuten warten, dann cloud-init status --wait |
| Diagnose ohne Login | Das Cloud-Image hat anfangs keinen Guest-Agent | VM 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 VM | Eintrag 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ück | beim mit Node 24 gelieferten npm 11 bleiben, nicht npm@latest |
| npm-Warnung install scripts not yet covered by allowScripts | Vorankündigung in npm 11.21 | nur eine Warnung, Skripte laufen noch (native Module geprüft). In npm 12 werden sie blockiert |
| Web-UI vom LAN: HTTP 403 hostname is not allowed | Onboarding erlaubt nur Loopback | paperclipai allowed-hostname <IP/Name>, dann paperclipai service restart |
Agenten finden claude nicht | Der systemd-User-Dienst hat ~/.local/bin nicht im PATH | Drop-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ültig | aktuellen 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 nicht | Rolle 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 connected | Langzeit-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 Run | Fehlgeschlagenen 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 unknown | Die Health-API liefert kein Versionsfeld | kosmetisch |
paperclip-dev.fritz.box löst nicht auf | Die FritzBox lernt Namen nur über DHCP | IP verwenden oder den Namen in einem eigenen DNS pflegen |
(nur LXC) Chrome ERR_INTERNET_DISCONNECTED / CreatePlatformSocket() failed: Permission denied | Das AppArmor-Profil chrome aus Ubuntu 24.04 blockiert verschachtelt im LXC das Anlegen von Sockets | VM 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 KonsoleFür die Produktivumgebung (Hostinger-VPS) später zu beachten
- Dort
authenticated+publicmit expliziter Public-URL,bind loopbackhinter einem Reverse-Proxy (TLS). 02-provision.shund03-paperclip.shsind weitgehend übertragbar (Ubuntu 24.04), ebenso npm 11, PATH-Drop-in und sudo-Wrapper.