SSD Nodes Learn Hosting plans →
Guide Matt ConnorDi Matt Connor · Aggiornato 2026-08-28

OpenBot self-hosted su VPS: coworker AI in container

Scopri come OpenBot assegna a ogni coworker AI un container e un browser Chromium, come il gateway verifica ogni azione e quanta RAM richiede il setup.

Cosa ottieni quando esegui il self-hosting di coworker AI OpenBot

Esegui il self-hosting dei coworker AI OpenBot avviando un server gateway e un container per ogni bot sull’hardware sotto il tuo controllo. Ogni container del bot include il proprio browser Chromium e il proprio volume di workspace, con un profilo del browser persistente tra una sessione e l’altra. Ogni azione eseguita da un bot su un computer, un file, un server MCP (model context protocol) o un componente dell’interfaccia passa attraverso quel gateway, che la verifica rispetto a una policy prima dell’esecuzione e la registra dopo. Se il ciclo dell’agente gestito dal gateway non ti è ancora familiare, il percorso graduale in imparare gli agenti AI da zero ti fa scrivere prima un piccolo agente, prima di affidare a un bot un browser e le tue credenziali di accesso.

OpenBot è pubblicato da CopilotKit con licenza MIT all’indirizzo github.com/CopilotKit/openbot. La prima release contrassegnata, v0.0.1, è stata pubblicata il 17 agosto 2026 e il progetto si descrive come alpha e in sviluppo attivo. Consideralo un progetto con un’architettura seria, ma ancora caratterizzato dai limiti tipici di una fase iniziale.

L’aspetto più interessante di questa architettura è anche quello più costoso. Un browser per ogni agente rappresenta il costo in memoria che più spesso viene trascurato nella pianificazione, quindi qui il dimensionamento viene prima dell’installazione.

Come il gateway decide ogni azione

Il server API sulla porta 3001 è l'unico percorso verso il computer di un bot. Prima di eseguire un'azione nel browser, il gateway risolve la destinazione a partire da uno snapshot della pagina, valuta le regole di policy CEL (Common Expression Language) rispetto al contesto, scrive una riga di audit con la decisione e solo dopo chiama il container. Se l'esecuzione non riesce, scrive una seconda riga. La documentazione definisce chiaramente il confine: il computer non decide la policy; il gateway del server è il confine delle azioni. Questa separazione ha un nome al di fuori di OpenBot, perché il ciclo, le definizioni degli strumenti, i controlli delle autorizzazioni e lo stato della sessione costituiscono insieme l'harness che avvolge un modello, mentre questo gateway ne rappresenta la componente di autorizzazione.

La policy applica il deny-by-default e le regole di deny vengono valutate prima di quelle di allow. La direzione del fallimento è più importante della sintassi delle regole. Una policy mancante non autorizza nulla e una regola non valida fallisce bloccando l'azione, sia che si tratti di una regola di deny sia di una regola di allow. Un errore nella policy quindi lascia il bot bloccato, invece di lasciarlo libero di agire sui tuoi account. Questo livello controlla ciò che fa un bot, non ciò che legge. Una pagina che contiene istruzioni rivolte all'agente resta quindi un problema distinto. È la stessa superficie di prompt injection che accetti quando fornisci a un agente i risultati della tua istanza SearXNG.

La traccia di audit risiede in PostgreSQL, quindi sopravvive a un riavvio. I passaggi del controllo vengono registrati come computer.help_requested, computer.control_taken e computer.control_released. In questo modo puoi vedere quando un bot chiede l'intervento di una persona e quando la persona restituisce il controllo. I secret vengono registrati come conteggi dei caratteri, mai come valori. Le operazioni sui file registrano il percorso e la dimensione, mai il contenuto. Se vuoi lo stesso confine di controllo senza un browser, controllare le azioni degli agenti AI tramite approvazioni tratta questo caso più specifico.

Quanto consumano un Bot in termini di RAM e disco

Il progetto pubblica valori misurati per un singolo Bot su arm64. Sono gli unici dati di dimensionamento forniti da OpenBot e descrivono un solo bot su una sola architettura. Usali quindi come punto di partenza, non come piano di capacità.

ChartOpenBot published resource figures, one Bot on arm64 (August 2026)
The data behind this chart
[
  {
    "label": "Measured, one Bot",
    "memory_gb": 0.55,
    "disk_gb": 5.3,
    "vcpu": 0.06
  },
  {
    "label": "Documented minimum",
    "memory_gb": 2,
    "disk_gb": 8,
    "vcpu": 1
  },
  {
    "label": "Documented recommended",
    "memory_gb": 4,
    "disk_gb": 10,
    "vcpu": 2
  }
]

La memoria di picco misurata è di 0.55 GB per un Bot. Il minimo documentato è 2 GB, mentre la raccomandazione è di 4 GB. La differenza tra il valore misurato e il minimo lascia margine alla crescita di Chromium sotto carico, perché il consumo di memoria di un browser dipende dalle pagine aperte e non dal processo a riposo. Il consumo CPU in idle è quasi nullo: raggiunge 0.06 di un core all'estremità superiore dell'intervallo misurato. La CPU, quindi, non è la risorsa principale da acquistare. Lo è il disco. La sola immagine occupa 5.3 GB, a fronte di un volume consigliato di 10 GB. Le sue dimensioni dipendono dal fatto che include i binari di Firefox e WebKit di Playwright oltre a Chromium.

Questi dati non indicano quanto costino complessivamente più bot e il progetto non pubblica alcun valore al riguardo. Un minimo documentato è il valore che un progetto ritiene accettabile pubblicare, non necessariamente quello osservato sotto carico. Per questo la scelta tra PhotoPrism e Immich dipende dai rispettivi valori minimi di RAM misurati, non da quelli pubblicati. Misura il tuo ambiente. Avvia un bot, assegnagli un'attività reale con una pagina aperta e monitora il container mentre lavora.

docker stats --no-stream
free -m

Usa la colonna MEM USAGE del container del bot come valore per singolo bot. Aggiungi il gateway e PostgreSQL, quindi moltiplica il valore per bot per il numero di bot che prevedi di avere contemporaneamente. Anche un bot inattivo mantiene un processo del browser, quindi il moltiplicatore si applica ai bot presenti, non soltanto a quelli occupati. Il calcolo è lo stesso usato per dimensionare RAM e CPU di una VPS per un coding agent e la parte relativa al browser è trattata in eseguire un browser headless per agent su una VPS.

Un dettaglio di Chromium incide sui piani di piccole dimensioni. OpenBot avvia Chromium con --disable-dev-shm-usage, quindi il browser scrive in /tmp invece che in /dev/shm. In questo modo evita il crash che si verifica su host con un /dev/shm di dimensioni ridotte e trasferisce la pressione sul filesystem root. Questo è un ulteriore motivo per cui il disco consigliato è più grande dell'immagine.

Come eseguire OpenBot in modalità self-hosted su un VPS?

Servono Docker, Bun 1.3 o versione successiva, un progetto CopilotKit Intelligence e una chiave API del modello. La documentazione per lo sviluppo richiede inoltre lsof, python3 e curl sul server. Clonate una release contrassegnata invece di main, perché main in un progetto alpha cambia senza preavviso.

git clone --branch v0.0.1 https://github.com/CopilotKit/openbot.git
cd openbot
cp .env.example .env

Provisionate il progetto Intelligence. Questi tre comandi scrivono la chiave di runtime e il token di licenza nel file di ambiente.

npx --yes copilotkit@latest login
npx --yes copilotkit@latest project select
npx --yes copilotkit@latest license --write

Generate la chiave che cifra le credenziali archiviate e inserite l'output in .env come KEY_ENCRYPTION_KEY. Aggiungete OPENAI_API_KEY nello stesso file oppure impostate BOT_PROVIDER su anthropic o google con la chiave corrispondente.

openssl rand -base64 32

Installate e avviate quindi i servizi.

bun install
bash scripts/start.sh

scripts/start.sh avvia i servizi Docker, esegue le migrazioni del database, avvia il server e l'applicazione e ne verifica lo stato. Al termine, l'applicazione risponde sulla porta 3010 e l'API sulla porta 3001. Lo script segnala i conflitti sulle porte e lascia invariato un servizio corrispondente già in esecuzione, quindi può essere eseguito due volte senza rischi.

Verificatene il funzionamento direttamente dal server prima di esporre qualsiasi servizio.

curl -sS -o /dev/null -w '%{http_code}\n' http://127.0.0.1:3010
ss -ltnp | grep -E ':(3010|3001|4100|4500|5432)'

Un 200 restituito dal primo comando indica che l'applicazione sta rispondendo. Il secondo comando mostra gli indirizzi su cui sono associate quelle porte: è questo il dato rilevante su un VPS. Una riga con 127.0.0.1:3001 indica che la porta è accessibile soltanto dal server. Una riga con 0.0.0.0:3001 indica che può raggiungerla chiunque disponga di un percorso di rete verso il server.

L'immagine container singola

La documentazione di distribuzione include anche una singola immagine che contiene l'applicazione, l'API e Chromium, esposti sulla porta 3001.

docker build -t openbot .
docker run -p 127.0.0.1:3001:3001 --env-file .env \
  -e EMBEDDED_POSTGRES=on -v openbot-data:/var/lib/postgresql/data openbot

EMBEDDED_POSTGRES=on esegue PostgreSQL all'interno del container e applica le migrazioni all'avvio. Il volume denominato conserva la cronologia degli audit tra una nuova distribuzione e l'altra; senza di esso, ogni ricostruzione elimina la cronologia. Se invece si configura DATABASE_URL per usare un database gestito, è necessario abilitare su quel database l'estensione vector. Servizi gestiti come RDS, Cloud SQL e Azure Database supportano l'estensione, ma nessuno la abilita automaticamente. Di conseguenza, una migrazione su un database gestito appena creato non riesce perché il tipo di colonna vector non esiste ancora.

Eseguire le migrazioni come fase di rilascio quando il database è esterno.

docker run --rm --env-file .env openbot \
  sh -c "cd /app/server && bun x drizzle-kit migrate --config=drizzle.config.ts"

Quell'immagine non pubblica intenzionalmente la porta del browser. Inoltre non include il supervisor, perché il supervisor richiede il socket Docker, che le piattaforme serverless non forniscono. Senza il supervisor, tutti i bot condividono un browser e quindi lo stesso insieme di credenziali. Questo elimina l'isolamento che rendeva utile eseguire container separati per ogni bot. Se il motivo per cui si sta leggendo questa sezione è usare credenziali separate per ogni bot, eseguire lo stack Compose con COMPUTER_SUPERVISOR_URL e SUPERVISOR_TOKEN impostati, su un host sul quale si accetta questo compromesso. Un processo che può comunicare con il socket Docker può avviare un container con privilegi elevati. In pratica, dispone quindi dei privilegi di root sull'host. Per questo è consigliabile mantenere OpenBot su una macchina dedicata, in linea con il principio di fornire agli agenti di programmazione una VM usa e getta.

Perché OPENBOT_SINGLE_USER è un'impostazione per laptop

.env.example viene distribuito con OPENBOT_SINGLE_USER=true. Questa impostazione considera ogni richiesta come proveniente da un unico amministratore e salta completamente l'accesso. Su un laptop è una comodità, perché l'unico client che può raggiungere la porta sei tu. Su un VPS significa che la prima persona che raggiunge la porta 3010 diventa amministratore di un sistema che memorizza credenziali crittografate e controlla un browser già autenticato ai tuoi account.

Esistono due modalità corrette per eseguirlo. Mantieni OPENBOT_SINGLE_USER=true, associa ogni porta a 127.0.0.1 e accedi all'app solo tramite un tunnel SSH o un'interfaccia di rete privata.

ssh -N -L 3010:127.0.0.1:3010 -L 3001:127.0.0.1:3001 you@your-vps

L'app è quindi disponibile all'indirizzo http://localhost:3010 nel tuo browser, che viene considerato un contesto sicuro. In questo modo funzionano sia i cookie di accesso sia le funzionalità del browser necessarie per la schermata interattiva. L'altra possibilità consiste nel disattivare la modalità a utente singolo e configurare un provider di identità reale. Sono supportati Google, Microsoft Entra, Okta, SAML e OIDC. Qualsiasi provider richiede inoltre BETTER_AUTH_SECRET con almeno 32 caratteri, BETTER_AUTH_URL impostato sull'URL di base pubblico dell'API per i callback OAuth, INITIAL_ADMIN_EMAILS e TRUSTED_ORIGINS. Le credenziali del provider devono essere complete, perché un provider configurato solo parzialmente interrompe l'avvio invece di tornare all'accesso aperto. Se aggiungi account perché ogni persona del team vuole un proprio agente invece di un proprio browser, OneCLI è progettato fin dall'inizio per questo modello, con un agente in sandbox per ogni persona e le chiavi dei modelli gestite in un unico gateway.

Se l'app è raggiungibile tramite un nome pubblico, configura TLS (transport layer security) davanti all'applicazione. Una pagina servita tramite http:// su qualsiasi host diverso da localhost non è un contesto sicuro. Di conseguenza, i cookie contrassegnati con Secure non vengono memorizzati e l'accesso non riesce in un modo che può sembrare un bug di OpenBot.

Proteggere con il firewall le porte dei livelli inferiori

La nota di sicurezza di OpenBot specifica che gli endpoint dei servizi dei livelli inferiori sono protetti da token, che devono restare privati e che non devono essere usati per aggirare il gateway. I token costituiscono la seconda protezione. La prima consiste nel fatto che la porta non deve essere raggiungibile in alcun modo.

L'agent-computer è in ascolto sulla porta 4100 e richiede COMPUTER_TOKEN. Gli endpoint del bot sono in ascolto sulle porte 4200 e 4201. Il supervisor è in ascolto sulla porta 4500 dell'host e sulla porta 4300 all'interno del relativo container. PostgreSQL è in ascolto sulla porta 5432. Nessuna di queste porte deve essere esposta su un'interfaccia pubblica; in una distribuzione per singolo utente non devono esserlo neppure l'applicazione e l'API.

sudo ufw default deny incoming
sudo ufw default allow outgoing
sudo ufw allow 22/tcp
sudo ufw enable
sudo ufw status verbose

Esiste un'insidia che può sorprendere chi presume che il firewall sia sufficiente. La pubblicazione di una porta del container con -p 3001:3001 induce Docker a installare una regola DNAT, quindi il traffico viene gestito nel percorso FORWARD e non attraversa mai la catena INPUT, sulla quale si applica il deny predefinito di ufw. La porta resta aperta anche se ufw status continua a mostrare Status: active. Associa la porta pubblicata all'interfaccia di loopback direttamente nella mappatura, come in -p 127.0.0.1:3001:3001, oppure imposta l'indirizzo dell'host nel file compose. Verifica con ss -ltnp, non con ufw status. Questa insidia non è specifica di OpenBot, quindi esegui lo stesso controllo su ogni altro container che hai pubblicato sul server, incluso quello che fornisce una libreria Jellyfin ricostruita come videoteca degli anni '90'.

OpenBot non è uno stack offline

Definiscilo prima di pianificare il deployment. OpenBot dipende da un progetto CopilotKit Intelligence, che conserva thread persistenti e memoria delle conversazioni al di fuori del tuo server. All'avvio, il server convalida INTELLIGENCE_API_URL, INTELLIGENCE_GATEWAY_WS_URL, INTELLIGENCE_API_KEY e COPILOTKIT_LICENSE_TOKEN; tutti e quattro devono essere presenti insieme, altrimenti l'avvio non riesce. Ad agosto 2026 è disponibile un piano gratuito. Intelligence può inoltre essere eseguito sul proprio hardware, quindi è possibile realizzare un deployment completamente locale, ma con un lavoro maggiore rispetto a quanto indicato dal quickstart.

Il modello è la seconda dipendenza esterna. Nel pacchetto non è incluso alcun modello. BOT_PROVIDER accetta openai, anthropic o google. OPENAI_BASE_URL indirizza il percorso OpenAI verso qualsiasi endpoint compatibile. In questo modo puoi eseguire Ollama su un VPS per eseguire autonomamente un LLM e mantenere i token sul tuo hardware. Il controllo del browser richiede molto a un modello, quindi prova un modello locale con un'attività reale prima di adottarlo.

Esegui una sola replica, per ora

Il gateway memorizza le istantanee delle pagine nella memoria del processo server. Con due repliche, un’istantanea acquisita da un processo non è visibile all’altro. Di conseguenza, le azioni falliscono in modo intermittente con errori element-not-found che sembrano casuali. La documentazione di deployment è chiara: esegui una sola replica e imposta a 1 il numero massimo di istanze della piattaforma. Questo limite verrà rimosso quando la memorizzazione nella cache delle istantanee verrà spostata nel database. Fino ad allora, per aumentare la capacità di OpenBot devi potenziare il server, non aggiungere server. L’isolamento tra i bot è comunque garantito dai container dedicati a ciascun bot, come i sandbox per agenti self-hosted impediscono che gli errori di un agente influenzino gli altri.

Modalità di errore e messaggi visualizzati

L'avvio termina immediatamente dopo la compilazione di .env. Il server valida la configurazione prima di iniziare a gestire le richieste. Un blocco Intelligence parziale, KEY_ENCRYPTION_KEY mancante oppure un provider OAuth con un client ID ma senza secret interrompono tutti l'avvio, invece di degradare silenziosamente. Leggi il primo errore, correggi quel campo e avvia nuovamente il server.

Le migrazioni falliscono su un database gestito. L'estensione vector non è abilitata per impostazione predefinita, quindi la migrazione utilizza un tipo di colonna che PostgreSQL non riconosce. Connettiti come superuser, esegui CREATE EXTENSION vector;, quindi ripeti il passaggio della migrazione.

L'applicazione viene caricata, ma l'accesso non rimane attivo. Stai utilizzando http:// in chiaro su un indirizzo pubblico. Non è quindi un contesto sicuro e il cookie Secure viene scartato. Configura TLS davanti all'applicazione oppure usa il tunnel SSH, in modo che il browser rilevi localhost.

I bot condividono account che dovevano essere separati. Il supervisor non è in esecuzione, quindi non esiste un computer dedicato per ogni bot e tutti i bot utilizzano il browser condiviso. Verifica che COMPUTER_SUPERVISOR_URL sia impostato e che il supervisor possa raggiungere il socket Docker.

Un bot si arresta e chiede assistenza. È il comportamento previsto dal design. Il registro di audit registra computer.help_requested, tu prendi il controllo della schermata attiva e il passaggio di consegne viene registrato da entrambe le parti.

FAQ

OPENBOT_SINGLE_USER può essere lasciato attivo per un'installazione VPS?

Solo quando il gateway non è raggiungibile da Internet. OPENBOT_SINGLE_USER=true accetta ogni richiesta come un unico amministratore senza autenticazione, quindi chiunque possa aprire la porta ottiene il controllo dell'installazione, delle credenziali memorizzate e del browser con sessione autenticata. È accettabile quando ogni porta è associata a 127.0.0.1 e si accede all'app tramite un tunnel SSH o un'interfaccia di rete privata. Su un'interfaccia pubblica, disattivarlo e configurare Google, Microsoft Entra, Okta o OIDC insieme a BETTER_AUTH_SECRET, BETTER_AUTH_URL, INITIAL_ADMIN_EMAILS e TRUSTED_ORIGINS.

Quanta RAM richiede un bot OpenBot?

I dati pubblicati dal progetto per un singolo Bot su arm64 indicano un picco di memoria pari a 0.55 GB, con 2 GB come minimo documentato e 4 GB consigliati. Non esiste un dato pubblicato per più bot eseguiti contemporaneamente, perché ciascuno mantiene una propria istanza di Chromium. Eseguire un bot con un'attività reale, leggere la memoria del relativo container in docker stats, aggiungere il gateway e il database, quindi moltiplicare il risultato per il numero di bot che si prevede di eseguire contemporaneamente.

Serve un account CopilotKit per eseguire OpenBot in self-hosting?

Sì. OpenBot dipende da un progetto CopilotKit Intelligence per i thread persistenti e la memoria, e il server rifiuta di avviarsi se non sono impostati l'URL dell'API Intelligence, l'URL WebSocket del gateway, la chiave API e il token di licenza. Ad agosto 2026 è disponibile un piano gratuito e Intelligence può essere eseguito in self-hosting, quindi la dipendenza dal servizio ospitato può essere rimossa con attività aggiuntive. È inoltre necessario fornire la propria chiave API del modello, perché OpenBot non include alcun modello.

Perché ogni bot dispone di un proprio browser invece di condividerne uno?

Perché un profilo del browser rappresenta un'identità. Un browser condiviso implica cookie e sessioni condivisi, quindi un bot che ha effettuato l'accesso a un account significa che tutti i bot hanno effettuato l'accesso allo stesso account. I container separati per bot assegnano a ogni collaboratore un proprio profilo e le proprie sessioni di accesso. Il costo è in termini di memoria, perché un'istanza di Chromium per bot è la voce più rilevante nel dimensionamento.

Quali porte di OpenBot devono essere aperte nel firewall?

Nessuna delle porte dei livelli sottostanti. L'agent-computer sulla porta 4100, gli endpoint dei bot sulle porte 4200 e 4201, il supervisor sulla porta 4500 e PostgreSQL sulla porta 5432 devono restare privati. Il progetto li protegge con token e richiede comunque che restino irraggiungibili. Pubblicare soltanto ciò che serve agli utenti per accedere e ricordare che una porta del container pubblicata con -p 3001:3001 è raggiungibile indipendentemente da una regola ufw default-deny, perché la regola DNAT di Docker inserisce il traffico nel percorso FORWARD invece che in INPUT.