Cómo alojar Open Connector para agentes de IA
Aloja Open Connector en tu VPS con una imagen fijada, origen TLS, callbacks OAuth y copias de seguridad, sin exponer tokens SaaS a tus agentes.
Qué hace Open Connector para un agente de IA
Alojar Open Connector por cuenta propia coloca una única puerta de enlace de autenticación entre los agentes de IA y todas las API de software como servicio (SaaS) que llaman. Así, 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 único contenedor, guarda su estado en un solo archivo SQLite y expone las acciones de los proveedores mediante HTTP y MCP (model context protocol).
El problema empieza con la segunda integración. Cada proveedor tiene su propio flujo OAuth (open authorization), su propio periodo de validez del refresh token 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 procesos de renovación que deben ejecutarse antes de que caduque un token. Casi nadie escribe ese código. En su lugar, generan un personal access token de larga duración para cada servicio y lo pegan en la configuración del agente, en un archivo de entorno o incluso en el prompt. Después, todas las herramientas que ejecuta el agente pueden leer ese token, y este queda incluido en la transcripción. Ese es el fallo que describe cómo 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 OAuth. El agente recibe un token 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 petición saliente desde el servidor y devuelve únicamente el cuerpo de la respuesta. El agente nunca recibe el access token del proveedor. Por tanto, si se filtra la transcripción del agente, el coste es un único token de ejecución revocable, no el control de 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 su estructura: un endpoint HTTP por acción, una conexión almacenada por proveedor y un token por agente. Si la parte relacionada con agentes todavía es nueva y términos como tool call o MCP server aún no están asentados, el recorrido gradual de cómo aprender sobre agentes de IA desde cero desarrolla el bucle, las herramientas y las prácticas de seguridad que una puerta de enlace como esta da por conocidas.
Por qué alojar Open Connector usted mismo en lugar de usar un servicio de conectores alojado
Un servicio de conectores alojado hace el mismo trabajo y conserva los tokens de actualización de cada proveedor al que lo conecta. Un token de actualización de Google o GitHub es una credencial de larga duración para acceder a su correo y a sus repositorios, y normalmente sigue siendo válido aunque cambie la contraseña. Si ese servicio sufre una brecha, usted también queda comprometido. El alojamiento propio guarda esos registros en SQLite, en una máquina que usted alquila y administra, protegidos con una clave que nunca sale de su servidor.
Evalúe el coste antes de empezar. Esta VPS se convierte en el servidor más valioso que administra. Contiene credenciales operativas de una docena de servicios en un solo archivo, por lo que requiere el mismo tratamiento que un servidor de un gestor de contraseñas: un firewall que sólo exponga 443, ninguna cuenta compartida, una copia de seguridad que haya restaurado al menos una vez y una alerta cuando deje de responder. Si no pondría su almacén de contraseñas en esta máquina, tampoco ponga aquí el conector.
Fija una versión antes de instalar cualquier cosa
Open Connector es un proyecto reciente. El repositorio apareció por primera vez el 29 de junio de 2026 y, al 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 avance dos versiones puede cambiar un endpoint del que depende el agente, y acabarás dedicando la tarde a depurarlo como si fuera un problema del agente. Fija la imagen a una etiqueta de versión y actualízala cuando lo decidas, después de leer las notas de la versión.
Implementar Open Connector detrás de TLS en tu propio VPS
Antes de iniciar el contenedor, necesitas:
- Docker con el complemento Compose, en Ubuntu 24.04 o una distribución similar
- un nombre de host cuyo registro A apunte a este VPS, por ejemplo
connect.example.com - un reverse proxy que ya gestione la terminación TLS (transport layer security) para ese nombre de host
- dos secretos aleatorios, que se generan más abajo
La guía reverse proxy Traefik para varias aplicaciones Docker Compose explica 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.
Genera primero los secretos. La clave de cifrado protege las credenciales almacenadas. El token de administrador protege la consola web y toda la superficie de /api. Ninguno tiene un valor predeterminado, y el runtime se inicia sin problemas 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 .envCopia ahora ambos valores en tu 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 abajo.
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; este es el problema descrito 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 tanto, la pila no se inicia si falta .env, en lugar de iniciarse con las credenciales sin cifrar. Mantener los valores en .env, en vez de 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 ya está activo. ss debe mostrar 127.0.0.1:3000. Una línea que indique 0.0.0.0:3000 significa que la asignación de puertos sigue siendo la del proyecto original y que la puerta de enlace responde directamente a todo Internet. Una conexión rechazada durante la comprobación de estado significa que el contenedor todavía no está escuchando. Revisa los registros 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, conecta este servicio a la red de Traefik y elimina el bloque ports:, porque Traefik alcanza el contenedor a través de la red interna y no es necesario publicar nada en el host. certresolver=le debe coincidir con el nombre del resolver de la configuración estática de Traefik. De lo contrario, el router se inicia sin certificado.
Por qué OAuth exige un nombre de host real
OOMOL_CONNECT_ORIGIN es el ajuste que muchos omiten. Al omitirlo, OAuth falla de una forma que parece un error del proveedor. El entorno de ejecución construye el URI de redirección a partir de ese origen, con el formato <origin>/oauth/callback. Si no se define, el origen toma el valor predeterminado http://localhost:3000. Por tanto, el entorno de ejecución envía al proveedor un URI de redirección http://localhost:3000/oauth/callback, mientras la aplicación OAuth tiene registrado 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 ese URI. Por tanto, debe ser una dirección accesible desde Internet. Los proveedores rechazan http:// sin cifrado para cualquier destino que no sea localhost. Esa es la razón por la que este despliegue necesita un nombre de host y un certificado. Defina el origen antes del primer arranque, porque el valor se lee al iniciar el servicio. Después de editar .env o compose.yaml, ejecute docker compose up -d de nuevo para aplicar el cambio.
Conecta tu primer proveedor mediante OAuth
Crea 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. Establece la URL de callback de autorización en https://connect.example.com/oauth/callback. Guarda el client ID y el client secret.
Cada llamada a /api incluye el token de administrador, así que expórtalo 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.
Guarda las credenciales del cliente y, después, inicia 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. Ábrelo en un navegador, aprueba los permisos y el proveedor devolverá el navegador a /oauth/callback. Allí, el runtime intercambia el código y guarda la credencial. La consola web en tu origen guía los mismos pasos mediante un formulario y usa el mismo token de administrador. Los proveedores que utilizan una API key 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 administrativa 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 uno 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 invoca las acciones mediante HTTP estándar.
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 un sobre cuyo campo success es true, con la carga útil del proveedor en data. El token de GitHub no aparece en ningún lugar de esa respuesta. En 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, lo que mantiene reducida la lista de herramientas del agente. Ejecución de servidores MCP en un VPS cubre la parte del cliente de esta configuración.
Realice una comprobación más antes de dar el trabajo 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 invoca /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 ahora 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 esa es la única ruta que necesita la redirección del navegador de un proveedor.
Reduzca la lista de acciones a las que necesita el agente
Un gateway con mil proveedores detrás ofrece 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 al responder 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 debe aplicarse a sus permisos: conceda las pocas acciones que el trabajo necesita realmente y ninguna más. Hay dos controles que reducen el alcance.
OOMOL_CONNECT_ALLOWED_ACTIONS acepta una lista de permitidos separada por comas y entiende 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 está vacía inicialmente, por lo que POST /v1/proxy/:service se rechaza hasta que se conceda. Ese endpoint del proxy reenvía una solicitud sin modificar a un proveedor con sus credenciales adjuntas, así que déjelo vacío salvo que un agente concreto lo necesite.
OOMOL_CONNECT_ALLOW_PRIVATE_NETWORK tiene false de forma predeterminada. Esto impide que una conexión a un proveedor autohospedado apunte a una dirección privada, como el servicio de metadatos de la nube en 169.254.169.254, o a su base de datos en la misma red. Déjelo desactivado. Actívelo sólo para un proveedor que aloje usted mismo.
Realice 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 de /app/data/connect.sqlite dentro del volumen connector-data contiene las credenciales selladas. La clave de cifrado de .env las abre. 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. 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 pasar una hora revisando 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 /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 después 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 pueda resolverlo. 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. Consulte las notas de la versión actual antes de rotar nada.
El agente muestra un error que menciona una acción visible en el catálogo. El descubrimiento y la ejecución son procesos independientes. Una acción puede aparecer en search_actions y aun así ser rechazada por OOMOL_CONNECT_ALLOWED_ACTIONS, por la lista de denegación o por las reglas propias del token de ese runtime.
Actualizaciones. Haga una copia de seguridad del volumen, cambie la etiqueta de imagen a la nueva versión y, después, docker compose pull && docker compose up -d. Supervise docker compose logs -n 50 connector para comprobar que aparezca 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 servicio. Para revertir la actualización, restaure la etiqueta anterior. Esto funciona sólo porque la fijó.
FAQ
¿Necesito un dominio público para alojar Open Connector?
Para los proveedores que usan una clave de API, no: basta con una puerta de enlace 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 cifrado fuera de localhost. Configure OOMOL_CONNECT_ORIGIN con su 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, ni siquiera 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 la llamada a través de la puerta de enlace. El agente se autentica con un token de ejecución que empieza por oct_, y la puerta de enlace inyecta la credencial del proveedor en la solicitud saliente en el servidor y devuelve sólo la respuesta. Hay dos situaciones que rompen esta propiedad: el endpoint /v1/proxy/:service, que reenvía solicitudes sin modificar con su 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 puerta de enlace.
¿Debe poder accederse a la puerta de enlace desde Internet público?
Sólo /oauth/callback debe ser 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 usarse 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 versión, nunca en latest ni en tip, lea las notas de la versión antes de cada actualización y conserve una copia de seguridad del volumen que haya restaurado al menos una vez. El diseño es sólido para un equipo que usted administra; el riesgo está en la rápida sucesión de versiones, no en la arquitectura.