Aloja Open Connector para agentes de IA
Ejecuta Open Connector en tu VPS para que tus agentes no guarden tokens SaaS: imagen fijada, TLS de origen, callbacks OAuth y copias de seguridad.
Qué hace Open Connector para un agente de IA
Alojar Open Connector en su propia infraestructura coloca una única puerta de enlace de autenticación entre sus agentes de IA y cada API de software como servicio (SaaS) que utilizan, de modo que el agente nunca almacena un token del proveedor. Es una puerta de enlace de código abierto de OOMOL Lab, con licencia Apache 2.0. Se ejecuta como un contenedor, almacena su estado en un único archivo SQLite y expone las acciones de los proveedores mediante HTTP y MCP (protocolo de contexto del modelo).
El problema empieza con la segunda integración. Cada proveedor tiene su propio flujo de OAuth (autorización abierta), su propio tiempo de vida para los tokens de actualización y sus propios nombres de ámbito. Integrar manualmente cinco proveedores en un agente implica cinco controladores de redirección, cinco almacenes de credenciales y cinco ciclos de renovación que deben ejecutarse antes de que caduque un token. Casi nadie escribe ese código. En su lugar, generan un token de acceso personal de larga duración para cada servicio y lo pegan en la configuración del agente, en un archivo de entorno o en el propio prompt. Entonces, todas las herramientas que ejecuta el agente pueden leer ese token, y este termina en la transcripción. Ese es el fallo que describe mantener los secretos fuera de los agentes de IA.
Una puerta de enlace de autenticación divide la credencial en dos. La puerta de enlace almacena la credencial del proveedor y ejecuta el flujo de OAuth. El agente recibe un token de tiempo de ejecución que sólo es válido frente a la puerta de enlace. Cuando el agente llama a una acción, la puerta de enlace carga la credencial almacenada, la inyecta en la solicitud saliente en el servidor y devuelve únicamente el cuerpo de la respuesta. El agente nunca recibe el token de acceso del proveedor. Por tanto, si se filtra la transcripción del agente, el coste es un único token de tiempo de ejecución revocable, no la cuenta de GitHub.
El catálogo anuncia más de 1,000 proveedores y 10,000 acciones predefinidas. Esa cifra procede del propio proyecto y no se puede verificar desde el exterior. Lo que sí se puede verificar es la estructura: un endpoint HTTP por acción, una conexión almacenada por proveedor y un token por agente.
Por qué alojar Open Connector en lugar de usar un servicio de conectores alojado
Un servicio de conectores alojado hace el mismo trabajo y almacena los tokens de actualización de cada proveedor que conectes. Un token de actualización de Google o GitHub es una credencial de larga duración para acceder a tu correo y tus repositorios, y normalmente sigue siendo válido después de cambiar la contraseña. Si ese servicio sufre una intrusión, tú también quedas expuesto. El alojamiento propio guarda esos registros en SQLite, en una máquina que alquilas y administras, protegidos con una clave que nunca sale de tu servidor.
Calcula el coste antes de empezar. Este VPS se convierte en el servidor más valioso que administras. Contiene las credenciales activas de una docena de servicios en un solo archivo, por lo que debes protegerlo como protegerías un servidor que aloja un gestor de contraseñas: un firewall que sólo exponga 443, ninguna cuenta compartida, una copia de seguridad que hayas restaurado al menos una vez y una alerta si deja de responder. Si no guardarías tu bóveda de contraseñas en este servidor, tampoco alojes aquí el conector.
Fije una versión antes de instalar nada
Open Connector es un proyecto reciente. El repositorio apareció por primera vez el 29 de junio de 2026 y, a fecha de 1 de agosto de 2026, la versión etiquetada más reciente es v1.3.3, publicada el 30 de julio de 2026 y con la etiqueta latest. El registro también publica una etiqueta tip, creada a partir del commit más reciente de main.
En un proyecto tan reciente, las etiquetas móviles cambian con frecuencia. Un docker compose pull que salta dos versiones puede cambiar un endpoint del que depende su agente, y pasará la tarde depurando el problema como si fuera un fallo del agente. Fije la imagen a una etiqueta de versión y actualícela cuando lo decida, después de leer las notas de la versión.
Implementar Open Connector detrás de TLS en su propio VPS
Antes de iniciar el contenedor, necesita:
- Docker con el plugin Compose, en Ubuntu 24.04 o una versión similar
- un nombre de host cuyo registro A apunte a este VPS, por ejemplo
connect.example.com - un reverse proxy que ya termine TLS (transport layer security) para ese nombre de host
- dos secretos aleatorios, que se generan a continuación
La guía Reverse proxy Traefik para varias aplicaciones Docker Compose cubre la configuración del proxy. La misma configuración de certificados, de principio a fin para una sola aplicación, se encuentra en la guía n8n en un VPS con Docker y HTTPS.
Genere primero los secretos. La clave de cifrado protege las credenciales almacenadas. El token de administrador protege la consola web y toda la superficie /api. Ninguno tiene un valor predeterminado, y el runtime se inicia correctamente aunque no estén definidos.
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 ahora ambos valores en su gestor de contraseñas, antes del primer inicio. La clave de cifrado no se puede recuperar. El motivo se explica en la lista de fallos más adelante.
Ahora compose.yaml. Difiere del ejemplo del proyecto original en dos puntos, y ambos son 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:El primer cambio es la etiqueta fijada en lugar de latest. El segundo es el puerto. El archivo original publica 3000:3000, que enlaza todas las interfaces del host. Docker escribe los puertos publicados en la tabla NAT (network address translation) antes de que el paquete llegue a la cadena de filtrado de ufw. Por eso, ufw deny 3000 no cierra ese puerto. Esta es la situación descrita en por qué los puertos de Docker omiten ufw. Escribir 127.0.0.1:3000:3000 publica el puerto sólo en la interfaz de loopback, y el reverse proxy se conecta desde el mismo host.
:? marca cada variable como obligatoria. Por eso, el stack no se inicia si falta .env, en lugar de iniciarse con las credenciales sin cifrar. Mantener los valores en .env, en vez de incluirlos en el archivo Compose, sigue el patrón de archivos env y secretos de 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 } cuando el runtime está activo. ss debe mostrar 127.0.0.1:3000. Una línea que muestre 0.0.0.0:3000 indica que la asignación de puertos sigue siendo la del proyecto original y que el gateway responde directamente a todo Internet. Si la comprobación de estado devuelve «connection refused», el contenedor todavía no está escuchando. Revise los logs antes de modificar el proxy.
Etiquetas de Traefik para el mismo servicio
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"Cuando Traefik se ejecuta en Docker en el mismo host, conecte este servicio a la red de Traefik y elimine el bloque ports:. Traefik llega al contenedor a través de la red interna y no es necesario publicar ningún puerto en el host. certresolver=le debe coincidir con el nombre del resolver en la configuración estática de Traefik. De lo contrario, el router se inicia sin certificado.
Por qué OAuth obliga a usar un nombre de host real
OOMOL_CONNECT_ORIGIN es el ajuste que se suele omitir, y omitirlo rompe OAuth de una forma que parece un fallo del proveedor. El runtime construye la URI de redirección a partir de ese origen, con el formato <origin>/oauth/callback. Si no se establece, el origen toma el valor predeterminado http://localhost:3000. Por eso, el runtime envía al proveedor una URI de redirección http://localhost:3000/oauth/callback, mientras la aplicación OAuth tiene registrada https://connect.example.com/oauth/callback. Las dos cadenas son diferentes, así que GitHub responde:
The redirect_uri MUST match the registered callback URL for this application.Un proveedor OAuth redirige el navegador a esa URI. Por tanto, debe ser una dirección accesible desde Internet. Los proveedores rechazan http:// sin cifrado para cualquier destino que no sea localhost. Esta es la razón por la que esta implementación necesita un nombre de host y un certificado. Establezca el origen antes del primer arranque, porque el valor se lee al iniciar. Después de editar .env o compose.yaml, vuelva a ejecutar docker compose up -d para aplicarlo.
Conecte su primer proveedor mediante OAuth
Cree primero la aplicación OAuth en el proveedor. En GitHub, la ruta es Settings, después Developer settings, luego OAuth Apps y, por último, New OAuth App. Establezca la URL de devolución de autorización en https://connect.example.com/oauth/callback. Guarde el client ID y el client secret.
Cada llamada a /api incluye el token de administrador, así que expórtelo una vez para la sesión del shell.
export ADMIN_TOKEN='paste-the-admin-token'
curl -s https://connect.example.com/api/oauth/configs \
-H "authorization: Bearer $ADMIN_TOKEN"Ese listado muestra el URI de redirección que el runtime espera para cada proveedor. Es la comprobación más rápida de que el origen se ha aplicado. Si todavía muestra localhost, el contenedor se está ejecutando con el valor anterior y el flujo OAuth fallará en el último paso.
Guarde las credenciales del cliente y, después, inicie una autorización.
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 segunda llamada devuelve un authorizationUrl. Ábralo en un navegador, apruebe los ámbitos y el proveedor devolverá el navegador a /oauth/callback. Allí, el runtime intercambia el código y guarda la credencial. La consola web de su origen sigue los mismos pasos mediante un formulario, protegido por el mismo token de administrador. Los proveedores que utilizan una clave de API simple omiten todo esto: PUT /api/connections/<service> con {"authType":"api_key","values":{"apiKey":"..."}} guarda la clave directamente.
Asigne a token de ejecución a cada agente, nunca la credencial
El agente se autentica en la puerta de enlace con un token de ejecución, que la API de administración genera.
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 respuesta incluye un token que comienza por oct_. Emita un token por agente y asígnele el nombre de ese agente, porque revocar un token que no puede identificar implica revocarlos todos. Después, el agente llama a las acciones mediante 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":{}}'Una respuesta correcta es una envoltura cuyo campo success tiene el valor true, con la carga útil del proveedor en data. El token de GitHub no aparece en ningún lugar de esa respuesta. Para un cliente MCP, configúrelo para usar https://connect.example.com/mcp con la misma cabecera bearer. La puerta de enlace ofrece herramientas de descubrimiento como search_actions y execute_action, en lugar de una herramienta por API. Esto mantiene reducida la lista de herramientas del agente. Ejecutar servidores MCP en un VPS explica la parte del cliente de esta configuración.
Realice una comprobación más antes de darlo por terminado. Repita la llamada a la acción después de eliminar la cabecera authorization. La guía de inicio rápido del proyecto llama a /v1 sin ningún bearer, por lo que una instalación sin autenticación de ejecución configurada ejecutará acciones para cualquiera que pueda acceder al puerto. Si la llamada sin autenticación tiene éxito, tiene dos opciones: configurar tokens de ejecución y confirmar que la llamada anónima falla, o restringir /api, /v1 y /mcp en el proxy inverso a las direcciones desde las que se conectan los agentes. Sólo /oauth/callback debe permanecer abierto al mundo, porque es la única ruta que necesita la redirección del navegador del proveedor.
Reducir la lista de acciones a lo que necesita el agente
Un gateway con mil proveedores detrás expone una superficie amplia a un modelo de lenguaje. La superficie aumenta en cuanto el modelo empieza a leer texto que no ha generado, porque una página devuelta por su propia instancia de SearXNG que responde a las búsquedas web del agente puede contener instrucciones dirigidas a cualquiera de las acciones que el agente tenga disponibles. La misma moderación que hace que un agente de programación aplique el cambio mínimo que funciona también debe aplicarse a sus permisos: conceda sólo las pocas acciones que el trabajo necesita y ninguna más. Hay dos controles que permiten reducirlos.
OOMOL_CONNECT_ALLOWED_ACTIONS acepta una lista de permitidos separada por comas y admite service.* y *. OOMOL_CONNECT_BLOCKED_ACTIONS es la lista de denegados, y esta tiene prioridad. Establecer la lista de permitidos en github.get_current_user,github.list_issues significa que se rechaza cualquier otra acción, independientemente de lo que solicite el agente. Esa es la diferencia entre un error y un incidente. Los tokens de ejecución tienen sus propias reglas de acciones además de las globales, y su lista allowedProxies empieza vacía, por lo que POST /v1/proxy/:service se rechaza hasta que se concede explícitamente. Ese endpoint del proxy reenvía una solicitud sin modificar a un proveedor con sus credenciales adjuntas. Déjelo vacío salvo que un agente concreto lo necesite.
OOMOL_CONNECT_ALLOW_PRIVATE_NETWORK tiene el valor predeterminado false. Esto impide que una conexión con un proveedor autohospedado apunte a una dirección privada, como el servicio de metadatos de la nube en 169.254.169.254 o la base de datos de la misma red. Déjelo desactivado. Actívelo sólo para un proveedor que aloje usted mismo.
Haga una copia de seguridad del servidor que contiene todos los tokens
Hay dos elementos importantes, y cada uno es inútil sin el otro. La base de datos ubicada en /app/data/connect.sqlite dentro del volumen connector-data contiene las credenciales selladas. La clave de cifrado ubicada en .env las descifra. Una copia de seguridad del volumen sin la clave no restaura nada, y la clave sin el volumen tampoco restaura nada. Por eso, la clave debe guardarse en el gestor de contraseñas y el volumen debe incluirse en la rotación normal de copias de seguridad.
Detenga el contenedor mientras copia el archivo SQLite, porque una copia realizada durante una escritura puede restaurar una base de datos dañada.
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 connectorEl nombre del volumen es el directorio del proyecto más _connector-data. Por eso se incluye el primer comando: pegue el nombre real en el tercero. Envíe el archivo fuera del VPS con copias de seguridad de restic desde un VPS. restic lo cifra antes de transferirlo, porque ese archivo es el almacén de credenciales.
El entorno de ejecución conserva las ejecuciones recientes como registros de auditoría, 5,000 de forma predeterminada. Así, la consola puede indicar qué agente ejecutó cada acción y cuándo. Ese registro es lo primero que debe revisar cuando un agente se comporta de forma extraña. Configure también una página de estado de Uptime Kuma para https://connect.example.com/health. Cuando la puerta de enlace deja de responder, los agentes fallan de formas confusas. Saber que la puerta de enlace está caída evita dedicar una hora a revisar la salida de los agentes.
Qué falla y qué mensaje verá
redirect_uri_mismatch en el proveedor. El origen y la URL de callback registrada no coinciden. Compare la cadena exacta de /api/oauth/configs con la configuración de la aplicación en el proveedor, incluido https frente a http y cualquier barra final.
Todas las llamadas a /api devuelven 401. Falta la cabecera del token de administrador o está mal escrita. La cabecera es Authorization: Bearer <token>, y la consola web solicita el mismo token.
El contenedor se ejecuta y las credenciales quedan en texto plano. Esto ocurre cuando OOMOL_CONNECT_ENCRYPTION_KEY nunca llega al contenedor, porque el runtime almacena los registros de credenciales sin cifrar en lugar de negarse a iniciar. Compruébelo en su propia instalación: conecte un proveedor con una API key que pueda reconocer y busque esa clave en la base de datos.
docker compose cp connector:/app/data/connect.sqlite /tmp/connect.sqlite
grep -c 'github_pat_' /tmp/connect.sqlite
shred -u /tmp/connect.sqliteUn recuento superior a 0 significa que la clave no está activa. Compruebe que .env esté en el mismo directorio que compose.yaml y que docker compose config muestre el valor. Con la clave configurada, la misma búsqueda devuelve 0, porque el registro está protegido con AES-256-GCM (advanced encryption standard, clave de 256 bits, modo Galois/counter).
Nada se descifra después de una restauración. La clave de cifrado cambió o se perdió. Por diseño, nunca se escribe junto a los datos, por lo que no existe una vía de recuperación ni un ticket de soporte que lo solucione. Vuelva a conectar todos los proveedores. La rotación se admite mediante una variable de clave independiente y un comando de datos en el runtime, así que lea las notas de la versión actual antes de rotar nada.
El agente devuelve un error que menciona una acción visible en el catálogo. El descubrimiento y la ejecución son operaciones independientes. Una acción puede aparecer en search_actions y aun así ser rechazada por OOMOL_CONNECT_ALLOWED_ACTIONS, por la denylist o por las reglas propias del token de ese runtime.
Actualizaciones. Haga una copia de seguridad del volumen, cambie el tag de la imagen por el de la nueva versión y, a continuación, docker compose pull && docker compose up -d. Supervise docker compose logs -n 50 connector para detectar una línea de migración y vuelva a ejecutar la comprobación de estado y una acción real antes de volver a confiar en el sistema. Para revertir la actualización, vuelva a poner el tag antiguo. Esto funciona sólo porque lo fijó.
FAQ
¿Necesito un dominio público para alojar Open Connector?
Para los proveedores que usan una clave de API, no: basta con una gateway en 127.0.0.1. Para OAuth, en la práctica sí. El proveedor redirige un navegador a la URL de callback, por lo que esa URL debe resolverse desde Internet público, y los proveedores rechazan http:// sin cifrar fuera de localhost. Establezca OOMOL_CONNECT_ORIGIN en el nombre de host https:// antes del primer arranque y registre <origin>/oauth/callback en la aplicación OAuth del proveedor.
¿Qué ocurre si pierdo la clave de cifrado de Open Connector?
Las credenciales almacenadas no se pueden descifrar y no existe ningún método de recuperación. La clave nunca se almacena junto con los datos de forma deliberada, por lo que nadie que tenga la base de datos puede leerla, incluido usted. La única opción es establecer una clave nueva y volver a conectar todos los proveedores. Guarde la clave en un gestor de contraseñas e incluya la base de datos en la rotación de copias de seguridad, porque una restauración necesita ambos elementos.
¿Puede mi agente de IA ver el token de acceso del proveedor?
No cuando realiza las llamadas a través de la gateway. El agente se autentica con un token de tiempo de ejecución que empieza por oct_, y la gateway inyecta la credencial del proveedor en la petición saliente en el servidor y devuelve sólo la respuesta. Dos situaciones rompen esta propiedad: el endpoint /v1/proxy/:service, que reenvía peticiones sin modificar con la credencial adjunta y cuyos permisos empiezan vacíos por un motivo, y pegar usted mismo una clave de API en el agente, lo que omite por completo la gateway.
¿Debe poder accederse a la gateway desde Internet público?
Sólo /oauth/callback debe estar accesible. Publique el puerto del contenedor en 127.0.0.1 para que las reglas NAT de Docker no puedan exponerlo más allá del firewall y coloque el reverse proxy delante. Después, pruebe una llamada de acción sin la cabecera authorization. Si funciona, restrinja /api, /v1 y /mcp en el proxy a las direcciones que usan sus agentes, hasta que sólo funcionen las llamadas autenticadas.
¿Está Open Connector listo para uso en producción?
Tiene licencia Apache 2.0 y evoluciona rápidamente: el repositorio apareció el 29 de junio de 2026 y v1.3.3 se publicó el 30 de julio de 2026, por lo que debe tratar cada número de versión de esta guía como una instantánea del 1 de agosto de 2026. Ejecútelo fijado a una etiqueta de release, nunca en latest ni en tip, lea las notas de la release antes de cada actualización y conserve una copia de seguridad de un volumen que haya restaurado al menos una vez. El diseño es sólido para un equipo que administra usted; el riesgo está en la rotación de versiones, no en la arquitectura.