Wie ein KI-Agent einen echten Produktionsserver uber Ploi steuert
- devops
- ai-agents
- ploi
- security
Der Agent erstellt einen ephemeren SSH-Schlussel uber die Ploi API, hangt ihn an den Server, fuhrt seine Aufgabe aus und loscht den Schlussel nach Abschluss. Null verbleibende Zugangsdaten. Hier ist die vollstandige Geschichte des Deployments dieses Portfolios mit diesem Modell.
Das ist keine Hypothese. Das Portfolio, das du gerade liest, wurde von einem KI-Coding-Agenten bereitgestellt, der durch die Ploi API gearbeitet hat. Der Agent hat das Repository auf GitHub gepusht, den ersten gescheiterten Deploy beobachtet, das Lockfile-Problem diagnostiziert, das Deploy-Skript uber die API gepatcht, neu deployed und abgeschlossen, indem er einen taglichen Auto-Update-Cron hinzufugte und bestatige, dass pm2 die Site beim Reboot neu startet. Er hat das alles getan, ohne eine einzige persistente Zugangsdaten auf dem Server zu hinterlassen.
Das Muster in einem Satz
Gib dem Agenten ein Ploi API-Token. Sage ihm: Verwende die API, um einen ephemeren SSH-Schlussel auf Server X zu erstellen, verbinde dich, erledige was du brauchst, und losche dann den Schlussel. Das ist der gesamte Vertrag. Die Ploi API ist die Kontrollebene. SSH ist der Notausgang fur alles, was die API nicht direkt erledigen kann. Der Schlussel existiert fur die Dauer einer einzigen Aufgabe und ist weg, sobald die Aufgabe endet.
Alles andere, Deploys auslosen, Deploy-Skripte patchen, Cron-Jobs hinzufugen, GitHub-Repositories verbinden, SSL verwalten, Daemon-Uberwachung aktivieren, lauft ausschliesslich uber die REST API. Kein SSH fur diese Operationen notig. Der ephemere Schlussel ist nur fur chirurgische serverseitige Arbeit, die kein API-Aquivalent hat.

Die echte Geschichte: Deployment dieses Portfolios
Der Agent begann mit einem frischen Hetzner CX22, der bereits von Ploi provisioniert worden war. Das Repository war lokal bereit. Erste Aufgabe: Push zum GitHub-Remote der Produktion und Verbindung mit der Ploi-Site. Der Agent verwendete die Ploi API, um das GitHub-Repo mit der Site zu verbinden, den Branch auf main zu konfigurieren und zu bestatigen, dass der Webhook eingerichtet war.
Der erste automatische Deploy lief und schlug fehl. Das Deploy-Skript rief npm ci auf, aber die Lockfile im Repository war von einer neueren npm-Version generiert worden als die auf dem Server installierte. npm ci ist dabei streng: Es weigert sich zu installieren, wenn die Lockfile nicht genau zu seiner eigenen Version passt.
Der Agent las das Deploy-Log uber die Ploi API, identifizierte den Fehler in drei Sekunden und patche das Deploy-Skript uber einen einzigen API-Aufruf: npm ci durch npm install ersetzen. Dann loste er einen neuen Deploy aus. Dieser war erfolgreich. Der Agent brauchte SSH an keinem Punkt dieser Sequenz. Die API war ausreichend.
Nach dem erfolgreichen Deploy fugte der Agent zwei letzte Handgriffe hinzu: einen Cron-Job, der um 3 Uhr morgens taglich npm install und npm run build ausfuhrt und pm2 neu ladt, sowie eine Verifizierung, dass pm2 als Startup-Service konfiguriert ist, damit die Site einen Server-Reboot uberlebt. Der Cron wurde uber die Ploi API erstellt. Die pm2-Startup-Prufung erforderte eine SSH-Sitzung, also verwendete der Agent den ephemeren Schlussel-Ablauf.
Der ephemere SSH-Ablauf, in Code
Hier ist das genaue Shell-Skript, das der Agent verwendet hat. Es generiert einen 4096-Bit-RSA-Schlussel lokal, registriert die offentliche Halfte bei Ploi, verbindet sich und fuhrt seinen Befehl aus, und loscht dann den Schlussel uber die API. Kein Schlusselmaterial beruht je eine Konfigurationsdatei oder einen Secrets-Manager. Es lebt im Arbeitsspeicher und in einer temporaren Datei fur die Dauer der SSH-Sitzung, dann ist es weg.
#!/usr/bin/env bash
# agent-ssh.sh -- ephemeral SSH via Ploi API
# Usage: PLOI_TOKEN=xxx SERVER_ID=4821 SERVER_IP=95.111.42.7 bash agent-ssh.sh
set -euo pipefail
PLOI_TOKEN="$PLOI_TOKEN"
SERVER_ID="$SERVER_ID"
SERVER_IP="$SERVER_IP"
BASE="https://ploi.io/api"
KEY_FILE="/tmp/agent-key-$$.pem"
KEY_NAME="agent-ephemeral-$$"
# 1. Generate an RSA key pair on disk (temp, mode 600)
ssh-keygen -t rsa -b 4096 -N '' -f "$KEY_FILE" -C "$KEY_NAME" >/dev/null 2>&1
chmod 600 "$KEY_FILE"
PUB_KEY="$(cat "$KEY_FILE.pub")"
# 2. Register the public key on the target server via Ploi API
KEY_RESPONSE="$(curl -s -X POST \
-H "Authorization: Bearer $PLOI_TOKEN" \
-H "Content-Type: application/json" \
-H "Accept: application/json" \
-d '{"name":"'"$KEY_NAME"'","key":"'"$PUB_KEY"'"}' \
"$BASE/servers/$SERVER_ID/ssh-keys")"
KEY_ID="$(echo "$KEY_RESPONSE" | python3 -c 'import sys,json; print(json.load(sys.stdin)["sshKey"]["id"])')"
echo "[agent] registered ephemeral key id=$KEY_ID"
# 3. Connect over SSH and run the task
ssh -i "$KEY_FILE" \
-o StrictHostKeyChecking=no \
-o BatchMode=yes \
"ploi@$SERVER_IP" \
"cd /var/www/portfolio/current && npm install --prefer-offline && echo done"
# 4. Delete the key from the server and remove local files
curl -s -X DELETE \
-H "Authorization: Bearer $PLOI_TOKEN" \
-H "Accept: application/json" \
"$BASE/servers/$SERVER_ID/ssh-keys/$KEY_ID"
rm -f "$KEY_FILE" "$KEY_FILE.pub"
echo "[agent] ephemeral key deleted -- server access closed"Das $$ im Schlusselnamen enthalt die Shell-Prozess-ID, sodass gleichzeitige Agenten-Laufe nicht kollidieren. Die Bereinigung im Post-Session-Protokoll (beschrieben im AGENTS.md-Abschnitt unten) erfasst jeden Schlussel, der eine abgebrochene Sitzung uberlebt hat, indem das Alter gegen das Prafix agent-ephemeral gepruft wird.
Deploy-Skript patchen und Cron per API hinzufugen
Das zweite Code-Beispiel zeigt die beiden API-Aufrufe, die der Agent nach der Diagnose des fehlgeschlagenen Deploys gemacht hat: Deploy-Skript via PUT patchen, neuen Deploy auslosen und den taglichen Wartungs-Cron hinzufugen. Alle drei Operationen sind in einem einzigen Bash-Skript mit drei curl-Aufrufen.
#!/usr/bin/env bash
# patch-deploy-and-cron.sh
# Patches the deploy script and adds a daily auto-update cron via Ploi API.
set -euo pipefail
PLOI_TOKEN="$PLOI_TOKEN"
SITE_ID="$SITE_ID"
SERVER_ID="$SERVER_ID"
BASE="https://ploi.io/api"
# ---- 1. Patch the deploy script ----
# The first deploy failed: npm ci rejected the lockfile generated by a newer npm.
# Fix: replace "npm ci" with "npm install" in the deploy script.
NEW_SCRIPT='cd /var/www/portfolio/current
git fetch --depth=1 origin main
git reset --hard origin/main
npm install
npm run build
pm2 reload portfolio --update-env'
curl -s -X PUT \
-H "Authorization: Bearer $PLOI_TOKEN" \
-H "Content-Type: application/json" \
-H "Accept: application/json" \
-d '{"deploy_script":"'"$NEW_SCRIPT"'"}' \
"$BASE/servers/$SERVER_ID/sites/$SITE_ID" | python3 -c 'import sys,json; d=json.load(sys.stdin); print("[patch] site updated:", d.get("site",{}).get("name","ok"))'
# ---- 2. Trigger a fresh deploy ----
curl -s -X POST \
-H "Authorization: Bearer $PLOI_TOKEN" \
-H "Accept: application/json" \
"$BASE/servers/$SERVER_ID/sites/$SITE_ID/deploy" | python3 -c 'import sys,json; print("[deploy] triggered:", json.load(sys.stdin))'
# ---- 3. Add a daily 3am auto-update cron ----
curl -s -X POST \
-H "Authorization: Bearer $PLOI_TOKEN" \
-H "Content-Type: application/json" \
-H "Accept: application/json" \
-d '{"command":"cd /var/www/portfolio/current && npm install && npm run build && pm2 reload portfolio","frequency":"custom","custom_frequency":"0 3 * * *","user":"ploi"}' \
"$BASE/servers/$SERVER_ID/cron-jobs" | python3 -c 'import sys,json; d=json.load(sys.stdin); print("[cron] created id:", d.get("cronJob",{}).get("id","?"))'
echo "[agent] patch, redeploy, and cron setup complete"Kein SSH, kein Server-State, keine Dateibearbeitung. Das Deploy-Skript lebt in Ploi, der Cron lebt in Ploi, und beide werden uber eine dokumentierte REST API aktualisiert. Wenn du prufen mochtest, was wann geandert wurde, hat das Ploi-Dashboard einen vollstandigen Verlauf. Wenn du das Deploy-Skript zuruckrollen mochtest, tust du es uber dieselbe API.
Dem Agenten persistentes Gedachtnis mit AGENTS.md geben
Ein KI-Coding-Agent hat kein Langzeitgedachtnis zwischen Sitzungen, es sei denn, du gibst ihm explizit eines. Jedes Mal, wenn eine neue Sitzung beginnt, liest der Agent das Projektverzeichnis. Wenn du eine AGENTS.md-Datei im Repository eingecheckt hast, liest der Agent sie und weiss sofort die Server-Topologie, die Deploy-Konventionen, die bekannten Fehlermodi und das Bereinigungsprotokoll fur ephemere Schlussel.
Das ist keine Magie. Es ist nur eine Markdown-Datei, die der Agent zu Beginn jeder Sitzung zu lesen angewiesen ist. Aber der Ertrag ist enorm: Keine erneuten Antworten auf dieselben Setup-Fragen, keine konservativen Vermutungen daruber, welchen API-Endpunkt man aufrufen soll, kein Vergessen mehr, dass npm ci auf diesem bestimmten Server fehlschlagen wird.

Hier ist die tatsachliche AGENTS.md, die in dieses Portfolio-Repository eingecheckt ist. Sie dokumentiert den Server, die angewendete Deploy-Skript-Korrektur, den Cron-Plan und das Bereinigungsprotokoll.
# AGENTS.md -- Infrastructure memory for AI coding agents
## Server
- Provider: Hetzner CX22, Ubuntu 24.04 LTS
- Ploi server ID: 4821 (env: PLOI_SERVER_ID)
- Public IP: 95.111.42.7 (env: SERVER_IP)
- Site ID: 9103 (env: PLOI_SITE_ID)
- Stack: Node 20, nginx, pm2, PostgreSQL 16
## Deploy
Trigger via Ploi API:
POST https://ploi.io/api/servers/4821/sites/9103/deploy
Authorization: Bearer PLOI_TOKEN
Deploy script uses "npm install" (NOT "npm ci" -- lockfile version mismatch on first deploy).
Zero-downtime via pm2 reload.
## Cron
Daily auto-update at 03:00 UTC:
cd /var/www/portfolio/current && npm install && npm run build && pm2 reload portfolio
## Ephemeral SSH
Use agent-ssh.sh for any direct server access. Script mints a key via API, runs the task,
and deletes the key. Do NOT leave persistent keys on the server.
## Post-session cleanup
GET https://ploi.io/api/servers/4821/ssh-keys
DELETE any key with name prefix "agent-ephemeral" older than 60 minutes.Behandle AGENTS.md als lebendes Dokument. Jedes Mal, wenn der Agent etwas Bedeutsames andert, aktualisiere die Datei im selben Commit. Wenn du das Deploy-Skript anderst, halte die Anderung und den Grund fest. Wenn du einen Cron hinzufugst, dokumentiere ihn. Die Datei ist gunstig in der Pflege und lasst jede zukunftige Agenten-Sitzung von einer informierten Position starten anstatt von null.
Das Sicherheitsmodell: Minimale Privilegien, kurzeste Lebensdauer
Das Ploi API-Token gibt dem Agenten Kontrolle uber die Server-Management-Ebene: Deploy-Skripte, Crons, Sites, Daemons, Datenbanken, SSL. Es gibt dem Agenten keine Shell. Der ephemere SSH-Schlussel gibt dem Agenten eine Shell fur ein begrenztes Zeitfenster. Das sind zwei verschiedene Vertrauensebenen und der Agent verwendet jede genau dann, wenn sie angemessen ist.
- Das API-Token beruht nie den Server. Es authentifiziert sich bei Ploi, das dann den Server instruiert. Das Token kompromittiert zu haben bedeutet, dass ein Angreifer deine Sites neu konfigurieren kann. Eine Shell bekommt er nicht.
- Der ephemere SSH-Schlussel beruht den Server direkt, wird aber sofort nach der Verwendung geloscht. Sein Expositionsfenster ist Minuten, nicht Tage.
- Das API-Token sollte auf die minimal notwendigen Ressourcen eingeschrankt werden. Ploi unterstutzt Token-Einschrankungen pro Server.
- Wenn die Agenten-Sitzung nach dem Erstellen des SSH-Schlussels, aber vor dem Loschen absturtzt, behandelt das Bereinigungsprotokoll in AGENTS.md das: Alle Schlussel mit dem ephemeren Prafix prufen und alle loschen, die alter als eine Stunde sind.
- Kein menschlicher SSH-Schlussel muss fur Agentenarbeit zum Server hinzugefugt werden. Der Agent verwaltet seinen eigenen Zugang vollstandig uber die API.
Das ist das richtige Modell fur agentengesteuerte Automatisierung. Die Alternative, dem Agenten einen langlebigen SSH-Schlussel oder ein sudo-Passwort zu geben, bedeutet, dass eine kompromittierte Agenten-Sitzung persistenten root-aquivalenten Zugang zu deinem Produktionsserver hat. Ephemere Schlussel bedeuten, dass der Schadensradius einer einzelnen kompromittierten Sitzung begrenzt und automatisch auf null reduziert wird.
Ein KI-Agent sollte den minimal notwendigen Zugang fur die minimal notwendige Dauer haben. Die Ploi API macht das trivial durchzusetzen.
Was die Ploi API ohne SSH erledigen kann
Es lohnt sich, konkret zu sein, wie viel der Agent erledigen kann, ohne jemals eine SSH-Verbindung zu offnen. Die Ploi API deckt die gesamte Oberflache der Server-Verwaltung fur typische Webanwendungen ab.
- Sites erstellen und konfigurieren, Document Root setzen, mit einem GitHub- oder GitLab-Repository verbinden.
- Deploy-Skripte lesen, schreiben und auslosen.
- Cron-Jobs hinzufugen, bearbeiten und loschen.
- Supervisor-Daemon-Worker verwalten: erstellen, starten, stoppen, neu starten.
- Datenbanken und Datenbankbenutzer erstellen und loschen.
- SSL-Zertifikate uber Let's Encrypt ausstellen und erneuern.
- Deploy-Logs zur Diagnose lesen.
- SSH-Schlussel fur jeden Benutzer auf dem Server hinzufugen und entfernen.
- Dienste wie nginx, php-fpm und Redis uber die API neu starten.
SSH ist fur Operationen reserviert, die nicht uber die API exponiert werden: beliebige Befehle ausfuhren, Log-Dateien in Echtzeit inspizieren oder einmalige Dateisystem-Operationen durchfuhren. In der Praxis benotige der Agent fur ein Standard-Next.js- oder Node-Portfolio wie dieses SSH genau einmal: um zu verifizieren, dass pm2 als systemd-Startup-Service registriert wurde. Alles andere lief uber die API.
Das ist die Architektur. API-first, SSH als letztes Mittel, ephemere Schlussel wenn SSH benotigt wird, und ein eingechecktes AGENTS.md, das jeder zukunftigen Sitzung den Kontext gibt, den sie benotigt, um ohne Nachfragen zu handeln. Der Server bleibt sauber. Der Agent bleibt pruftbar. Und der beim ersten Lauf fehlgeschlagene Deploy ist gepatcht und lauft in der Produktion, vollstandig durch einen Agenten, der nie eine persistente Zugangsdaten hielt.