Self-hosting di Open Connector per agenti AI
Installa Open Connector sul tuo VPS: immagine fissata, origine TLS, callback OAuth e backup SQLite, senza esporre ai tuoi agenti i token SaaS.
Cosa fa Open Connector per un agente AI
L'hosting autonomo di Open Connector inserisce un unico gateway di autenticazione tra gli agenti AI e tutte le API software as a service (SaaS) che chiamano, così l'agente non gestisce mai un token del provider. È un gateway con codice sorgente disponibile di OOMOL Lab, attualmente distribuito con una licenza Apache 2.0 modificata e condizioni aggiuntive. Le release fino alla v1.9.4 restano sotto Apache 2.0; la modifica è stata introdotta nella v1.9.5. La fornitura di un servizio hosted o gestito il cui valore principale è la funzionalità di OpenConnector richiede una licenza commerciale di OOMOL. Il gateway viene eseguito in un unico container, conserva lo stato in un singolo file SQLite ed espone le azioni dei provider tramite HTTP e MCP (model context protocol).
Il problema emerge già con la seconda integrazione. Ogni provider ha un proprio flusso OAuth (open authorization), una propria durata del refresh token e propri nomi degli scope. Collegare manualmente cinque provider a un agente significa gestire cinque redirect handler, cinque archivi di credenziali e cinque cicli di rinnovo da eseguire prima della scadenza dei token. Quasi nessuno scrive questo codice. Si genera un personal access token di lunga durata per ogni servizio e lo si copia nella configurazione dell'agente, in un file di ambiente o direttamente nel prompt. Ogni tool eseguito dall'agente può quindi leggere quel token, che finisce anche nella trascrizione: è questo il problema descritto da come mantenere i secret fuori dagli agenti AI.
Un gateway di autenticazione separa la credenziale in due parti. Il gateway memorizza la credenziale del provider ed esegue il flusso OAuth. L'agente riceve un token di runtime valido soltanto verso il gateway. Quando l'agente chiama un'azione, il gateway carica la credenziale memorizzata, la inserisce lato server nella richiesta in uscita e restituisce soltanto il corpo della risposta. L'agente non riceve mai l'access token del provider; quindi, se la trascrizione dell'agente viene divulgata, il costo è un singolo token di runtime revocabile, non l'accesso al proprio account GitHub.
Il catalogo dichiara più di 1,000 provider e 10,000 azioni predefinite. Si tratta del dato indicato dal progetto e non di un valore verificabile dall'esterno. Quello che si può verificare è la struttura: un endpoint HTTP per ogni azione, una connessione memorizzata per ogni provider e un token per ogni agente. Se la parte relativa agli agenti è ancora nuova e termini come tool call o MCP server non sono ancora consolidati, il percorso graduale in come imparare gli agenti AI da zero introduce il ciclo, i tool e le pratiche di sicurezza che un gateway di questo tipo presuppone già acquisite.
Perché eseguire autonomamente Open Connector invece di usare un servizio di connector in hosting
Un servizio di connector in hosting svolge lo stesso lavoro e conserva i refresh token di ogni provider a cui lo colleghi. Un refresh token per Google o GitHub è una chiave a lunga durata per accedere alla posta e ai repository. Se il servizio viene violato, la violazione riguarda anche te. L'hosting autonomo sposta questi record in SQLite su una macchina che noleggi e amministri, protetti da una chiave che non lascia mai il tuo server.
Valuta esplicitamente il costo prima di iniziare. Questo VPS diventa il server più importante che gestisci. Contiene in un unico file credenziali operative per una dozzina di servizi, quindi richiede lo stesso livello di protezione di un host che esegue un password manager: un firewall che espone soltanto la porta 443, nessun account condiviso, un backup che hai effettivamente ripristinato almeno una volta e un alert quando il server smette di rispondere. Se non conserveresti il tuo password vault su questa macchina, non installarci neppure il connector.
Blocca la versione prima di installare qualsiasi componente
Open Connector è un progetto recente. Questa guida utilizza v1.3.3, pubblicata il 30 luglio 2026, come versione fissata per lo snapshot di installazione del 1 agosto 2026. Non è più la release più recente. Il registry pubblica anche il tag tip, creato a partire dal commit più recente su main.
In un progetto così recente, i tag mobili cambiano spesso. Un docker compose pull che salta due release può modificare un endpoint da cui dipende il tuo agent, e potresti passare la serata a eseguire il troubleshooting come se il problema riguardasse l'agent. Fissa l'immagine a un tag di release ed esegui l'upgrade quando lo decidi tu, dopo aver letto le note di release.
Implementare Open Connector dietro TLS sul proprio VPS
Prima di avviare il container sono necessari:
- Docker Engine 28.0.0 o versione successiva con il plugin Compose, su Ubuntu 24.04 o una distribuzione simile
- un hostname il cui record A punti a questo VPS, ad esempio
connect.example.com - un reverse proxy che termini già TLS (Transport Layer Security) per questo hostname
- due secret casuali, generati di seguito
La guida Reverse proxy Traefik per più applicazioni Docker Compose tratta la configurazione del proxy. La guida n8n su un VPS con Docker e HTTPS descrive la configurazione completa dei certificati, dall'inizio alla fine, per una singola applicazione.
Generare prima i secret. La chiave di crittografia protegge le credenziali memorizzate. Il token amministrativo protegge la console web e l'intera superficie /api. Nessuno dei due ha un valore predefinito e il runtime si avvia comunque senza questi valori.
mkdir -p ~/open-connector && cd ~/open-connector
umask 077
printf 'OOMOL_CONNECT_ENCRYPTION_KEY=%s\n' "$(openssl rand -base64 32)" > .env
printf 'OOMOL_CONNECT_ADMIN_TOKEN=%s\n' "$(openssl rand -base64 32)" >> .env
chmod 600 .envCopiare subito entrambi i valori nel password manager, prima del primo avvio. Non è possibile recuperare la chiave di crittografia. Il motivo è spiegato nell'elenco degli errori più avanti.
Ora compose.yaml. Differisce dall'esempio upstream in due punti, entrambi importanti.
services:
connector:
image: ghcr.io/oomol-lab/open-connector:v1.3.3
restart: unless-stopped
ports:
- "127.0.0.1:3000:3000"
volumes:
- connector-data:/app/data
environment:
OOMOL_CONNECT_DATA_DIR: /app/data
OOMOL_CONNECT_ORIGIN: "https://connect.example.com"
OOMOL_CONNECT_ENCRYPTION_KEY: "${OOMOL_CONNECT_ENCRYPTION_KEY:?set this in .env}"
OOMOL_CONNECT_ADMIN_TOKEN: "${OOMOL_CONNECT_ADMIN_TOKEN:?set this in .env}"
volumes:
connector-data:La prima modifica è il tag fissato invece di latest. La seconda riguarda la porta. Il file upstream pubblica 3000:3000, associandola a tutte le interfacce dell'host. Docker scrive le porte pubblicate nella tabella NAT (Network Address Translation) prima che il pacchetto raggiunga la catena di filtro ufw. Di conseguenza, ufw deny 3000 non chiude quella porta: questo è il problema descritto in perché le porte Docker bypassano ufw. La configurazione 127.0.0.1:3000:3000 pubblica la porta soltanto sull'interfaccia di loopback e il reverse proxy si connette dallo stesso host. Prima di Docker Engine 28.0.0, gli host dello stesso segmento L2 potevano raggiungere le porte pubblicate su localhost. Per questo la guida richiede la versione 28.0.0 o successiva.
:? contrassegna ogni variabile come obbligatoria. Lo stack quindi rifiuta di avviarsi quando manca .env, invece di avviarsi con le credenziali non crittografate. Conservare i valori in .env anziché nel file Compose è il modello descritto in file env e secret di Docker Compose. Mantenere privati /v1 e /mcp nel reverse proxy fino a quando non è stato creato il primo token del runtime, come descritto di seguito.
docker compose up -d
docker compose logs -n 30 connector
curl -s http://127.0.0.1:3000/health
sudo ss -tlnp | grep 3000/health risponde { "ok": true } quando il runtime è attivo. ss deve restituire 127.0.0.1:3000. Una riga con 0.0.0.0:3000 indica che il listener è associato a tutte le interfacce IPv4, ma non dimostra che sia raggiungibile da Internet: firewall upstream o regole nella catena DOCKER-USER di Docker possono ancora bloccare il traffico esterno. Un errore «connection refused» nel controllo di integrità indica che il container non è ancora in ascolto. Consultare quindi i log prima di modificare il proxy.
Etichette Traefik per lo stesso servizio
labels:
- "traefik.enable=true"
- "traefik.http.routers.connector.rule=Host(`connect.example.com`)"
- "traefik.http.routers.connector.entrypoints=websecure"
- "traefik.http.routers.connector.tls.certresolver=le"
- "traefik.http.services.connector.loadbalancer.server.port=3000"Quando Traefik viene eseguito in Docker sullo stesso host, collegare questo servizio alla rete Traefik ed eliminare il blocco ports:, perché Traefik raggiunge il container tramite la rete interna e non è necessario pubblicare alcuna porta sull'host. certresolver=le deve corrispondere al nome del resolver nella configurazione statica di Traefik. In caso contrario, il router viene avviato senza certificato.
Perché i callback OAuth richiedono l’origine corretta
OOMOL_CONNECT_ORIGIN è l’impostazione che spesso viene ignorata. Se viene omessa, OAuth non funziona e l’errore può sembrare un problema del provider. Il runtime costruisce l’URI di reindirizzamento a partire da quell’origine, nel formato <origin>/oauth/callback. Se non viene impostata, l’origine predefinita è http://localhost:3000. Di conseguenza, il runtime invia al provider l’URI di reindirizzamento http://localhost:3000/oauth/callback, mentre nell’app OAuth è registrato https://connect.example.com/oauth/callback. Le due stringhe non coincidono, quindi GitHub risponde:
The redirect_uri MUST match the registered callback URL for this application.Un provider OAuth reindirizza il browser a quell’URI. L’indirizzo deve quindi essere raggiungibile dal browser. OAuth non richiede necessariamente un hostname pubblico: OpenConnector documenta i callback GitHub su http://localhost:3000/oauth/callback. Questa distribuzione su VPS usa un hostname e un certificato, in modo che il browser raggiunga il gateway tramite la relativa origine HTTPS. Imposta l’origine prima del primo avvio, perché il valore viene letto all’avvio. Dopo aver modificato .env o compose.yaml, esegui di nuovo docker compose up -d per applicare la modifica.
Collega il primo provider tramite OAuth
Crea prima l'app OAuth presso il provider. Su GitHub, il percorso è Settings, quindi Developer settings, OAuth Apps e New OAuth App. Imposta l'URL di callback per l'autorizzazione su https://connect.example.com/oauth/callback. Conserva il client ID e il client secret.
Ogni chiamata /api include il token amministrativo, quindi esportalo una sola volta per la sessione della shell.
export ADMIN_TOKEN='paste-the-admin-token'
curl -s https://connect.example.com/api/oauth/configs \
-H "authorization: Bearer $ADMIN_TOKEN"L'elenco mostra l'URI di reindirizzamento previsto dal runtime per ogni provider. È il controllo più rapido per verificare che l'origine sia stata applicata. Se mostra ancora localhost, il container è in esecuzione con il valore precedente e il flusso OAuth non riuscirà nell'ultimo passaggio.
Salva le credenziali client, quindi avvia un'autorizzazione.
curl -s -X PUT https://connect.example.com/api/oauth/configs/github \
-H "authorization: Bearer $ADMIN_TOKEN" \
-H 'content-type: application/json' \
-d '{"clientId":"...","clientSecret":"..."}'
curl -s -X POST https://connect.example.com/api/oauth/authorizations \
-H "authorization: Bearer $ADMIN_TOKEN" \
-H 'content-type: application/json' \
-d '{"service":"github"}'La seconda chiamata restituisce un authorizationUrl. Aprilo in un browser e approva gli scope. Il provider reindirizza quindi il browser a /oauth/callback, dove il runtime scambia il codice e salva la credenziale. La console web disponibile presso la tua origine esegue gli stessi passaggi tramite un modulo, usando lo stesso token amministrativo. I provider che usano una semplice chiave API non richiedono questa procedura: PUT /api/connections/<service> con {"authType":"api_key","values":{"apiKey":"..."}} salva direttamente la chiave.
Assegna a ogni agent un token di runtime, mai la credenziale
L'agent esegue l'autenticazione al gateway con un token di runtime, generato dall'API di amministrazione.
curl -s -X POST https://connect.example.com/api/runtime-tokens \
-H "authorization: Bearer $ADMIN_TOKEN" \
-H 'content-type: application/json' \
-d '{"name":"research-agent"}'La risposta contiene un token che inizia con oct_. Generane uno per ogni agent e assegnagli il nome dell'agent, perché revocare un token che non puoi identificare significa revocarli tutti. L'agent invoca quindi le action tramite HTTP standard.
curl -s -X POST https://connect.example.com/v1/actions/github.get_current_user \
-H "authorization: Bearer oct_..." \
-H 'content-type: application/json' \
-d '{"input":{}}'Una risposta corretta è un envelope il cui campo success è true, con il payload del provider nel campo data. Il token GitHub non compare in alcun punto di questa risposta. Per un client MCP, impostalo su https://connect.example.com/mcp con lo stesso header bearer; il gateway mette a disposizione strumenti di discovery come search_actions e execute_action invece di uno strumento per ogni API. In questo modo l'elenco degli strumenti dell'agent resta ridotto. Eseguire server MCP su un VPS tratta la parte relativa al client.
Esegui un altro controllo prima di considerare conclusa la configurazione. Ripeti la chiamata all'action eliminando l'header authorization. Il quickstart ufficiale del progetto invoca /v1 senza alcun bearer; un'installazione senza autenticazione di runtime configurata eseguirà quindi le action per chiunque possa raggiungere la porta. Se la chiamata non autenticata ha esito positivo, hai due possibilità: configurare i token di runtime e verificare che la chiamata anonima ora fallisca, oppure limitare /api, /v1 e /mcp nel reverse proxy agli indirizzi da cui provengono i tuoi agent. /oauth/callback deve essere raggiungibile dal browser che completa l'autorizzazione; non deve essere esposto all'intera Internet.
Ridurre l’elenco delle azioni a quelle necessarie all’agente
Un gateway con mille provider alle spalle offre a un modello linguistico una superficie operativa troppo ampia. La superficie aumenta ulteriormente quando il modello inizia a leggere testo che non ha scritto, perché una pagina restituita da una propria istanza SearXNG che risponde alle ricerche web dell’agente può contenere istruzioni rivolte alle azioni disponibili per l’agente. La stessa prudenza che porta un agente di coding ad applicare la modifica minima efficace deve essere applicata anche alle autorizzazioni: concedi solo le poche azioni effettivamente necessarie al lavoro, senza aggiungerne altre. Due controlli consentono di restringere l’accesso.
OOMOL_CONNECT_ALLOWED_ACTIONS accetta un elenco di autorizzazione separato da virgole e riconosce service.* e *. OOMOL_CONNECT_BLOCKED_ACTIONS è l’elenco di negazione, che ha la precedenza. Impostare l’elenco di autorizzazione su github.get_current_user,github.list_issues significa rifiutare ogni altra azione, indipendentemente da ciò che richiede l’agente. Questa è la differenza tra un errore e un incidente. I token di runtime applicano regole proprie sulle azioni, in aggiunta a quelle globali, e il relativo elenco allowedProxies è vuoto per impostazione predefinita. Di conseguenza, POST /v1/proxy/:service viene rifiutata finché non la autorizzi. L’endpoint del proxy inoltra una richiesta non elaborata a un provider usando le tue credenziali, quindi lascialo vuoto salvo che un agente specifico ne abbia bisogno.
OOMOL_CONNECT_ALLOW_PRIVATE_NETWORK è impostato per impostazione predefinita su false. Questo impedisce a una connessione verso un provider self-hosted di puntare a un indirizzo privato, ad esempio il servizio di metadati cloud su 169.254.169.254 o il database sulla stessa rete. Lascialo disattivato. Attivalo solo per un provider che gestisci direttamente.
Eseguire il backup del server che contiene tutti i token
Ci sono due elementi importanti, e ciascuno è inutilizzabile senza l’altro. Il database in /app/data/connect.sqlite, all’interno del volume connector-data, contiene le credenziali sigillate. La chiave di crittografia in .env le apre. Un backup del volume senza la chiave non consente di ripristinare nulla, e la chiave senza il volume non consente di ripristinare nulla. La chiave deve quindi essere conservata nel password manager, mentre il volume deve rientrare nella normale rotazione dei backup.
Arrestare il container mentre si copia il file SQLite, perché una copia eseguita durante una scrittura può essere ripristinata come database corrotto.
docker volume ls | grep connector-data
docker compose stop connector
docker run --rm -v open-connector_connector-data:/data -v "$PWD":/backup alpine \
tar czf /backup/connector-data.tgz -C /data .
docker compose start connectorIl nome del volume è la directory del progetto seguita da _connector-data. Per questo il primo comando è presente: incollare il nome reale nel terzo. Trasferire l’archivio fuori dal VPS usando i backup restic da un VPS, che lo cifra prima del trasferimento, perché quell’archivio contiene il repository delle credenziali.
Il runtime conserva le esecuzioni recenti delle azioni come record di audit, 5,000 per impostazione predefinita. In questo modo la console può indicare quale agent ha eseguito quale operazione e quando. Questo log è il primo elemento da consultare quando un agent si comporta in modo anomalo. Configurare anche una pagina di stato Uptime Kuma su https://connect.example.com/health. Quando il gateway smette di rispondere, gli agent falliscono in modi poco chiari e sapere che il gateway è inattivo evita un’ora di analisi dell’output degli agent.
Cosa può non funzionare e quale messaggio verrà visualizzato
redirect_uri_mismatch presso il provider. L'origine e l'URL di callback registrato non corrispondono. Confronta la stringa esatta di /api/oauth/configs con le impostazioni dell'applicazione presso il provider, verificando anche https rispetto a http e l'eventuale slash finale.
Ogni chiamata /api restituisce 401. L'header del token amministrativo manca oppure è scritto in modo errato. L'header è Authorization: Bearer <token> e la console Web richiede lo stesso token.
Il container è in esecuzione e le credenziali sono memorizzate in testo in chiaro. Questo accade quando OOMOL_CONNECT_ENCRYPTION_KEY non raggiunge il container, perché il runtime memorizza i record delle credenziali senza cifrarli invece di rifiutare l'avvio. Verificalo sulla tua installazione: collega un provider usando una API key riconoscibile, quindi cerca la chiave nel database.
docker compose cp connector:/app/data/connect.sqlite /tmp/connect.sqlite
grep -c 'github_pat_' /tmp/connect.sqlite
shred -u /tmp/connect.sqliteUn valore superiore a 0 indica che la chiave non è applicata. Verifica quindi che .env si trovi nella stessa directory di compose.yaml e che docker compose config mostri il valore. Dopo aver impostato la chiave, la stessa ricerca restituisce 0, perché il record è protetto con AES-256-GCM (advanced encryption standard, chiave a 256 bit, modalità Galois/counter).
Dopo un ripristino non viene decrittografato nulla. La chiave di cifratura è cambiata oppure è andata persa. Per progettazione, non viene mai scritta accanto ai dati. Non esiste quindi una procedura di recupero e nessun ticket di supporto può risolvere il problema. Ricollega tutti i provider. La rotazione è supportata tramite una variabile separata per la chiave e un comando sui dati nel runtime. Consulta quindi le note di rilascio della versione corrente prima di eseguire la rotazione.
L'agente restituisce un errore relativo a un'azione che risulta visibile nel catalogo. La rilevazione e l'esecuzione sono processi distinti. Un'azione può comparire in search_actions e venire comunque rifiutata da OOMOL_CONNECT_ALLOWED_ACTIONS, dalla denylist oppure dalle regole associate al token del runtime in uso.
Aggiornamenti. Esegui il backup del volume, modifica il tag dell'immagine impostandolo sulla nuova release, quindi docker compose pull && docker compose up -d. Monitora docker compose logs -n 50 connector per verificare la presenza di una riga relativa alla migrazione, quindi esegui nuovamente il controllo di integrità e un'azione reale prima di considerare il sistema nuovamente affidabile. Per eseguire il rollback, ripristina il tag precedente. Questa procedura funziona solo perché hai fissato il tag.
FAQ
Devo disporre di un dominio pubblico per eseguire Open Connector in self-hosting?
Per i provider che usano una chiave API, no: è sufficiente un gateway su 127.0.0.1. Neppure OAuth lo richiede sempre: OpenConnector documenta il callback locale di GitHub come http://localhost:3000/oauth/callback. Il browser che completa l'autorizzazione deve raggiungere l'URL di callback. Per questa distribuzione su VPS, imposta OOMOL_CONNECT_ORIGIN sull'hostname https:// prima del primo avvio e registra <origin>/oauth/callback nell'app OAuth del provider.
Cosa succede se perdo la chiave di cifratura di Open Connector?
Le credenziali archiviate non possono essere decifrate e non esiste alcun recupero. La chiave non viene mai archiviata insieme ai dati, per scelta progettuale, quindi chiunque disponga del database non può leggerla, nemmeno tu. L'unica possibilità è impostare una nuova chiave e ricollegare ogni provider. Conserva la chiave in un password manager e includi il database nella rotazione dei backup, perché per un ripristino sono necessari entrambi.
Il mio agente AI può vedere il token di accesso del provider?
Non quando effettua le chiamate tramite il gateway. L'agente si autentica con un token di runtime che inizia con oct_ e il gateway inserisce la credenziale del provider nella richiesta in uscita sul server, restituendo soltanto la risposta. Due situazioni compromettono questa separazione: l'endpoint /v1/proxy/:service, che inoltra richieste non modificate con la credenziale allegata e le cui autorizzazioni iniziano vuote per un motivo preciso, e l'inserimento manuale di una chiave API nell'agente, che aggira completamente il gateway.
Il gateway deve essere raggiungibile da Internet?
Il callback OAuth deve essere raggiungibile dal browser che completa l'autorizzazione, ma non è necessario consentire l'accesso da tutta Internet. Con Docker Engine 28.0.0 o versioni successive e la rete bridge predefinita, pubblica la porta del container su 127.0.0.1 per mantenere la porta pubblicata accessibile soltanto dall'host, quindi posiziona il reverse proxy davanti al gateway. Le versioni precedenti di Docker consentivano agli host dello stesso segmento L2 di raggiungere le porte pubblicate su localhost. Esegui quindi il test di una chiamata a un'azione senza l'header authorization. Se la chiamata riesce, limita /api, /v1 e /mcp sul proxy agli indirizzi utilizzati dagli agenti, finché funzionano soltanto le chiamate autenticate.
Open Connector è pronto per l'uso in produzione?
Le release attuali usano una licenza Apache 2.0 modificata con condizioni aggiuntive; le release fino alla v1.9.4 inclusa, compresa la v1.3.3 indicata nel tutorial, restano soggette alla licenza Apache 2.0. Un servizio di connettore hosted o gestito il cui valore principale è la funzionalità di OpenConnector richiede una licenza commerciale da OOMOL secondo la licenza attuale. I comandi di installazione della v1.3.3 sono una fotografia della situazione al 1 August 2026 e quella release è stata pubblicata il 30 July 2026. Eseguila fissando un release tag, mai su latest o tip, leggi le note di rilascio prima di ogni upgrade e conserva un backup del volume che hai già ripristinato almeno una volta. Il design è valido per un server di tua proprietà; il rischio deriva dal rapido susseguirsi delle versioni, non dall'architettura.