SSD Nodes Learn Hosting plans →
Guias Matt ConnorPor Matt Connor

Hospede o Open Connector para agentes de IA

Execute o gateway OAuth do Open Connector no seu VPS, com imagem fixada, origem TLS, callbacks OAuth e backups do SQLite, sem expor tokens SaaS aos agentes.

O que o Open Connector faz por um agente de IA

A utilização autónoma do Open Connector coloca um gateway de autenticação entre os seus agentes de IA e todas as APIs de software como serviço (SaaS) que estes chamam. Assim, o agente nunca armazena um token do fornecedor. É um gateway com código disponível de forma limitada, desenvolvido pelo OOMOL Lab, atualmente licenciado ao abrigo de uma licença Apache 2.0 modificada, com condições adicionais. As releases até à v1.9.4 permanecem sob a licença Apache 2.0; a v1.9.5 introduziu a alteração. A disponibilização de um serviço alojado ou gerido cujo valor principal seja a funcionalidade do OpenConnector requer uma licença comercial da OOMOL. O serviço é executado num único contentor, mantém o estado num único ficheiro SQLite e expõe ações dos fornecedores através de HTTP e de MCP (model context protocol).

O problema começa na segunda integração. Cada fornecedor tem o seu próprio fluxo OAuth (open authorization), a sua própria duração dos refresh tokens e os seus próprios nomes de scopes. Integrar manualmente cinco fornecedores num agente significa criar cinco handlers de redirecionamento, cinco repositórios de credenciais e cinco ciclos de renovação que têm de 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 colam-no na configuração do agente, num ficheiro de ambiente ou no próprio prompt. Esse token fica legível por todas as ferramentas executadas pelo agente e é incluído na transcrição. É esta a falha descrita em manter segredos fora dos agentes de IA.

Um gateway de autenticação separa a credencial em duas partes. O gateway armazena a credencial do fornecedor e executa o fluxo OAuth. O agente recebe um token de execução válido apenas para o gateway. Quando o agente chama uma ação, o gateway carrega a credencial armazenada, injeta-a no pedido de saída no lado do servidor e devolve apenas o corpo da resposta. O agente nunca recebe o access token do fornecedor. Assim, se a transcrição do agente for divulgada, o custo é um único token de execução revogável, e não a sua conta do GitHub.

O catálogo anuncia mais de 1,000 fornecedores e 10,000 ações pré-criadas. Estes valores são apresentados pelo próprio projeto e não podem ser verificados externamente. O que pode ser verificado é a estrutura: um endpoint HTTP por ação, uma ligação armazenada por fornecedor e um token por agente. Se a parte relacionada com agentes ainda for nova e termos como tool call ou MCP server ainda não estiverem estabilizados, o percurso faseado em como aprender agentes de IA do zero explica o ciclo, as ferramentas e as práticas de segurança que um gateway deste tipo pressupõe que já conhece.

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 refresh tokens de todos os provedores que liga a ele. Um refresh token do Google ou do GitHub é uma chave de longa duração para o seu correio e os seus repositórios. Se o serviço for comprometido, os seus dados também ficam comprometidos. Ao hospedar o serviço por conta própria, esses registos passam para uma base de dados SQLite numa máquina que você aluga e administra, protegidos por uma chave que nunca sai do seu servidor.

Considere o custo real antes de começar. Este VPS passa a ser o servidor mais valioso que você administra. Ele armazena as credenciais funcionais de uma dúzia de serviços num único ficheiro. Por isso, deve receber o mesmo tratamento que um servidor de gestor de palavras-passe: uma firewall que expõe apenas a porta 443, nenhuma conta partilhada, uma cópia de segurança que você já tenha restaurado pelo menos uma vez e um alerta quando o servidor deixar de responder. Se não colocaria o seu cofre de palavras-passe neste servidor, também não coloque o conector nele.

Fixe uma versão antes de instalar qualquer componente

O Open Connector é recente. Este guia mantém a v1.3.3, publicada em 30 July 2026, fixada como o snapshot de instalação de 1 August 2026. Esta já não é a versão mais recente. O registry também publica uma tag tip, criada a partir do commit mais recente em main.

Num 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 de que o seu agent depende, e passará a noite a investigar o problema como se fosse uma falha do agent. Fixe a imagem numa tag de release e faça o upgrade quando decidir, depois de ler as notas da release.

Implemente o Open Connector atrás de TLS no seu próprio VPS

Antes de iniciar o contentor, precisa de:

  • Docker Engine 28.0.0 ou mais recente, com o plugin Compose, no Ubuntu 24.04 ou numa versão próxima
  • um hostname cujo registo A aponte para este VPS, por exemplo connect.example.com
  • um reverse proxy que já faça a terminação TLS (transport layer security) para esse hostname
  • dois segredos aleatórios, gerados abaixo

O guia reverse proxy Traefik para várias aplicações Docker Compose cobre a configuração do proxy. A configuração dos certificados, do início ao fim para uma única aplicação, está no guia n8n num VPS com Docker e HTTPS.

Gere primeiro os segredos. A chave de encriptação protege as credenciais armazenadas. O token de administrador protege a consola Web e toda a superfície /api. Nenhum dos dois tem um valor predefinido, 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 .env

Copie já ambos os valores para o seu gestor de palavras-passe, antes do primeiro arranque. A chave de encriptação não tem recuperação, e o motivo está na lista de falhas mais abaixo.

Agora compose.yaml. 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 é a tag fixada em vez de latest. A segunda é a porta. O ficheiro upstream publica 3000:3000, que faz bind em todas as interfaces do host. O Docker escreve as portas publicadas na tabela NAT (network address translation) antes de o pacote passar pela cadeia de filtragem do ufw, por isso ufw deny 3000 não fecha essa porta. Esta é a armadilha descrita em por que motivo as portas do Docker ignoram o ufw. Escrever 127.0.0.1:3000:3000 publica apenas na interface de loopback, e o reverse proxy liga-se a partir do mesmo host. Antes do Docker Engine 28.0.0, hosts no mesmo segmento L2 conseguiam alcançar portas publicadas no localhost. Por isso, este guia exige a versão 28.0.0 ou mais recente.

O :? marca cada variável como obrigatória, por isso a stack recusa iniciar quando .env está em falta, em vez de iniciar com as credenciais sem encriptação. Manter os valores em .env, em vez de no ficheiro Compose, segue o padrão descrito em ficheiros env e segredos do Docker Compose. Mantenha /v1 e /mcp privados no reverse proxy até criar o primeiro token de runtime abaixo.

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 a { "ok": true } quando o runtime estiver ativo. ss tem de apresentar 127.0.0.1:3000. Uma linha com 0.0.0.0:3000 significa que o listener está associado a todas as interfaces IPv4, mas não prova que seja alcançável a partir da Internet: firewalls upstream ou regras na cadeia DOCKER-USER do Docker ainda podem bloquear o tráfego externo. Uma ligação recusada no health check significa que o contentor ainda não está a escutar, por isso consulte os logs antes de alterar o proxy.

Labels 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 corre no Docker no mesmo host, associe este serviço à rede do Traefik e elimine o bloco ports:, porque o Traefik alcança o contentor através da rede interna e não é necessário publicar nada no host. certresolver=le tem de corresponder ao nome do resolver na configuração estática do Traefik. Caso contrário, o router é iniciado sem certificado.

Por que os callbacks OAuth precisam da origem correta

OOMOL_CONNECT_ORIGIN é a configuração que muitas pessoas ignoram, e ignorá-la faz o OAuth falhar 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. Quando não é definida, a origem assume http://localhost:3000 por padrão. Assim, o runtime envia ao provedor um URI de redirecionamento http://localhost:3000/oauth/callback, enquanto a sua aplicação OAuth tem https://connect.example.com/oauth/callback registrado. As duas strings são diferentes, por isso 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 o endereço precisa estar acessível a esse navegador. O OAuth não exige universalmente um hostname público: o OpenConnector documenta callbacks do GitHub em http://localhost:3000/oauth/callback. Esta implementação em um VPS usa um hostname e um certificado para que o navegador alcance o gateway pela sua origem HTTPS. 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 o primeiro provider por OAuth

Crie primeiro a aplicação OAuth no provider. 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 /api inclui o token de administrador, por isso exporte-o uma vez para a sessão da 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 provider. É a forma mais rápida de confirmar que a origem foi aplicada. Se ainda indicar localhost, o container está a executar com o valor antigo e o fluxo OAuth falhará no último passo.

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 devolve um authorizationUrl. Abra-o num browser, aprove os scopes e o provider redirecionará o browser para /oauth/callback. Nesse ponto, o runtime troca o código e armazena a credencial. A consola web na sua origem executa os mesmos passos através de um formulário, usando o mesmo token de administrador. Os providers que usam uma API key simples ignoram todo este processo: PUT /api/connections/<service> com {"authType":"api_key","values":{"apiKey":"..."}} armazena a chave diretamente.

Dê a cada agente um token de runtime, nunca a credencial

O agente autentica-se no gateway com um token de runtime, que a API de administração gera.

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 por oct_. Emita um token por agente e atribua-lhe o nome desse agente, porque revogar um token que não consegue identificar significa revogar todos. Em seguida, o agente chama as ações por HTTP normal.

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 saudável é um envelope cujo campo success tem o valor true, com o payload do fornecedor em data. O token do GitHub não aparece em nenhum ponto dessa resposta. Num cliente MCP, aponte-o para https://connect.example.com/mcp com o mesmo cabeçalho bearer. O gateway disponibiliza ferramentas de descoberta, como search_actions e execute_action, em vez de uma ferramenta por API. Isto mantém reduzida a lista de ferramentas do agente. Executar servidores MCP numa VPS aborda a parte do cliente dessa configuração.

Faça mais uma verificação antes de considerar o trabalho concluído. Repita a chamada da ação depois de eliminar o cabeçalho authorization. O quickstart do próprio projeto chama /v1 sem qualquer bearer. Portanto, uma instalação sem autenticação de runtime configurada executará ações para qualquer pessoa que consiga aceder à porta. Se a chamada sem autenticação for bem-sucedida, há duas soluções: configurar tokens de runtime e confirmar que a chamada anónima passa a falhar; ou restringir /api, /v1 e /mcp no reverse proxy aos endereços de onde vêm os seus agentes. /oauth/callback tem de estar acessível pelo navegador que conclui a autorização. Não precisa de estar aberto à Internet inteira.

Reduza a lista de ações ao que o agente precisa

Um gateway com mil provedores por trás oferece uma superfície ampla para um modelo de linguagem. Essa superfície aumenta assim que o modelo começa a ler texto que não escreveu, porque uma página devolvida pela sua própria instância SearXNG que responde às pesquisas web do agente pode conter instruções destinadas às ações disponíveis para o agente. A mesma contenção que faz um agente de programação aplicar a menor alteração funcional também deve ser usada nas permissões: conceda apenas o conjunto reduzido de ações de que a tarefa realmente precisa, sem nada além disso. Há dois controlos para limitar esse acesso.

OOMOL_CONNECT_ALLOWED_ACTIONS aceita uma lista de permissões separada por vírgulas e compreende service.* e *. OOMOL_CONNECT_BLOCKED_ACTIONS é a lista de bloqueios, e a lista de bloqueios tem prioridade. Definir a lista de permissões como github.get_current_user,github.list_issues significa que todas as outras ações são recusadas, independentemente do que o agente solicitar. Essa é a diferença entre um erro e um incidente. Os tokens de runtime têm as suas próprias regras de ações, além das regras globais, e a lista allowedProxies começa vazia. Por isso, POST /v1/proxy/:service é recusada até que lhe conceda permissão. Esse endpoint de proxy encaminha uma solicitação bruta para um provedor com as suas credenciais anexadas. Deixe-o vazio, a menos que um agente específico precise dele.

OOMOL_CONNECT_ALLOW_PRIVATE_NETWORK assume o valor false. Isso impede que uma ligação a um provedor autoalojado aponte para um endereço privado, como o serviço de metadados da cloud em 169.254.169.254 ou a sua base de dados na mesma rede. Mantenha-o desativado. Ative-o apenas para um provedor que aloja sob o seu controlo.

Faça backup do servidor que armazena todos os tokens

Há duas coisas importantes, 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 seladas. A chave de encriptação em .env remove o selamento. Um backup do volume sem a chave não restaura nada, e a chave sem o volume também não restaura nada. Por isso, a chave deve ficar no seu gestor de palavras-passe, e o volume deve entrar na sua rotação normal de backups.

Pare o contentor enquanto copia o ficheiro SQLite. Uma cópia feita durante uma operação de escrita pode ser restaurada como uma base de dados corrompida.

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

O nome do volume é o diretório do projeto seguido de _connector-data. É por isso que o primeiro comando aparece aqui: cole o nome real no terceiro comando. Envie o arquivo para fora do VPS com backups restic a partir de um VPS. O restic encripta o arquivo antes de o enviar, porque esse arquivo é o repositório de credenciais.

O runtime mantém as execuções recentes das ações como registos de auditoria, 5,000 por padrão. Assim, a consola pode indicar qual agente executou cada ação e quando. Esse registo é o primeiro recurso a consultar quando um agente se comporta de forma estranha. Aponte também uma página de estado do Uptime Kuma para https://connect.example.com/health. Quando o gateway deixa de responder, os agentes falham de formas confusas. Saber que o gateway está indisponível poupa uma hora de análise da saída dos agentes.

O que falha e a mensagem apresentada

redirect_uri_mismatch no fornecedor. A origem e o URL de callback registado são diferentes. Compare a cadeia exata de /api/oauth/configs com as definições da aplicação no fornecedor, incluindo https e http e qualquer barra final.

Todas as chamadas /api devolvem 401. O cabeçalho do token de administrador está em falta ou foi escrito incorretamente. O cabeçalho é Authorization: Bearer <token>, e a consola web pede o mesmo token.

O contentor está em execução e as credenciais ficam em texto simples. Isto acontece quando OOMOL_CONNECT_ENCRYPTION_KEY nunca chega ao contentor, porque o runtime armazena os registos de credenciais sem encriptação em vez de recusar o arranque. Confirme isto na sua própria instalação: ligue um fornecedor com uma chave de API que consiga reconhecer e procure-a na base de dados.

docker compose cp connector:/app/data/connect.sqlite /tmp/connect.sqlite
grep -c 'github_pat_' /tmp/connect.sqlite
shred -u /tmp/connect.sqlite

Um valor superior a 0 significa que a chave não está em vigor. Confirme que .env está no mesmo diretório que compose.yaml e que docker compose config apresenta o valor. Com a chave definida, a mesma pesquisa devolve 0, porque o registo está protegido com AES-256-GCM (advanced encryption standard, chave de 256 bits, modo Galois/counter).

Nada é desencriptado depois de uma restauração. A chave de encriptação mudou ou foi perdida. Por conceção, nunca é escrita junto dos dados. Por isso, não existe um caminho de recuperação nem um pedido de suporte que resolva o problema. Ligue novamente todos os fornecedores. A rotação é suportada através de uma variável de chave separada e de um comando de dados no runtime. Consulte as notas da versão atual antes de rodar qualquer chave.

O agente apresenta um erro que identifica uma ação visível no catálogo. A descoberta e a execução são operações 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 desse token do runtime.

Atualizações. Faça uma cópia de segurança do volume, altere a tag da imagem para a nova versão e, em seguida, docker compose pull && docker compose up -d. Monitorize docker compose logs -n 50 connector à procura de uma linha de migração e volte a executar a verificação de estado e uma ação real antes de voltar a confiar no sistema. Reverter significa repor a tag antiga. Isto só funciona porque a fixou.

FAQ

Preciso de um domínio público para alojar o Open Connector?

Para fornecedores que usam uma API key, não: um gateway em 127.0.0.1 é suficiente. O OAuth também não exige universalmente um domínio público: a documentação do OpenConnector indica o callback local do GitHub como http://localhost:3000/oauth/callback. O browser que conclui a autorização tem de conseguir aceder ao URL de callback. Nesta implementação no VPS, defina OOMOL_CONNECT_ORIGIN como o hostname https:// antes do primeiro arranque e registe <origin>/oauth/callback na aplicação OAuth do fornecedor.

O que acontece se perder a chave de encriptação do Open Connector?

Não é possível desencriptar as credenciais armazenadas e não existe recuperação. A chave nunca é armazenada juntamente com os dados, de forma deliberada. Assim, ninguém que tenha a base de dados consegue lê-la, incluindo você. A única opção é definir uma chave nova e voltar a ligar todos os fornecedores. Guarde a chave num gestor de palavras-passe e inclua a base de dados na sua rotação de backups, porque uma reposição precisa de ambos.

O meu agente de IA consegue ver o token de acesso do fornecedor?

Não quando faz chamadas através do gateway. O agente autentica-se com um token de runtime que começa por oct_. O gateway injeta a credencial do fornecedor no pedido de saída no servidor e devolve apenas a resposta. Há duas situações que quebram esta proteção: o endpoint /v1/proxy/:service, que encaminha pedidos brutos com a sua credencial anexada e cujas permissões começam vazias por uma razão, e colar você próprio uma API key no agente, ignorando completamente o gateway.

O gateway deve estar acessível a partir da Internet pública?

O callback OAuth tem de estar acessível pelo browser que conclui a autorização. Isso não exige acesso a partir de toda a Internet. Com Docker Engine 28.0.0 ou mais recente e a rede bridge predefinida, publique a porta do contentor em 127.0.0.1 para manter a porta publicada acessível apenas a partir do host e coloque o reverse proxy à frente. As versões mais antigas do Docker permitiam que hosts no mesmo segmento L2 acedessem a portas publicadas em localhost. Teste depois uma chamada de ação sem o cabeçalho authorization. Se for bem-sucedida, restrinja /api, /v1 e /mcp no proxy aos endereços usados pelos seus agentes, até que apenas as chamadas autenticadas funcionem.

O Open Connector está pronto para utilização em produção?

As versões atuais usam uma licença Apache 2.0 modificada, com condições adicionais. As versões até à v1.9.4, incluindo a v1.3.3 fixada, continuam sob a licença Apache 2.0. Um serviço de connector alojado ou gerido cujo valor principal seja a funcionalidade do OpenConnector requer uma licença comercial da OOMOL ao abrigo da licença atual. Os comandos de instalação da v1.3.3 continuam a ser um snapshot de 1 August 2026, e essa versão foi lançada em 30 July 2026. Execute-a fixada numa release tag, nunca em latest ou tip, leia as release notes antes de cada upgrade e mantenha um backup do volume que tenha restaurado pelo menos uma vez. O desenho é adequado para uma máquina que você controla. O risco está na alteração frequente das versões, não na arquitetura.

Este artigo foi útil?

#ai-agents#oauth#self-hosting#integrations#source-available