Как установить Open Connector на свой VPS
Разверните Open Connector на собственном VPS: закрепите образ, настройте TLS origin и OAuth callbacks, храните токены в шлюзе, а SQLite-файл включите в резервные копии.
Что Open Connector делает для AI-агента
Self-hosting Open Connector размещает один шлюз аутентификации между AI-агентами и всеми API программного обеспечения как услуги (SaaS), к которым они обращаются. Поэтому агенту не требуется хранить токен провайдера. Это шлюз с открытым исходным кодом от OOMOL Lab, распространяемый по лицензии Apache 2.0. Он работает как один контейнер, хранит состояние в одном файле SQLite и предоставляет действия провайдеров по HTTP и через MCP (протокол контекста модели).
Проблемы начинаются со второй интеграции. У каждого провайдера свой процесс OAuth (открытая авторизация), свой срок действия refresh token и свои имена scope. Ручное подключение пяти провайдеров к агенту означает наличие пяти обработчиков перенаправления, пяти хранилищ учетных данных и пяти циклов обновления, которые должны выполняться до истечения срока действия токена. Почти никто не пишет такой код. Вместо этого для каждого сервиса создают один долгоживущий personal access token и вставляют его в конфигурацию агента, файл окружения или сам prompt. Затем этот токен становится доступен для чтения каждому инструменту, который запускает агент, и попадает в transcript. Именно такую проблему описывает раздел как не допустить утечки секретов из AI-агентов.
Шлюз аутентификации разделяет учетные данные на две части. Шлюз хранит учетные данные провайдера и выполняет процесс OAuth. Агент получает runtime token, действительный только при обращении к шлюзу. Когда агент вызывает действие, шлюз загружает сохраненные учетные данные, добавляет их на стороне сервера в исходящий запрос и возвращает только тело ответа. Агент не получает access token провайдера. Поэтому при утечке transcript агента вы отзываете один runtime token, а не доступ к учетной записи GitHub.
В каталоге заявлена поддержка более 1,000 провайдеров и 10,000 готовых действий. Это собственная оценка проекта, которую нельзя проверить извне. Проверить можно структуру: одна HTTP endpoint для каждого действия, одно сохраненное подключение для каждого провайдера и один token для каждого агента.
Зачем размещать Open Connector самостоятельно, а не использовать размещённую службу коннекторов
Размещённая служба коннекторов выполняет ту же работу и хранит токены обновления для каждого подключённого к ней провайдера. Токен обновления для Google или GitHub — это долгосрочный криптографический ключ к вашей почте и репозиториям. Обычно он продолжает действовать после смены пароля. Если служба будет взломана, ваш сервер также окажется скомпрометирован. При самостоятельном размещении эти записи переносятся в SQLite на арендованную и администрируемую вами машину. Они защищены ключом, который никогда не покидает ваш сервер.
До начала оцените стоимость вслух. Этот VPS станет самым ценным сервером в вашей инфраструктуре. В одном файле он хранит действующие учётные данные для десятка служб. Поэтому обращаться с ним нужно так же, как с сервером менеджера паролей: настроить firewall, открыв только порт 443, не использовать общие учётные записи, создать резервную копию и хотя бы один раз проверить её восстановление, а также настроить оповещение о прекращении ответа сервера. Если вы не стали бы размещать на этой машине хранилище паролей, не размещайте на ней и коннектор.
Зафиксируйте версию до установки чего-либо
Open Connector — молодой проект. Репозиторий впервые появился 29 June 2026, а по состоянию на 1 August 2026 новейшим помеченным выпуском является v1.3.3, опубликованный 30 July 2026 и также содержащий тег latest. Реестр также публикует тег tip, собранный из последнего коммита в main.
В таком новом проекте изменяемые теги часто обновляются. Образ docker compose pull, который перескакивает через два выпуска, может изменить endpoint, от которого зависит ваш агент, и вы потратите вечер на поиск причины, считая проблему связанной с агентом. Зафиксируйте образ на теге выпуска и обновляйте его по своему решению после чтения примечаний к выпуску.
Развертывание Open Connector за TLS на собственном VPS
До запуска контейнера необходимо:
- Docker с плагином Compose на Ubuntu 24.04 или близкой к ней системе
- имя хоста, A-запись которого указывает на этот VPS, например
connect.example.com - обратный прокси, который уже завершает TLS (защиту транспортного уровня) для этого имени хоста
- два случайных секрета, которые генерируются ниже
В руководстве Обратный прокси Traefik для нескольких приложений Docker Compose описана настройка прокси. Полная настройка сертификатов для одного приложения приведена в руководстве n8n на VPS с Docker и HTTPS.
Сначала сгенерируйте секреты. Ключ шифрования защищает сохраненные учетные данные. Токен администратора защищает веб-консоль и весь интерфейс /api. Для обоих значений нет значения по умолчанию, а среда выполнения без них запускается без ошибок.
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Сразу сохраните оба значения в менеджере паролей до первого запуска. Для ключа шифрования не предусмотрено восстановление. Причина указана в списке ошибок ниже.
Теперь compose.yaml. Он отличается от примера разработчика в двух местах, и оба изменения важны.
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:Первое изменение — зафиксированный тег вместо latest. Второе — порт. В исходном файле публикуется 3000:3000, который привязывает порт ко всем интерфейсам хоста. Docker записывает опубликованные порты в таблицу NAT (трансляции сетевых адресов) до того, как пакет попадает в цепочку фильтрации ufw. Поэтому ufw deny 3000 не закрывает этот порт. Эта проблема описана в материале почему порты Docker обходят ufw. Запись 127.0.0.1:3000:3000 публикует порт только на интерфейсе loopback, а обратный прокси подключается с того же хоста.
:? помечает каждую переменную как обязательную. Поэтому стек отказывается запускаться, если отсутствует .env, вместо запуска с незашифрованными учетными данными. Хранение значений в .env, а не в файле Compose, соответствует подходу из материала файлы env и секреты 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 проверяет { "ok": true } после запуска среды выполнения. ss должен вывести 127.0.0.1:3000. Строка 0.0.0.0:3000 означает, что сопоставление портов все еще соответствует исходному варианту, а шлюз напрямую отвечает всему интернету. Отказ в соединении при проверке состояния означает, что контейнер еще не начал принимать соединения. Перед настройкой прокси изучите журналы.
Метки Traefik для того же сервиса
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"Если Traefik работает в Docker на том же хосте, подключите этот сервис к сети Traefik и удалите блок ports:, поскольку Traefik обращается к контейнеру через внутреннюю сеть и публиковать порт на хосте вообще не требуется. certresolver=le должен совпадать с именем resolver в статической конфигурации Traefik. В противном случае маршрутизатор запустится без сертификата.
Почему OAuth требует настоящего имени хоста
OOMOL_CONNECT_ORIGIN — это параметр, который часто пропускают. Из-за этого OAuth завершается ошибкой, похожей на ошибку провайдера. Среда выполнения формирует URI перенаправления на основе этого источника в формате <origin>/oauth/callback. Если источник не задан, по умолчанию используется http://localhost:3000. Поэтому среда выполнения отправляет провайдеру URI перенаправления http://localhost:3000/oauth/callback, а в приложении OAuth зарегистрирован https://connect.example.com/oauth/callback. Эти строки различаются, поэтому GitHub отвечает:
The redirect_uri MUST match the registered callback URL for this application.Провайдер OAuth перенаправляет браузер обратно на этот URI. Поэтому URI должен быть доступен из внешней сети. Провайдеры отклоняют обычный http:// для всех адресов, кроме localhost. Поэтому для этого развертывания нужны имя хоста и сертификат. Задайте источник до первого запуска, поскольку значение считывается при запуске. После изменения .env или compose.yaml снова выполните docker compose up -d, чтобы применить настройку.
Подключение первого провайдера через OAuth
Сначала создайте OAuth-приложение у провайдера. В GitHub откройте Settings, затем Developer settings, затем OAuth Apps и выберите New OAuth App. Укажите URL обратного вызова авторизации https://connect.example.com/oauth/callback. Сохраните идентификатор клиента и секрет клиента.
Каждый вызов /api передаёт токен администратора, поэтому экспортируйте его один раз для текущего сеанса shell.
export ADMIN_TOKEN='paste-the-admin-token'
curl -s https://connect.example.com/api/oauth/configs \
-H "authorization: Bearer $ADMIN_TOKEN"В этом списке указан URI перенаправления, который runtime ожидает для каждого провайдера. Это самый быстрый способ проверить, применилось ли значение origin. Если по-прежнему указано localhost, контейнер работает со старым значением, и поток OAuth завершится ошибкой на последнем шаге.
Сохраните учётные данные клиента и запустите авторизацию.
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"}'Второй вызов возвращает authorizationUrl. Откройте его в браузере и подтвердите области доступа. После этого провайдер вернёт браузер на /oauth/callback, где runtime обменяет код и сохранит учётные данные. Веб-консоль по адресу origin выполняет те же шаги с помощью формы и использует тот же токен администратора. Провайдеры, которые используют обычный API-ключ, пропускают весь этот процесс: PUT /api/connections/<service> с {"authType":"api_key","values":{"apiKey":"..."}} напрямую сохраняет ключ.
Выдавайте каждому агенту токен времени выполнения, а не учетные данные
Агент проходит аутентификацию на шлюзе с помощью токена времени выполнения, который выпускает API администрирования.
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"}'Ответ содержит токен, начинающийся с oct_. Выпускайте отдельный токен для каждого агента и называйте его в соответствии с этим агентом. Если вы не можете определить токен, его отзыв приведет к отзыву всех токенов. После этого агент вызывает действия через обычный HTTP.
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":{}}'Корректный ответ представляет собой конверт, в котором поле success имеет значение true, а данные провайдера находятся в поле data. Токен GitHub нигде в этом ответе не содержится. Для клиента MCP укажите https://connect.example.com/mcp и передайте тот же заголовок bearer. Шлюз предоставляет инструменты обнаружения, такие как search_actions и execute_action, вместо отдельного инструмента для каждого API. Это уменьшает список инструментов агента. В разделе Запуск серверов MCP на VPS описана настройка клиентской части.
Перед завершением выполните еще одну проверку. Повторите вызов действия, удалив заголовок authorization. В собственной инструкции по быстрому запуску проекта вызов /v1 выполняется вообще без bearer. Поэтому установка без настроенной аутентификации времени выполнения будет выполнять действия для любого пользователя, который может подключиться к порту. Если неаутентифицированный вызов завершается успешно, есть два варианта: настройте токены времени выполнения и убедитесь, что анонимный вызов теперь завершается ошибкой, либо ограничьте /api, /v1 и /mcp на обратном прокси адресами, с которых подключаются агенты. Открытым для всего мира должен оставаться только /oauth/callback, поскольку это единственный путь, необходимый для перенаправления браузера провайдера.
Сократите список действий до необходимых агенту
Шлюз с тысячей подключенных провайдеров предоставляет языковой модели слишком широкую область доступа. Для ее ограничения предусмотрены два параметра.
OOMOL_CONNECT_ALLOWED_ACTIONS принимает список разрешенных действий через запятую и поддерживает service.* и *. OOMOL_CONNECT_BLOCKED_ACTIONS задает список запрещенных действий, который имеет приоритет. Если задать для списка разрешенных действий значение github.get_current_user,github.list_issues, все остальные действия будут запрещены независимо от запроса агента. Это отличает ошибку от инцидента. Токены времени выполнения дополнительно используют собственные правила действий поверх глобальных. Их список allowedProxies изначально пуст, поэтому действие POST /v1/proxy/:service запрещено, пока вы явно не разрешите его. Этот прокси-эндпоинт пересылает необработанный запрос провайдеру с вашими учетными данными. Поэтому оставьте его пустым, если он не нужен конкретному агенту.
Параметр OOMOL_CONNECT_ALLOW_PRIVATE_NETWORK по умолчанию имеет значение false. Это не позволяет подключению к провайдеру, размещенному самостоятельно, обращаться к частному адресу, например к сервису метаданных облака на 169.254.169.254 или к базе данных в той же сети. Оставьте этот параметр выключенным. Включайте его только для провайдера, который размещен вами самостоятельно.
Создайте резервную копию сервера, на котором хранятся все токены
Важны две вещи, и каждая бесполезна без другой. База данных в /app/data/connect.sqlite внутри тома connector-data содержит зашифрованные учетные данные. Криптографический ключ в .env расшифровывает их. Резервная копия тома без ключа ничего не восстановит, а ключ без тома тоже ничего не восстановит. Поэтому храните ключ в менеджере паролей, а том включите в обычный цикл резервного копирования.
Остановите контейнер перед копированием файла SQLite. Копия, созданная во время записи, может восстановиться как поврежденная база данных.
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Имя тома состоит из имени каталога проекта и _connector-data. Поэтому первая команда нужна для получения имени: вставьте фактическое имя в третью команду. Отправьте архив с VPS с помощью резервного копирования restic с VPS. Перед отправкой restic зашифрует архив, что важно, поскольку в нем хранится хранилище учетных данных.
Среда выполнения по умолчанию хранит последние 5,000 запусков действий в виде аудиторских записей. Поэтому консоль может показать, какой агент выполнил какое действие и когда. Этот журнал нужно читать в первую очередь, если агент ведет себя необычно. Также настройте страницу состояния Uptime Kuma для https://connect.example.com/health. Если шлюз перестает отвечать, агенты начинают выдавать непонятные ошибки. Информация о недоступности шлюза сэкономит час на просмотре вывода агентов.
Что не работает и какое сообщение вы увидите
redirect_uri_mismatch у провайдера. Исходный URL и зарегистрированный URL обратного вызова различаются. Сравните точную строку из /api/oauth/configs с настройками приложения у провайдера, включая https и http, а также завершающий слеш.
Каждый вызов /api возвращает 401. Заголовок с токеном администратора отсутствует или указан с ошибкой. Имя заголовка — Authorization: Bearer <token>. Веб-консоль запрашивает тот же токен.
Контейнер запускается, а учетные данные хранятся в открытом виде. Это происходит, если OOMOL_CONNECT_ENCRYPTION_KEY не попадает в контейнер. Среда выполнения сохраняет записи учетных данных без шифрования, вместо того чтобы отказываться от запуска. Проверьте это в своей установке: подключите провайдера с API-ключом, который можно распознать, затем найдите его в базе данных.
docker compose cp connector:/app/data/connect.sqlite /tmp/connect.sqlite
grep -c 'github_pat_' /tmp/connect.sqlite
shred -u /tmp/connect.sqliteЗначение выше 0 означает, что ключ не применяется. Проверьте, что .env находится в том же каталоге, что и compose.yaml, а docker compose config выводит это значение. После установки ключа тот же поиск возвращает 0, поскольку запись зашифрована с помощью AES-256-GCM (Advanced Encryption Standard, 256-битный ключ, режим Галуа/счетчика).
После восстановления расшифровка не выполняется. Ключ шифрования изменился или был утерян. По замыслу он никогда не записывается рядом с данными, поэтому восстановить их невозможно, и обращение в службу поддержки не поможет. Подключите каждого провайдера повторно. Ротация поддерживается через отдельную переменную ключа и команду работы с данными в среде выполнения, поэтому перед ротацией ознакомьтесь с примечаниями к текущему выпуску.
Агент сообщает об ошибке для действия, которое отображается в каталоге. Обнаружение и выполнение — разные процессы. Действие может отображаться в search_actions и при этом отклоняться через OOMOL_CONNECT_ALLOWED_ACTIONS, списком запрета или собственными правилами токена этой среды выполнения.
Обновления. Создайте резервную копию тома, измените тег образа на тег нового выпуска, затем docker compose pull && docker compose up -d. Контролируйте docker compose logs -n 50 connector на наличие строки миграции. После этого повторно выполните проверку работоспособности и одно реальное действие, прежде чем снова доверять системе. Откат означает возврат старого тега. Он работает только потому, что тег был зафиксирован.
FAQ
Нужен ли мне публичный домен для самостоятельного размещения Open Connector?
Для провайдеров, использующих API key, нет: достаточно шлюза на 127.0.0.1. Для OAuth на практике он нужен. Провайдер перенаправляет браузер на ваш callback URL, поэтому этот URL должен разрешаться из общедоступного интернета, а провайдеры отклоняют обычный http:// за пределами localhost. До первого запуска задайте OOMOL_CONNECT_ORIGIN равным имени хоста https:// и зарегистрируйте <origin>/oauth/callback в OAuth-приложении провайдера.
Что произойдет, если я потеряю ключ шифрования Open Connector?
Сохраненные учетные данные невозможно расшифровать, и восстановление не предусмотрено. Ключ намеренно не хранится вместе с данными, поэтому прочитать их не сможет никто, у кого есть база данных, включая вас. Единственный вариант — задать новый ключ и заново подключить каждого провайдера. Храните ключ в менеджере паролей, а базу данных включите в цикл резервного копирования, поскольку для восстановления нужны оба компонента.
Может ли мой AI-агент увидеть токен доступа провайдера?
Нет, если он обращается через шлюз. Агент проходит аутентификацию с помощью runtime token, начинающегося с oct_, а шлюз добавляет учетные данные провайдера в исходящий запрос на сервере и возвращает только ответ. Это свойство нарушают два случая: конечная точка /v1/proxy/:service, которая пересылает необработанные запросы с прикрепленными учетными данными и намеренно не предоставляет разрешений по умолчанию, а также самостоятельная вставка API key в агент, полностью обходящая шлюз.
Должен ли шлюз быть доступен из общедоступного интернета?
Доступной извне должна быть только /oauth/callback. Опубликуйте порт контейнера на 127.0.0.1, чтобы правила NAT Docker не смогли открыть его за пределами firewall, и разместите reverse proxy перед ним. Затем проверьте один вызов действия без заголовка authorization. Если он успешен, ограничьте на proxy доступ к /api, /v1 и /mcp адресами, которые используют ваши агенты, пока рабочими не останутся только аутентифицированные вызовы.
Готов ли Open Connector для использования в production?
Лицензия — Apache 2.0, а разработка идет быстро: репозиторий появился 29 June 2026, а v1.3.3 был выпущен 30 July 2026, поэтому рассматривайте каждый номер версии в этом руководстве как снимок состояния на 1 August 2026. Запускайте приложение с фиксацией на release tag, а не на latest или tip, перед каждым обновлением читайте release notes и храните резервную копию volume, восстановление из которой вы уже проверили. Архитектура подходит для сервера под вашим управлением. Основной риск связан с частой сменой версий, а не с архитектурой.