Cum opereaza un agent AI un server real de productie prin Ploi
- devops
- ai-agents
- ploi
- security
Agentul creeaza o cheie SSH efemera prin API-ul Ploi, o ataseaza la server, isi executa sarcina si o sterge la final. Zero acces rezidual. Iata toata povestea deploymentului acestui portofoliu cu acel model.
Aceasta nu e o poveste ipotetica. Portofoliul pe care il citesti acum a fost deployat de un agent AI de coding care a lucrat prin API-ul Ploi. Agentul a facut push al repository-ului pe GitHub, a vazut primul deploy esuat, a diagnosticat problema cu lockfile-ul, a patch-uit scriptul de deploy prin API, a facut un nou deploy si a incheiat adaugand un cron zilnic de auto-actualizare si confirmand ca pm2 reporneste site-ul la reboot. A facut toate astea fara a lasa nicio credentiala persistenta pe server.
Modelul intr-o singura propozitie
Da agentului un token API Ploi. Spune-i: foloseste API-ul pentru a crea o cheie SSH efemera pe serverul X, conecteaza-te, fa ce ai de facut, apoi sterge cheia. Acesta este intregul contract. API-ul Ploi este planul de control. SSH este usa de urgenta pentru tot ce API-ul nu poate face direct. Cheia exista pe durata unei singure sarcini si dispare in momentul in care sarcina se incheie.
Orice altceva, declansarea deploy-urilor, patch-uirea scripturilor de deploy, adaugarea de cron job-uri, conectarea repository-urilor GitHub, gestionarea SSL, activarea supravegherii daemon-ilor, curge exclusiv prin REST API. Nu e nevoie de SSH pentru aceste operatiuni. Cheia efemera este rezervata doar pentru lucru chirurgical pe server care nu are echivalent in API.

Povestea reala: Deploymentul acestui portofoliu
Agentul a pornit cu un Hetzner CX22 deja provizionat de Ploi. Repository-ul era gata local. Prima sarcina: push catre remote-ul GitHub de productie si conectarea la site-ul Ploi. Agentul a folosit API-ul Ploi pentru a asocia repo-ul GitHub cu site-ul, a configura branch-ul pe main si a confirma ca webhook-ul era in loc.
Primul deploy automat a rulat si a esuat. Scriptul de deploy apela npm ci, dar lockfile-ul din repository fusese generat de o versiune mai noua de npm decat cea instalata pe server. npm ci este strict in aceasta privinta: refuza sa instaleze daca lockfile-ul nu se potriveste exact cu propria sa versiune.
Agentul a citit log-ul de deploy prin API-ul Ploi, a identificat eroarea in trei secunde si a patch-uit scriptul de deploy printr-un singur apel API: inlocuieste npm ci cu npm install. Apoi a declansat un nou deploy. Acela a reusit. Agentul nu a avut nevoie de SSH in niciun punct al acestei secvente. API-ul a fost suficient.
Dupa deploy-ul reusit, agentul a adaugat doua finisaje: un cron job programat la ora 3 dimineata zilnic care ruleaza npm install si npm run build si reincarca pm2, si o verificare ca pm2 este configurat ca serviciu de startup astfel incat site-ul sa supravietuiasca unui reboot de server. Cron-ul a fost creat via API Ploi. Verificarea startup-ului pm2 a necesitat o sesiune SSH, deci agentul a folosit fluxul cheii efemere.
Fluxul SSH efemer, in cod
Iata exact scriptul shell pe care l-a folosit agentul. Genereaza o cheie RSA de 4096 biti local, inregistreaza jumatatea publica la Ploi, se conecteaza si ruleaza comanda sa, dupa care sterge cheia prin API. Niciun material de cheie nu atinge vreodata un fisier de configuratie sau un manager de secrete. Traieste in memorie si intr-un fisier temporar pe durata sesiunii SSH, apoi dispare.
#!/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"Simbolul $$ din numele cheii incorporeaza ID-ul procesului shell, astfel incat rumarile concurente ale agentului nu se ciocnesc. Curatarea din protocolul post-sesiune (descris in sectiunea AGENTS.md de mai jos) captureaza orice cheie care a supravietuit unei sesiuni blocate verificand varsta fata de prefixul agent-ephemeral.
Patch-uirea scriptului de deploy si adaugarea cron-ului via API
Al doilea exemplu de cod arata cele doua apeluri API pe care le-a facut agentul dupa diagnosticarea deploy-ului esuat: patch-uieste scriptul de deploy via PUT, declanseaza un nou deploy si adauga cron-ul zilnic de intretinere. Toate trei operatiunile sunt intr-un singur script bash cu trei apeluri curl.
#!/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"Niciun SSH, nicio stare a serverului, nicio editare de fisiere. Scriptul de deploy traieste in Ploi, cron-ul traieste in Ploi, si ambele sunt actualizate printr-un REST API documentat. Daca vrei sa auditezi ce s-a schimbat si cand, dashboard-ul Ploi are un istoric complet. Daca vrei sa dai rollback scriptului de deploy, o faci prin acelasi API.
A da agentului memorie persistenta cu AGENTS.md
Un agent AI de coding nu are memorie pe termen lung intre sesiuni decat daca ii dai una explicit. De fiecare data cand incepe o noua sesiune, agentul citeste directorul proiectului. Daca ai commitat un fisier AGENTS.md in repository, agentul il citeste si stie imediat topologia serverului, conventiile de deploy, modurile de esec cunoscute si protocolul de curatare pentru cheile efemere.
Nu e magie. E doar un fisier markdown pe care agentul este instruit sa il citeasca la inceputul fiecarei sesiuni. Dar castigul este enorm: nu mai raspunzi la aceleasi intrebari de setup in mod repetat, nu mai faci presupuneri conservative despre ce endpoint API sa apelezi, nu mai uiti ca npm ci va esua pe acest server particular.

Iata AGENTS.md real commitat in acest repository de portofoliu. Documenteaza serverul, corectia scriptului de deploy aplicata, programul cron si protocolul de curatare.
# 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.Trateaza AGENTS.md ca un document viu. De fiecare data cand agentul schimba ceva semnificativ, actualizeaza fisierul in acelasi commit. Cand schimbi scriptul de deploy, inregistreaza schimbarea si motivul. Cand adaugi un cron, documenteaza-l. Fisierul e ieftin de intretinut si face ca fiecare sesiune viitoare a agentului sa inceapa dintr-o pozitie informata mai degraba decat de la zero.
Modelul de securitate: privilegiu minim, durata minima
Token-ul API Ploi da agentului control asupra planului de management al serverului: scripturi de deploy, cron-uri, site-uri, daemoni, baze de date, SSL. Nu ii da agentului un shell. Cheia SSH efemera da agentului un shell pentru o fereastra delimitata. Acestea sunt doua niveluri de incredere diferite si agentul le foloseste pe fiecare exact cand este adecvat.
- Token-ul API nu atinge niciodata serverul. Se autentifica la Ploi, care apoi instruieste serverul. Token-ul compromis inseamna ca un atacator poate reconfigura site-urile tale. Nu poate obtine un shell.
- Cheia SSH efemera atinge serverul direct dar este stearsa imediat dupa utilizare. Fereastra sa de expunere este de minute, nu zile.
- Token-ul API ar trebui limitat la resursele minim necesare. Ploi suporta restrictii de token per server.
- Daca sesiunea agentului se blocheaza dupa crearea cheii SSH dar inainte de stergere, protocolul de curatare din AGENTS.md o gestioneaza: verifica toate cheile cu prefixul efemer si sterge-le pe cele mai vechi de o ora.
- Nicio cheie SSH detinuta de un om nu trebuie adaugata pe server pentru lucrul agentului. Agentul isi gestioneaza propriul acces in intregime prin API.
Acesta este modelul corect pentru automatizarea condusa de agenti. Alternativa, a da agentului o cheie SSH de lunga durata sau o parola sudo, inseamna ca o sesiune compromisa a agentului are acces persistent echivalent root-ului la serverul tau de productie. Cheile efemere inseamna ca raza de explozie a oricarei sesiuni compromise este delimitata si automat redusa la zero.
Un agent AI ar trebui sa aiba accesul minim necesar pentru durata minima necesara. API-ul Ploi face asta trivial de aplicat.
Ce poate face API-ul Ploi fara SSH
Merita sa fim concret in privinta cat de mult poate realiza agentul fara a deschide vreodata o conexiune SSH. API-ul Ploi acopera intreaga suprafata a gestionarii serverului pentru aplicatii web tipice.
- Creeaza si configureaza site-uri, seteaza document root, conecteaza-te la un repository GitHub sau GitLab.
- Citeste, scrie si declanseaza scripturi de deploy.
- Adauga, editeaza si sterge cron job-uri.
- Gestioneaza workeri daemon supervisor: creeaza, porneste, opreste, reporneste.
- Creeaza si distruge baze de date si utilizatori de baze de date.
- Emite si reinnoieste certificate SSL via Let's Encrypt.
- Citeste log-urile de deploy pentru diagnostic.
- Adauga si sterge chei SSH pentru orice utilizator de pe server.
- Reporneste servicii precum nginx, php-fpm si Redis prin API.
SSH este rezervat pentru operatiuni care nu sunt expuse prin API: rularea de comenzi arbitrare, inspectarea fisierelor de log in timp real sau efectuarea de operatiuni one-off pe filesystem. In practica, pentru un portofoliu standard Next.js sau Node ca acesta, agentul a avut nevoie de SSH exact o data: pentru a verifica ca pm2 fusese inregistrat ca serviciu de startup systemd. Orice altceva a trecut prin API.
Aceasta este arhitectura. API-first, SSH ca ultima resursa, chei efemere cand SSH este necesar si un AGENTS.md commitat care da fiecarei sesiuni viitoare contextul de care are nevoie pentru a actiona fara a intreba. Serverul ramane curat. Agentul ramane auditabil. Iar deploy-ul care a esuat la prima rulare este patch-uit si ruleaza in productie, in intregime de un agent care nu a detinut niciodata o credentiala persistenta.