Como hospedar o Open Connector para agentes de IA
Execute o gateway OAuth do Open Connector em um VPS, com imagem fixada, origem TLS, callbacks OAuth e backups do SQLite, sem expor tokens SaaS ao agente.
O que o Open Connector faz para um agente de IA
A hospedagem própria do Open Connector coloca um gateway de autenticação entre seus agentes de IA e todas as APIs de software como serviço (SaaS) que eles chamam. Assim, o agente nunca armazena um token do provedor. Ele é um gateway de código aberto da OOMOL Lab, licenciado sob Apache 2.0. Ele é executado como um único container, mantém o estado em um único arquivo SQLite e expõe ações dos provedores por HTTP e por MCP (model context protocol).
O problema começa na segunda integração. Cada provedor tem seu próprio fluxo OAuth (open authorization), seu próprio prazo de validade para tokens de atualização e seus próprios nomes de escopo. Integrar cinco provedores manualmente a um agente significa criar cinco handlers de redirecionamento, cinco armazenamentos de credenciais e cinco loops de atualização que precisam ser executados antes de um token expirar. Quase ninguém escreve esse código. Em vez disso, criam um personal access token de longa duração para cada serviço e o colam na configuração do agente, em um arquivo de ambiente ou no próprio prompt. Todos os tools executados pelo agente podem ler esse token. Ele também aparece na transcrição, que é a falha descrita em mantendo segredos fora dos agentes de IA.
Um gateway de autenticação divide a credencial em duas partes. O gateway armazena a credencial do provedor e executa o fluxo OAuth. O agente recebe um token de runtime válido somente para o gateway. Quando o agente chama uma ação, o gateway carrega a credencial armazenada, a injeta no request de saída no lado do servidor e retorna somente o corpo da resposta. O agente nunca recebe o access token do provedor. Portanto, uma transcrição do agente exposta custa um token de runtime revogável, e não sua conta do GitHub.
O catálogo anuncia mais de 1,000 provedores e 10,000 ações predefinidas. Esse número é uma estimativa do próprio projeto, não algo que possa ser verificado externamente. O que pode ser verificado é a estrutura: um endpoint HTTP por ação, uma conexão armazenada por provedor e um token por agente.
Por que hospedar o Open Connector por conta própria em vez de usar um serviço de conectores hospedado
Um serviço de conectores hospedado faz o mesmo trabalho e armazena os tokens de atualização de todos os provedores que você conecta a ele. Um token de atualização do Google ou do GitHub é uma credencial de longa duração para acessar seu e-mail e seus repositórios e, normalmente, continua válido após uma alteração de senha. Se o serviço for comprometido, seu ambiente também será comprometido. Ao hospedar o serviço por conta própria, esses registros passam a ficar em um banco SQLite em uma máquina que você aluga e administra, protegidos por uma chave que nunca sai do seu servidor.
Considere o custo antes de começar. Esse VPS se torna o servidor mais valioso que você administra. Ele armazena credenciais ativas de uma dúzia de serviços em um único arquivo. Por isso, exige o mesmo tratamento que você daria a um host de gerenciador de senhas: um firewall que exponha apenas a porta 443, nenhuma conta compartilhada, um backup que você já tenha restaurado pelo menos uma vez e um alerta quando o servidor parar de responder. Se você não colocaria seu cofre de senhas nesse servidor, também não coloque o conector nele.
Fixe uma versão antes de instalar qualquer coisa
O Open Connector é recente. O repositório apareceu pela primeira vez em 29 de junho de 2026. Em 1 de agosto de 2026, a versão marcada mais recente é v1.3.3, publicada em 30 de julho de 2026 e também com a tag latest. O registro também publica uma tag tip, criada a partir do commit mais recente em main.
Em um projeto tão recente, as tags móveis mudam com frequência. Uma docker compose pull que avance duas versões pode alterar um endpoint do qual seu agente depende, e você passará a noite investigando o problema como se fosse um erro do agente. Fixe a imagem em uma tag de versão e atualize quando decidir, depois de ler as notas da versão.
Implantar o Open Connector atrás de TLS em seu próprio VPS
Antes de iniciar o container, você precisa de:
- Docker com o plugin Compose, no Ubuntu 24.04 ou em uma versão semelhante
- um hostname cujo registro A aponte para este VPS, por exemplo
connect.example.com - um reverse proxy que já encerre o TLS (transport layer security) para esse hostname
- dois secrets aleatórios, gerados abaixo
O guia Reverse proxy Traefik para vários aplicativos Docker Compose aborda a configuração do proxy. A mesma configuração de certificados, do início ao fim para um único aplicativo, está no guia n8n em um VPS com Docker e HTTPS.
Gere primeiro os secrets. A chave de criptografia protege as credenciais armazenadas. O token de administrador protege o console web e toda a superfície /api. Nenhum dos dois tem valor padrão, e o runtime inicia normalmente sem eles.
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 .envCopie agora os dois valores para o gerenciador de senhas, antes da primeira inicialização. A chave de criptografia não tem um caminho de recuperação. O motivo está na lista de falhas mais abaixo.
Agora compose.yaml. Ele difere do exemplo upstream em dois pontos, e ambos são importantes.
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:A primeira alteração é usar a tag fixada em vez de latest. A segunda é a porta. O arquivo upstream publica 3000:3000, que faz bind em todas as interfaces do host. O Docker grava as portas publicadas na tabela NAT (network address translation) antes que o filter chain do ufw veja o pacote. Por isso, ufw deny 3000 não fecha essa porta. Essa é a armadilha descrita em por que as portas do Docker ignoram o ufw. Escrever 127.0.0.1:3000:3000 publica somente na interface de loopback, e o reverse proxy se conecta a partir do mesmo host.
O :? marca cada variável como obrigatória. Assim, a stack se recusa a iniciar quando .env está ausente, em vez de iniciar com as credenciais sem criptografia. Manter os valores em .env, em vez de no arquivo compose, é o padrão descrito em arquivos env e secrets do 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 responde { "ok": true } quando o runtime está em execução. ss deve imprimir 127.0.0.1:3000. Uma linha com 0.0.0.0:3000 indica que o mapeamento de portas ainda é o do upstream e que o gateway está respondendo diretamente à internet inteira. Uma conexão recusada na verificação de integridade indica que o container ainda não está escutando. Nesse caso, leia os logs antes de alterar o proxy.
Rótulos do Traefik para o mesmo serviço
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 o Traefik é executado no Docker no mesmo host, conecte este serviço à rede do Traefik e exclua o bloco ports:, porque o Traefik acessa o container pela rede interna e não é necessário publicar nada no host. certresolver=le precisa corresponder ao nome do resolver na configuração estática do Traefik. Caso contrário, o router será iniciado sem certificado.
Por que o OAuth exige um hostname real
OOMOL_CONNECT_ORIGIN é a configuração que as pessoas ignoram, e ignorá-la interrompe o OAuth de uma forma que parece um erro do provedor. O runtime cria o URI de redirecionamento a partir dessa origem, no formato <origin>/oauth/callback. Se não estiver definida, a origem assume o valor padrão http://localhost:3000. Assim, o runtime envia ao provedor um URI de redirecionamento com o valor http://localhost:3000/oauth/callback, enquanto o aplicativo OAuth tem https://connect.example.com/oauth/callback registrado. As duas strings são diferentes, então o GitHub responde:
The redirect_uri MUST match the registered callback URL for this application.Um provedor OAuth redireciona o navegador de volta para esse URI. Portanto, ele precisa ser um endereço acessível pela rede externa. Os provedores rejeitam http:// simples para qualquer finalidade que não seja localhost. Esse é o motivo pelo qual esta implantação precisa de um hostname e de um certificado. Defina a origem antes da primeira inicialização, porque o valor é lido na inicialização. Depois de editar .env ou compose.yaml, execute docker compose up -d novamente para aplicar a alteração.
Conecte seu primeiro provedor por OAuth
Crie primeiro o aplicativo OAuth no provedor. No GitHub, o caminho é Settings, depois Developer settings, depois OAuth Apps e, por fim, New OAuth App. Defina a URL de callback de autorização como https://connect.example.com/oauth/callback. Guarde o client ID e o client secret.
Cada chamada de /api inclui o token de administrador, portanto exporte-o uma vez para a sessão do shell.
export ADMIN_TOKEN='paste-the-admin-token'
curl -s https://connect.example.com/api/oauth/configs \
-H "authorization: Bearer $ADMIN_TOKEN"Essa listagem mostra o URI de redirecionamento que o runtime espera para cada provedor. Isso faz dela a verificação mais rápida para confirmar que a origem foi aplicada. Se ainda aparecer localhost, o container está sendo executado com o valor antigo, e o fluxo OAuth falhará na última etapa.
Armazene as credenciais do cliente e inicie uma autorização.
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"}'A segunda chamada retorna um authorizationUrl. Abra-o em um navegador, aprove os escopos, e o provedor enviará o navegador de volta para /oauth/callback. Nesse ponto, o runtime troca o código e armazena a credencial. O console web na sua origem executa as mesmas etapas por meio de um formulário, usando o mesmo token de administrador. Provedores que usam uma chave de API simples ignoram tudo isso: PUT /api/connections/<service> com {"authType":"api_key","values":{"apiKey":"..."}} armazena a chave diretamente.
Dê a cada agente um token de execução, nunca a credencial
O agente se autentica no gateway com um token de execução, emitido pela API administrativa.
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"}'A resposta contém um token que começa com oct_. Emita um token por agente e atribua a ele o nome desse agente, porque revogar um token que você não consegue identificar significa revogar todos eles. Em seguida, o agente chama as ações por HTTP comum.
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":{}}'Uma resposta válida é um envelope cujo campo success é true, com o payload do provedor em data. O token do GitHub não aparece em nenhum lugar dessa resposta. Para um cliente MCP, aponte-o para https://connect.example.com/mcp usando o mesmo cabeçalho bearer, e o gateway disponibiliza ferramentas de descoberta, como search_actions e execute_action, em vez de uma ferramenta por API. Isso mantém pequena a lista de ferramentas do agente. Executando servidores MCP em um VPS aborda o lado do cliente dessa configuração.
Faça mais uma verificação antes de considerar o trabalho concluído. Repita a chamada da ação com o cabeçalho authorization removido. O quickstart do próprio projeto chama /v1 sem nenhum bearer. Portanto, uma instalação sem autenticação de execução configurada executará ações para qualquer pessoa que consiga alcançar a porta. Se a chamada sem autenticação for bem-sucedida, há duas opções: configurar tokens de execução e confirmar que a chamada anônima agora falha, ou restringir /api, /v1 e /mcp no proxy reverso aos endereços de onde seus agentes se conectam. Somente /oauth/callback precisa permanecer aberto para o mundo, porque esse é o único caminho necessário para o redirecionamento do navegador do provedor.
Reduza a lista de ações ao necessário para o agente
Um gateway com mil provedores disponíveis oferece uma superfície ampla demais para um modelo de linguagem. Dois controles a reduzem.
OOMOL_CONNECT_ALLOWED_ACTIONS recebe uma lista de permissões separada por vírgulas e entende service.* e *. OOMOL_CONNECT_BLOCKED_ACTIONS é a lista de bloqueios, e ela tem prioridade. Definir a lista de permissões como github.get_current_user,github.list_issues faz com que todas as outras ações sejam recusadas, independentemente do que o agente solicitar. Essa é a diferença entre um erro e um incidente. Os tokens de execução têm suas próprias regras de ação, além das regras globais, e a lista allowedProxies começa vazia. Portanto, POST /v1/proxy/:service é recusada até que você a autorize. Esse endpoint de proxy encaminha uma solicitação bruta a um provedor com sua credencial anexada. Mantenha-o vazio, a menos que um agente específico precise dele.
OOMOL_CONNECT_ALLOW_PRIVATE_NETWORK usa false por padrão. Isso impede que uma conexão com um provedor auto-hospedado aponte para um endereço privado, como o serviço de metadados da nuvem em 169.254.169.254 ou seu banco de dados na mesma rede. Mantenha-o desativado. Ative-o somente para um provedor hospedado por você.
Fazer backup do servidor que armazena todos os tokens
Duas coisas importam, e cada uma é inútil sem a outra. O banco de dados em /app/data/connect.sqlite, dentro do volume connector-data, armazena as credenciais protegidas. A chave de criptografia em .env as desbloqueia. Um backup do volume sem a chave não restaura nada, e a chave sem o volume também não restaura nada. Portanto, armazene a chave no gerenciador de senhas e inclua o volume na rotação normal de backups.
Pare o container enquanto copia o arquivo SQLite, porque uma cópia feita durante uma gravação pode ser restaurada como um banco de dados corrompido.
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 connectorO nome do volume é o diretório do projeto seguido de _connector-data. Por isso o primeiro comando está incluído: cole o nome real no terceiro comando. Envie o arquivo compactado para fora do VPS usando backups restic de um VPS, que o criptografa antes de transmiti-lo, porque esse arquivo é o armazenamento de credenciais.
O runtime mantém as execuções recentes como registros de auditoria, 5,000 por padrão. Assim, o console pode informar qual agente executou cada ação e quando. Esse log é a primeira coisa a consultar quando um agente se comporta de forma estranha. Aponte uma página de status do Uptime Kuma também para https://connect.example.com/health. Quando o gateway deixa de responder, os agentes falham de maneiras confusas. Saber que o gateway está indisponível economiza uma hora de análise da saída dos agentes.
O que falha e qual mensagem você verá
redirect_uri_mismatch no provedor. A origem e a URL de callback registrada são diferentes. Compare a string exata de /api/oauth/configs com as configurações do aplicativo no provedor, incluindo https e http e qualquer barra final.
Toda chamada /api retorna 401. O cabeçalho do token de administrador está ausente ou foi escrito incorretamente. O cabeçalho é Authorization: Bearer <token>, e o console web solicita o mesmo token.
O contêiner é executado, e as credenciais ficam em texto simples. Isso acontece quando OOMOL_CONNECT_ENCRYPTION_KEY nunca chega ao contêiner, porque o runtime armazena os registros de credenciais sem criptografia em vez de impedir a inicialização. Comprove isso na sua própria instalação: conecte um provedor usando uma chave de API que você consiga identificar e pesquise esse valor no banco de dados.
docker compose cp connector:/app/data/connect.sqlite /tmp/connect.sqlite
grep -c 'github_pat_' /tmp/connect.sqlite
shred -u /tmp/connect.sqliteUma contagem acima de 0 significa que a chave não está em vigor. Verifique se .env está no mesmo diretório que compose.yaml e se docker compose config exibe o valor. Com a chave configurada, a mesma pesquisa retorna 0, porque o registro está protegido com AES-256-GCM (advanced encryption standard, chave de 256 bits, modo Galois/counter).
Nada é descriptografado depois de uma restauração. A chave de criptografia mudou ou foi perdida. Por projeto, ela nunca é gravada junto aos dados. Portanto, não há caminho de recuperação e nenhum chamado de suporte resolverá o problema. Reconecte todos os provedores. A rotação é compatível por meio de uma variável de chave separada e de um comando de dados no runtime. Leia as notas da versão atual antes de fazer qualquer rotação.
O agente retorna um erro mencionando uma ação que ele consegue ver no catálogo. A descoberta e a execução são separadas. Uma ação pode aparecer em search_actions e ainda assim ser recusada por OOMOL_CONNECT_ALLOWED_ACTIONS, pela denylist ou pelas próprias regras do token desse runtime.
Atualizações. Faça backup do volume, edite a tag da imagem para a nova versão e execute docker compose pull && docker compose up -d. Monitore docker compose logs -n 50 connector em busca de uma linha de migração e execute novamente a verificação de integridade e uma ação real antes de voltar a confiar no sistema. Para fazer rollback, restaure a tag antiga. Isso funciona somente porque você a fixou.
FAQ
Preciso de um domínio público para hospedar o Open Connector por conta própria?
Para provedores que usam uma chave de API, não: um gateway em 127.0.0.1 é suficiente. Para OAuth, na prática, sim. O provedor redireciona um navegador para a sua URL de callback. Portanto, essa URL precisa ser resolvida pela internet pública, e os provedores recusam http:// simples fora do localhost. Defina OOMOL_CONNECT_ORIGIN como o hostname https:// antes da primeira inicialização e registre <origin>/oauth/callback no aplicativo OAuth do provedor.
O que acontece se eu perder a chave de criptografia do Open Connector?
As credenciais armazenadas não poderão ser descriptografadas, e não existe recuperação. A chave deliberadamente nunca é armazenada junto com os dados. Portanto, ninguém que tenha o banco de dados poderá lê-la, inclusive você. A única opção é definir uma nova chave e reconectar todos os provedores. Mantenha a chave em um gerenciador de senhas e o banco de dados na sua rotina de backups, porque uma restauração precisa dos dois.
Meu agente de IA pode ver o token de acesso do provedor?
Não quando ele faz chamadas pelo gateway. O agente se autentica com um token de execução que começa com oct_, e o gateway insere a credencial do provedor na requisição de saída no servidor, retornando apenas a resposta. Duas situações quebram essa propriedade: o endpoint /v1/proxy/:service, que encaminha requisições brutas com a sua credencial anexada e cujas concessões começam vazias por um motivo; e colar uma chave de API no próprio agente, ignorando completamente o gateway.
O gateway deve ser acessível pela internet pública?
Somente /oauth/callback precisa ser. Publique a porta do container em 127.0.0.1 para que as regras de NAT do Docker não possam expô-la além do firewall, e coloque o proxy reverso na frente. Em seguida, teste uma chamada de ação sem o cabeçalho authorization. Se funcionar, restrinja /api, /v1 e /mcp no proxy aos endereços usados pelos seus agentes, até que apenas chamadas autenticadas funcionem.
O Open Connector está pronto para uso em produção?
Ele é licenciado sob Apache 2.0 e está evoluindo rapidamente: o repositório apareceu em 29 June 2026 e a v1.3.3 foi lançada em 30 July 2026. Portanto, trate cada número de versão deste guia como um instantâneo de 1 August 2026. Execute-o fixado em uma tag de release, nunca em latest ou tip, leia as notas da release antes de cada atualização e mantenha um backup do volume que você já tenha restaurado uma vez. O design é sólido para um servidor sob seu controle. O risco está na mudança frequente das versões, não na arquitetura.