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

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

Il self-hosting di Open Connector inserisce un unico gateway di autenticazione tra gli agenti AI e tutte le API software as a service (SaaS) che chiamano. L'agente non conserva mai un token del provider. È un gateway open source sviluppato da OOMOL Lab e distribuito con licenza Apache 2.0. Viene eseguito come 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 inizia con la seconda integrazione. Ogni provider ha il proprio flusso OAuth (open authorization), la propria durata del refresh token e i propri nomi degli scope. Collegare manualmente cinque provider a un agente significa gestire cinque handler di redirect, cinque archivi di credenziali e cinque processi di rinnovo che devono essere eseguiti prima della scadenza di un token. Quasi nessuno scrive questo codice. Si genera un personal access token con validità lunga per ogni servizio e lo si incolla nella configurazione dell'agente, in un file di ambiente o nel prompt stesso. Ogni tool eseguito dall'agente può quindi leggere quel token, che finisce anche nella trascrizione. È questo il problema descritto in come mantenere i secret fuori dagli agenti AI.

Un gateway di autenticazione separa la credenziale in due parti. Il gateway conserva la credenziale del provider ed esegue il flusso OAuth. L'agente riceve un runtime token valido soltanto per il gateway. Quando l'agente chiama un'azione, il gateway carica la credenziale salvata, 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. Una trascrizione dell'agente esposta compromette quindi un solo runtime token revocabile, non l'account GitHub.

Il catalogo dichiara più di 1,000 provider e 10,000 azioni predefinite. Questa è una cifra fornita dal progetto e non può essere verificata dall'esterno. Ciò che si può verificare è la struttura: un endpoint HTTP per ogni azione, una connessione salvata per ogni provider e un token per ogni agente. Se il funzionamento lato agente è ancora nuovo e termini come tool call o MCP server non sono ancora chiari, il percorso graduale in come imparare da zero a usare gli agenti AI introduce il ciclo di esecuzione, 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 connettore in hosting

Un servizio di connettore in hosting svolge lo stesso lavoro e conserva i refresh token per ogni provider a cui lo colleghi. Un refresh token per Google o GitHub è una chiave a lunga durata per accedere alla tua posta e ai tuoi repository e, in genere, resta valido anche dopo una modifica della password. Una loro violazione compromette anche il tuo sistema. Con il self-hosting, questi dati vengono spostati 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 solo la porta 443, nessun accesso condiviso, un backup che hai effettivamente ripristinato almeno una volta e un avviso quando il server smette di rispondere. Se non metteresti il tuo password vault su questa macchina, non installarci neppure il connettore.

Blocca una versione prima di installare qualsiasi componente

Open Connector è un progetto recente. Il repository è comparso per la prima volta il 29 June 2026 e, al 1 August 2026, la versione contrassegnata più recente è v1.3.3, pubblicata il 30 July 2026 e contrassegnata anche con il tag latest. Il registry pubblica inoltre un 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 trascorrere la serata a eseguire il debug dell'agent come se il problema fosse nell'agent stesso. Blocca l'immagine su un tag di release e aggiorna quando decidi tu, dopo aver letto le note di rilascio.

Distribuire Open Connector dietro TLS sul proprio VPS

Prima dell’avvio del container sono necessari:

  • Docker con il plugin Compose, su Ubuntu 24.04 o una versione simile
  • un hostname il cui record A punti a questo VPS, ad esempio connect.example.com
  • un reverse proxy che gestisca già la terminazione TLS (transport layer security) per quell’hostname
  • due secret casuali, generati più avanti

La guida Reverse proxy Traefik per più applicazioni Docker Compose illustra la configurazione del proxy. La stessa configurazione dei certificati, dall’inizio alla fine per una singola applicazione, è descritta nella guida n8n su un VPS con Docker e HTTPS.

Generare prima i secret. La chiave di cifratura 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 di essi.

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 .env

Copiare subito entrambi i valori nel password manager, prima del primo avvio. La chiave di cifratura non può essere recuperata. Il motivo è indicato 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 filtraggio di ufw. Di conseguenza, ufw deny 3000 non chiude quella porta: questo è il problema descritto in perché le porte Docker bypassano ufw. Scrivere 127.0.0.1:3000:3000 pubblica la porta soltanto sull’interfaccia loopback e il reverse proxy si connette dallo stesso host.

:? indica che ogni variabile è obbligatoria. In questo modo lo stack non si avvia quando manca .env, invece di avviarsi con credenziali non cifrate. Mantenere i valori in .env anziché nel file Compose segue il modello descritto in file env e secret di Docker Compose.

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 restituisce { "ok": true } quando il runtime è attivo. ss deve stampare 127.0.0.1:3000. Una riga con 0.0.0.0:3000 indica che la mappatura della porta è ancora quella upstream e che il gateway risponde direttamente all’intera Internet. Un errore “connection refused” nel controllo di stato indica che il container non è ancora in ascolto. Consultare 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é OAuth richiede un hostname reale

OOMOL_CONNECT_ORIGIN è l'impostazione che spesso viene omessa. Se manca, OAuth non funziona e l'errore può sembrare causato dal provider. Il runtime costruisce l'URI di redirect a partire da quell'origine, nel formato <origin>/oauth/callback. Se non è impostata, l'origine predefinita è http://localhost:3000. Di conseguenza, il runtime invia al provider l'URI di redirect http://localhost:3000/oauth/callback, mentre nell'app OAuth è registrato https://connect.example.com/oauth/callback. Le due stringhe sono diverse, 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'URI deve quindi essere un indirizzo raggiungibile dall'esterno. I provider rifiutano http:// semplice per qualsiasi destinazione diversa da localhost. Per questo questa distribuzione richiede un hostname e un certificato. Imposta l'origine prima del primo avvio, perché il valore viene letto all'avvio. Dopo aver modificato .env o compose.yaml, esegui nuovamente 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 agente un token di runtime, mai la credenziale

L’agente si autentica 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 agente e assegnagli il nome dell’agente, perché revocare un token che non puoi identificare significa revocarli tutti. L’agente esegue quindi le chiamate alle azioni tramite HTTP ordinario.

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 con il campo success impostato su true e il payload del provider nel campo data. Il token GitHub non compare in alcun punto della risposta. Per un client MCP, configuralo per usare https://connect.example.com/mcp con lo stesso header bearer; il gateway espone strumenti di discovery come search_actions e execute_action invece di uno strumento per ogni API, mantenendo così ridotto l’elenco degli strumenti dell’agente. Eseguire server MCP su un VPS illustra la parte relativa al client.

Esegui un ulteriore controllo prima di considerare conclusa la configurazione. Ripeti la chiamata all’azione eliminando l’header authorization. Il quickstart del progetto chiama /v1 senza alcun bearer; quindi, se non hai configurato l’autenticazione di runtime, l’installazione eseguirà le azioni 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 gli agenti. Solo /oauth/callback deve restare aperto al mondo, perché è l’unico percorso necessario al redirect del browser del provider.

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 connector

Il 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.sqlite

Un 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. Per OAuth, nella pratica sì. Il provider reindirizza il browser al tuo URL di callback, quindi quell'URL deve essere raggiungibile da Internet pubblico e i provider rifiutano http:// semplice al di fuori di localhost. Imposta OOMOL_CONNECT_ORIGIN sul tuo hostname https:// prima del primo avvio e registra <origin>/oauth/callback nell'app OAuth del provider.

Cosa succede se perdo la chiave di crittografia di Open Connector?

Le credenziali memorizzate non possono essere decrittografate e non esiste alcun recupero. La chiave non viene mai memorizzata insieme ai dati, per progettazione, quindi nessuno può leggere il database, nemmeno tu. L'unica opzione è 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 esegue l'autenticazione con un token di runtime che inizia con oct_, mentre il gateway inserisce la credenziale del provider nella richiesta in uscita sul server e restituisce soltanto la risposta. Questa proprietà viene meno in due casi: l'endpoint /v1/proxy/:service, che inoltra le richieste non elaborate con la tua credenziale allegata e i cui grant iniziano vuoti per un motivo preciso, e l'inserimento manuale di una chiave API nell'agente, che bypassa completamente il gateway.

Il gateway deve essere raggiungibile da Internet pubblico?

Soltanto /oauth/callback deve esserlo. Pubblica la porta del container su 127.0.0.1, in modo che le regole NAT di Docker non possano esporla oltre il firewall, e posiziona il reverse proxy davanti al gateway. Quindi testa una chiamata d'azione senza l'header authorization. Se la chiamata riesce, limita /api, /v1 e /mcp nel proxy agli indirizzi usati dai tuoi agenti, finché non funzionano soltanto le chiamate autenticate.

Open Connector è pronto per l'uso in produzione?

È distribuito con licenza Apache 2.0 e il suo sviluppo procede rapidamente: il repository è comparso il 29 giugno 2026 e la versione v1.3.3 è stata rilasciata il 30 luglio 2026, quindi considera ogni numero di versione in questa guida come un'istantanea al 1 agosto 2026. Eseguilo fissando un release tag, mai su latest o tip, leggi le note di rilascio prima di ogni aggiornamento e conserva un backup del volume che hai già ripristinato almeno una volta. Il design è adeguato per un server che possiedi; il rischio è il rapido susseguirsi delle versioni, non l'architettura.