KiroCrew su VPS: agente sempre attivo con Docker
Esegui KiroCrew in un container bloccato sul tuo VPS: memoria e job sopravvivono ai riavvii, con Docker, systemd, SSH, backup e rollback.
Perché eseguire KiroCrew in self-hosting su un VPS invece che su un laptop
Il self-hosting di KiroCrew è utile soltanto su una macchina che non va mai in sospensione. Per questo un VPS è la scelta corretta, mentre un laptop non lo è. KiroCrew conserva su disco la cronologia delle sessioni, la memoria semantica, i job pianificati e la coda delle approvazioni. Ricarica tutti questi dati quando il processo viene riavviato. Nulla di tutto questo è utile se il processo non è in esecuzione alle 03:00, quando deve essere eseguito un job pianificato. Un laptop chiuso non esegue il processo.
KiroCrew è un workspace open source per agenti sviluppato dal team Kiro e distribuito con licenza Apache 2.0. Le prime release pubbliche sono state rese disponibili all'inizio di agosto 2026. Un unico processo, chiamato gateway, gestisce lo stato e pubblica una dashboard web sulla porta 5476. Puoi raggiungere il gateway dalla dashboard, dalla CLI kirocrew oppure da un canale di chat come Slack. Il gateway è l'unico componente che esegui in self-hosting. Questa guida spiega quindi come mantenerlo in esecuzione, come impedirne l'esposizione a Internet e come ripristinarlo dopo un aggiornamento problematico.
Prima di iniziare, devi sapere due cose. KiroCrew utilizza kiro-cli, che richiede un accesso iniziale con un account Kiro. L'inferenza dell'agente viene addebitata su un piano Kiro. Pertanto, ad agosto 2026, questa non è una configurazione offline. Il progetto ha inoltre soltanto poche settimane di vita. Considera quindi probabile la necessità di eseguire un rollback e installalo in modo da poterlo fare. Se non hai mai eseguito un agente su un server, eseguire un agente di programmazione su un VPS illustra le regole di base su cui si fonda questa guida. Se hai più esperienza con il lato server che con quello degli agenti, leggi prima capire che cosa sono realmente un loop dell'agente, i suoi strumenti e la sua memoria. Le scelte descritte di seguito saranno così più facili da comprendere come decisioni tecniche, anziché come comandi da eseguire meccanicamente.
Di cosa ha bisogno KiroCrew e dove risiede il suo stato
Un'installazione nativa richiede Python 3.10 o versione successiva (il progetto consiglia la 3.12), Node.js 18 o versione successiva se si compila la dashboard dal codice sorgente e kiro-cli, che viene installato e configura l'accesso al primo avvio. L'installazione tramite container non richiede nulla di tutto questo sull'host. Richiede Docker. Questo è il motivo principale per preferirla.
Lo stato risiede in ~/.kiro/crew e la variabile d'ambiente KIROCREW_HOME consente di spostarlo altrove. Il contenuto include:
config.json: impostazioni del gateway e credenziali dei canali di chat..env: secret.workspace/memory/: preferenze, note di progetto e cronologia delle chat.memory.dbememory_index.db: gli indici semantico e full-text.models/: il modello di embedding, scaricato al primo avvio.gateway.logesecurity_events.jsonl: il log di runtime e il log degli eventi di sicurezza.
Quella directory è l'installazione. Copiala su un nuovo VPS per spostare l'agente. Per questo la sezione sul backup riportata sotto è più importante di quella sull'installazione.
Pianifica lo spazio su disco, non la RAM. Il gateway è un processo Python; ciò che carica effettivamente il sistema è quello che esegue l'agente, ad esempio una build o una suite di test. La directory dello stato cresce con la cronologia delle chat e il modello di embedding viene scaricato al primo avvio. Dopo alcune settimane, misurala sul tuo sistema con du -sh ~/.kiro/crew invece di affidarti a qualsiasi valore pubblicato nel primo mese di un progetto. Il confronto è con un runtime che assegna a ogni worker un container e un browser dedicati: in self-hosting dei colleghi AI di OpenBot, il dimensionamento diventa prima una questione di RAM e poi di spazio su disco.
Quale dei tre metodi di installazione usare
Il progetto ne pubblica tre. L'installer in una riga scarica un wheel e aggiunge kirocrew al PATH:
curl -fsSL https://download.crew.kiro.dev/cli.sh | shAccetta un flag per il canale e uno per la versione:
curl -fsSL https://download.crew.kiro.dev/cli.sh | sh -s -- --channel insider
curl -fsSL https://download.crew.kiro.dev/cli.sh | sh -s -- --version 0.1.3L'immagine del container è pubblicata su ghcr.io/kirodotdev/kirocrew, per linux/amd64 e linux/arm64 in ogni tag. La build dal codice sorgente richiede git clone e make build ed è destinata a chi modifica il codice, non a chi esegue il software.
Usa il container. Un'installazione nativa colloca i pacchetti Python, Node e kiro-cli sullo stesso host che esegue gli altri servizi. Se un aggiornamento non va a buon fine, devi quindi risolvere manualmente le conseguenze. Il container mantiene il runtime in un'unica immagine e lo stato in un unico volume. Un rollback richiede così soltanto la modifica del tag e un riavvio.
Fissa l’immagine a un tag di release, non a stable
L’esempio del progetto usa il tag stable:
docker run -d --name kirocrew \
-p 127.0.0.1:5476:5476 \
-v kirocrew-home:/home/kirocrew \
ghcr.io/kirodotdev/kirocrew:stablestable è un tag mobile. Punta alla release stabile più recente disponibile, quindi il pull successivo può modificare la versione in esecuzione senza una scelta esplicita da parte tua. Inoltre, il tag non registra quale versione fosse stata utilizzata. I tag di versione sono immutabili, quindi fissane uno. La release più recente al 6 agosto 2026 è 0.1.3, pubblicata il 5 agosto 2026. Esiste anche il tag nightly, che in un progetto così giovane indica che il codice è cambiato questa mattina.
Scrivi /opt/kirocrew/compose.yaml:
services:
kirocrew:
image: ghcr.io/kirodotdev/kirocrew:0.1.3
container_name: kirocrew
restart: unless-stopped
ports:
- "127.0.0.1:5476:5476"
volumes:
- kirocrew-home:/home/kirocrew
volumes:
kirocrew-home:Avvialo, quindi controlla l'endpoint di health check che l'immagine usa anche per il proprio HEALTHCHECK:
cd /opt/kirocrew
docker compose up -d
docker compose ps
curl -s http://127.0.0.1:5476/api/healthdocker compose ps dovrebbe segnalare il container come integro entro circa un minuto e /api/health risponde senza token, così come /api/live e /api/ready. Per questo possono essere utilizzati come probe. Se lo stato resta starting, leggi docker logs kirocrew prima di modificare qualsiasi cosa. Il primo avvio scarica il modello di embedding, quindi una connessione lenta può rendere lungo il primo avvio.
Mantienilo in esecuzione con systemd
restart: unless-stopped riavvia il container dopo un arresto anomalo e dopo un riavvio, purché Docker stesso venga avviato al boot. Un file unit rende esplicita questa dipendenza e fornisce un unico comando per arrestare l'intero stack prima di un backup. Avviare uno stack Docker Compose al boot descrive il modello generale. Per KiroCrew, la configurazione è questa, in /etc/systemd/system/kirocrew.service:
[Unit]
Description=KiroCrew gateway
Requires=docker.service
After=docker.service
[Service]
Type=oneshot
RemainAfterExit=yes
WorkingDirectory=/opt/kirocrew
ExecStart=/usr/bin/docker compose up -d
ExecStop=/usr/bin/docker compose down
TimeoutStartSec=0
[Install]
WantedBy=multi-user.targetsudo systemctl daemon-reload
sudo systemctl enable --now kirocrew
systemctl status kirocrewsystemctl status kirocrew dovrebbe restituire active (exited), che è il risultato corretto per questa unit. Type=oneshot con RemainAfterExit=yes è corretto in questo caso perché docker compose up -d restituisce il controllo non appena il container viene avviato: systemd tiene traccia del fatto che lo stack è attivo, non di un processo in primo piano. Scrivi invece Type=simple: systemd rileva che il comando termina immediatamente, contrassegna il servizio come terminato e poi rinuncia oppure entra in un ciclo di riavvii, a seconda dell'impostazione Restart=. Per un'installazione nativa, il progetto fornisce l'equivalente, kirocrew service install, che scrive /etc/systemd/system/kirocrew.service ed esegue il gateway con il tuo utente. Non eseguire entrambe le unit. La trattazione più ampia dell'argomento è disponibile in Servizi e timer systemd su un VPS. Un'unit che non torna attiva dopo un riavvio rimane silenziosa finché non la configuri per segnalare l'errore: aggiungi un gestore OnFailure= che invia un avviso al tuo server ntfy e saprai dal telefono che il gateway è inattivo, invece di scoprirlo tramite un job pianificato che non è mai stato eseguito.
Prima esecuzione: accedi e ottieni un token per la dashboard
Il container avvia il gateway, ma il runtime dell'agent non ha ancora effettuato l'accesso. Accedi all'interno del container:
docker exec -it kirocrew kiro-cli loginVengono visualizzati un codice dispositivo e un URL da aprire nel tuo browser. Genera quindi un token per la dashboard:
docker exec kirocrew kirocrew token --ttl 2hL'URL della dashboard è http://localhost:5476/?token=<the token>. I token scadono: per impostazione predefinita, le sessioni durano un'ora e il limite massimo documentato è di venti ore. Se la dashboard viene caricata vuota oppure ti riporta immediatamente alla schermata di accesso, la causa è in genere un token scaduto; generane un altro. Non incollare mai un token in un ticket o in un messaggio di chat, perché chiunque ne sia in possesso può controllare il tuo agent.
Accedere al dashboard tramite SSH senza pubblicare la porta 5476
Osservate di nuovo l'indirizzo di bind nell'esempio del progetto: -p 127.0.0.1:5476:5476. All'interno del container, il gateway è in ascolto su 0.0.0.0, perché deve essere raggiungibile tramite il port mapping; tuttavia, il mapping pubblica la porta soltanto sull'interfaccia loopback dell'host. Eliminate il prefisso 127.0.0.1: e il gateway sarà esposto su Internet a chiunque esegua una scansione di quella porta. Neppure una regola del firewall è sufficiente: Docker pubblica le porte scrivendo regole DNAT che vengono valutate prima del filtraggio di ufw, quindi ufw deny 5476 non ha effetto su una porta pubblicata. Le porte Docker ignorano ufw descrive questo meccanismo.
Inoltrate invece la porta tramite SSH dal laptop:
ssh -N -L 5476:127.0.0.1:5476 you@your-server.example.comLasciate il comando in esecuzione e aprite localmente http://localhost:5476/?token=<the token>. Per rendere automatico il forwarding a ogni connessione, inseritelo in ~/.ssh/config:
Host your-server.example.com
LocalForward 5476 127.0.0.1:5476Se la porta 5476 è già in uso sul laptop, modificate soltanto il numero a sinistra: ssh -N -L 45476:127.0.0.1:5476 you@your-server.example.com, quindi aprite http://localhost:45476/?token=... nel browser. Non appena un secondo agent condividerà il server, userete più forwarding di questo tipo, perché self-hosting di open-kritt per la scansione di sicurezza aggiunge sullo stesso server un altro dashboard accessibile soltanto tramite loopback, sulla porta 5173.
È previsto un comportamento specifico quando si usa un tunnel: il gateway considera remote le richieste inoltrate, quindi gli endpoint del dashboard per scrivere la configurazione e rivelare i secret le rifiutano. Se una modifica delle impostazioni non viene salvata tramite SSH, il comportamento è previsto e non indica un bug. Modificate invece la configurazione direttamente sull'host:
docker cp kirocrew:/home/kirocrew/.kiro/crew/config.json .
# edit config.json here
docker cp config.json kirocrew:/home/kirocrew/.kiro/crew/config.json
docker exec -u 0 kirocrew chown kirocrew:kirocrew /home/kirocrew/.kiro/crew/config.json
docker restart kirocrewPer l’accesso da telefono, il progetto indica tailscale serve di Tailscale, che mantiene la dashboard all’interno del proprio tailnet invece di pubblicarla su un hostname pubblico. È preferibile rispetto a un reverse proxy pubblico. Il token viene trasmesso nell’URL e l’URL viene scritto in ogni log degli accessi attraversato dalla richiesta. Questa regola riguarda ciò che si trova dietro la porta, non la porta in sé: qualcosa come Halcyon, che ricostruisce una libreria Jellyfin come videoteca degli anni ’90 consultabile è destinato all’accesso di altre persone ed è quindi un candidato appropriato per un reverse proxy, mentre un gateway in grado di eseguire comandi sul server non lo è.
Assegna all'agente il perimetro di impatto più ridotto possibile
Al primo avvio, il container verifica il supporto della sandbox. Il risultato determina se gli agenti possono eseguire operazioni. Se l'isolamento tramite namespace è disponibile, i processi secondari dell'agente vengono eseguiti in isolamento. Se non è disponibile e KIROCREW_ALLOW_UNSANDBOXED=1 non è impostato, l'esecuzione viene rifiutata invece di procedere senza isolamento. Per questo, quando il gateway risulta operativo ma ogni attività rimane bloccata, questa è di solito la causa. La decisione viene registrata in docker logs kirocrew durante la prima esecuzione. Il progetto pubblica anche un profilo seccomp (secure computing mode) che puoi applicare:
curl -fsSL https://raw.githubusercontent.com/kirodotdev/KiroCrew/main/docker/seccomp/kirocrew-seccomp.json \
-o /opt/kirocrew/kirocrew-seccomp.json security_opt:
- seccomp:./kirocrew-seccomp.jsonSe imposti KIROCREW_ALLOW_UNSANDBOXED=1, chiarisci cosa cambia: il container diventa l'unico confine tra l'agente e il server. È importante ripetere integralmente l'avviso del progetto. Non montare percorsi dell'host che non consegneresti direttamente all'agente. In pratica, questo esclude il socket Docker, qualsiasi bind mount di / e qualsiasi directory che contenga i dati di un altro servizio.
Il resto costituisce il perimetro da applicare a ogni agente autorizzato a eseguire comandi. Limita le sue credenziali al singolo repository o al singolo bucket di cui ha bisogno. Non usare mai un token personale con autorizzazioni sull'intero account. Eseguilo con un utente dedicato la cui home non contenga altro: è questo lo scopo di utenti con privilegi minimi su un VPS. Quando l'agente scrive codice e poi lo esegue, assegnagli una macchina che possa danneggiare: una VM temporanea per gli agenti di coding offre un confine più solido di qualsiasi flag in questo file compose, perché puoi eliminarla invece di ripulirla. Lo stesso principio si applica a eseguire OpenClaw in sicurezza su un VPS e a ospitare autonomamente l'agente Hermes su un VPS. Anche gli strumenti contribuiscono al perimetro di impatto: concedere all'agente l'accesso alla ricerca web trasforma ogni pagina recuperata in un input non attendibile. Per questo, indirizzarlo alla propria istanza SearXNG è una decisione che riguarda la prompt injection tanto quanto la configurazione dei collegamenti. Anche le attività pianificate comportano costi mentre dormi, perché l'inferenza viene addebitata al tuo piano Kiro. Imposta quindi i limiti descritti in controllare i costi di un agente AI su un VPS prima di aggiungere un'attività notturna.
Eseguire il backup del volume di stato prima di ogni aggiornamento
Prima individuare il nome effettivo del volume. Compose antepone ai volumi denominati il nome del progetto, che per impostazione predefinita corrisponde al nome della directory. Di conseguenza, il volume dichiarato come kirocrew-home in /opt/kirocrew/compose.yaml viene creato come kirocrew_kirocrew-home:
docker volume lsArrestare il gateway prima di copiare qualsiasi file. memory.db e memory_index.db sono database SQLite. Copiare un database mentre è in corso una scrittura può acquisire una transazione incompleta, che durante il ripristino produce un file danneggiato. Anche le istruzioni di migrazione del progetto indicano la stessa procedura: spostare la memoria solo quando i gateway sono arrestati. Questa regola di arrestare prima il servizio non è specifica di KiroCrew. Se sullo stesso host è presente un server fotografico, il confronto tra PhotoPrism e Immich riporta i comandi di backup esatti richiesti da ciascuno dei due.
sudo systemctl stop kirocrew
docker run --rm -v kirocrew_kirocrew-home:/data:ro -v "$PWD":/backup \
alpine tar czf /backup/kirocrew-2026-08-06.tgz -C /data .
sudo systemctl start kirocrewCopiare l'archivio fuori dall'host. Il ripristino usa lo stesso comando, con il container arrestato e tar xzf al posto di tar czf:
sudo systemctl stop kirocrew
docker run --rm -v kirocrew_kirocrew-home:/data -v "$PWD":/backup \
alpine tar xzf /backup/kirocrew-2026-08-06.tgz -C /data
sudo systemctl start kirocrewLa migrazione a un nuovo host è un'operazione diversa dal ripristino sullo stesso host, e il progetto fornisce indicazioni specifiche. La cronologia delle chat e le note dei progetti in workspace/memory/ vengono trasferite, così come i due file di database e config.json. I file PID, il log degli eventi di sicurezza e .env sono associati al vecchio host. Non trasferirli e inserire nuovamente i secret sul nuovo host.
Come eseguire il rollback dopo un aggiornamento problematico
L'aggiornamento è rapido ed è sicuro soltanto perché hai bloccato una versione. Crea prima il backup, quindi modifica il tag:
sudo systemctl stop kirocrew
# take the backup here, as above
sudo nano /opt/kirocrew/compose.yaml # set the new image tag
sudo systemctl start kirocrew
docker compose -f /opt/kirocrew/compose.yaml ps
curl -s http://127.0.0.1:5476/api/healthdocker compose up -d scarica l'immagine se non è già presente sul server, quindi la modifica del tag costituisce l'intero aggiornamento. Il rollback segue la stessa procedura, usando il numero della versione precedente, e ripristina esattamente l'immagine che avevi prima, perché i tag delle versioni sono immutabili.
Il binario può essere riportato alla versione precedente senza problemi. Lo stato, invece, potrebbe non essere compatibile. Un gateway più recente può riscrivere config.json oppure migrare i database in memoria in un formato che un gateway precedente non sa leggere; ad agosto 2026 non è documentata alcuna procedura di downgrade. Se quindi l'immagine precedente si avvia ma poi presenta comportamenti anomali, non eseguire il troubleshooting. Arrestala, ripristina il backup creato prima dell'aggiornamento e riavvia il servizio. Questo è il motivo per cui il backup va creato prima dell'aggiornamento e per cui, in un progetto ancora così recente, l'abitudine di aggiornare subito e creare il backup in seguito non è affidabile.
Cosa non è dimostrato in questa sede
Siate consapevoli dell'età di questo software. La versione 0.1.3 ha solo pochi giorni al momento della stesura, le relative note di rilascio sono collegamenti automatici al changelog anziché note di migrazione e non esiste ancora uno storico degli aggiornamenti. Nulla in questa guida è un risultato osservato nel lungo periodo. Considerate quindi la crescita della memoria, le dimensioni del database e l'affidabilità dello scheduler come aspetti da misurare sul vostro server, non come valori da dare per scontati.
Prima di fare affidamento su due comportamenti, è opportuno verificarli direttamente. Per prima cosa, controllate se un downgrade è in grado di leggere lo stato scritto da una versione più recente. Eseguite la prova su una copia del volume, quando un eventuale problema non ha conseguenze, e non durante un'interruzione del servizio. Verificate poi cosa fa il gateway quando l'accesso a Kiro scade mentre è prevista l'esecuzione di un job pianificato. Entrambi sono esempi di problemi iniziali che un progetto giovane può risolvere senza particolare evidenza tra una release e l'altra. In entrambi i casi, la verifica è semplice e può essere eseguita subito.
FAQ
Perché il dashboard di KiroCrew non si apre sull'IP pubblico del mio server?
Perché l'esempio pubblicato associa la porta all'interfaccia di loopback. -p 127.0.0.1:5476:5476 associa la porta del container soltanto all'indirizzo di loopback dell'host, intenzionalmente. Raggiungila inoltrando la porta tramite SSH con ssh -N -L 5476:127.0.0.1:5476 you@your-server, quindi apri http://localhost:5476/?token=<token> sul laptop. Rimuovere il prefisso 127.0.0.1: per renderla raggiungibile espone il gateway su Internet e una regola del firewall non è sufficiente a contenerlo, perché le regole DNAT delle porte pubblicate da Docker vengono valutate prima che ufw filtri il traffico.
Dove archivia KiroCrew i dati e di cosa devo eseguire il backup?
Tutto si trova in ~/.kiro/crew, che nell'immagine del container corrisponde a /home/kirocrew/.kiro/crew, e KIROCREW_HOME lo sposta. Esegui il backup dell'intera directory o dell'intero volume Docker, con il gateway arrestato. memory.db e memory_index.db sono database SQLite, quindi una copia eseguita mentre il gateway scrive può risultare incoerente. Quando esegui la migrazione su un nuovo host, workspace/memory/, i due file di database e config.json vengono trasferiti, mentre i file PID, il log degli eventi di sicurezza e .env appartengono al vecchio host.
Devo usare il tag stable o un tag di versione?
Usa un tag di versione. stable cambia ogni volta che viene rilasciata una nuova versione, quindi la versione in esecuzione può cambiare al pull successivo e il tag, da solo, non indica quale versione è in esecuzione. I tag di versione come 0.1.3 sono immutabili. Questo è ciò che rende possibile un rollback: ripristini il numero precedente e ottieni la stessa immagine. Al 6 agosto 2026, la versione più recente è 0.1.3.
Perché il mio agent rifiuta di eseguire qualsiasi comando?
Il container verifica il supporto per il sandboxing al primo avvio. Se non riesce a isolare i sottoprocessi dell'agent e KIROCREW_ALLOW_UNSANDBOXED=1 non è impostato, rifiuta di eseguirli invece di avviarli senza isolamento. Di conseguenza, il gateway risulta operativo mentre ogni attività resta bloccata. docker logs kirocrew mostra la decisione relativa al sandboxing presa durante quella prima esecuzione. Impostare la variabile rende il container l'unico confine tra l'agent e l'host. Pertanto, se la imposti, non montare nulla che non consegneresti direttamente all'agent.
Serve un account Kiro per eseguire il self-hosting di KiroCrew?
Sì, ad agosto 2026. KiroCrew è software libero distribuito con licenza Apache 2.0, ma utilizza kiro-cli, che richiede un accesso una tantum, e l'inferenza dell'agent viene addebitata a un piano Kiro. Nel container, esegui docker exec -it kirocrew kiro-cli login e approva il codice del dispositivo nel browser. Fino al completamento dell'accesso, il gateway si avvia e il dashboard viene caricato, ma l'agent non dispone di alcun modello con cui interagire.