SSD Nodes Learn Hosting plans →
Руководства Matt ConnorАвтор: Matt Connor · Обновлено 2026-08-26

Self-hosted Open Connector: настройка и запуск

Разверните Open Connector на собственном VPS для безопасного управления OAuth токенами AI-агентов. Инструкция по настройке TLS, SQLite и работе через MCP без утечек данных.

Зачем AI-агенту нужен Open Connector

Самостоятельный хостинг Open Connector позволяет разместить единый шлюз аутентификации между вашими AI-агентами и всеми API сервисов (SaaS), к которым они обращаются. Благодаря этому агент никогда не хранит токены провайдеров. Это шлюз с открытым исходным кодом от OOMOL Lab, распространяемый по лицензии Apache 2.0. Он работает как один контейнер, хранит состояние в единственном файле SQLite и предоставляет доступ к действиям провайдеров через HTTP и MCP (model context protocol).

Проблемы начинаются уже на второй интеграции. У каждого провайдера свой процесс OAuth (open authorization), свой срок жизни токена обновления и свои названия областей доступа (scopes). Ручная настройка пяти провайдеров для одного агента означает создание пяти обработчиков редиректов, пяти хранилищ учетных данных и пяти циклов обновления токенов, которые должны срабатывать до истечения срока их действия. Почти никто не пишет такой код самостоятельно. Обычно создают один долгоживущий персональный токен доступа для каждого сервиса и вставляют его в конфигурацию агента, файл переменных окружения или непосредственно в промпт. Этот токен становится доступен любому инструменту, который запускает агент, и попадает в историю переписки, что приводит к инциденту, описанному в как не допустить утечки секретов в AI-агентах.

Шлюз аутентификации разделяет учетные данные на две части. Шлюз хранит учетные данные провайдера и выполняет процесс OAuth. Агент получает токен времени выполнения, который действителен только для взаимодействия со шлюзом. Когда агент вызывает действие, шлюз загружает сохраненные учетные данные, внедряет их в исходящий запрос на стороне сервера и возвращает только тело ответа. Агент никогда не получает токен доступа провайдера, поэтому в случае утечки истории переписки агента вы теряете лишь один отзывный токен времени выполнения, а не доступ к своей учетной записи GitHub.

Каталог заявляет о поддержке более 1000 провайдеров и 10 000 готовых действий — это цифры самого проекта, которые невозможно проверить извне. Что можно проверить, так это архитектуру: одна HTTP-точка входа на действие, одно сохраненное соединение на провайдера, один токен на агента. Если сторона агентов для вас еще нова, а термины вроде tool call или MCP server пока не устоялись, поэтапный план в как изучать AI-агентов с нуля поможет выстроить цикл работы, инструменты и правила безопасности, которые такой шлюз считает уже внедренными.

Почему стоит развернуть Open Connector самостоятельно, а не использовать облачный сервис

Облачный сервис коннекторов выполняет ту же работу, но хранит refresh tokens для всех подключенных провайдеров. Refresh token для Google или GitHub — это долгоживущий ключ к вашей почте и репозиториям, который обычно продолжает действовать даже после смены пароля. Взлом такого сервиса становится вашим взломом. Самостоятельное развертывание переносит эти записи в базу данных SQLite на арендованном вами сервере, который вы администрируете, и защищает их ключом, который никогда не покидает ваш контур.

Оцените стоимость владения до начала работы. Этот VPS станет самым ценным сервером в вашей инфраструктуре. Он хранит рабочие учетные данные для десятка сервисов в одном файле, поэтому заслуживает такого же отношения, как и хост для менеджера паролей: межсетевой экран, открывающий только порт 443, отсутствие общих учетных записей, резервная копия, которую вы хотя бы раз восстанавливали, и оповещения при потере доступности. Если вы не готовы разместить на этом сервере хранилище паролей, не стоит размещать на нем и коннектор.

Фиксация версии перед установкой

Open Connector — молодой проект. Репозиторий появился 29 июня 2026 года, и по состоянию на 1 августа 2026 года новейший помеченный релиз — v1.3.3, опубликованный 30 июля 2026 года и также имеющий тег latest. В реестре также публикуется тег tip, собранный из новейшего коммита в main.

В проектах на такой ранней стадии динамические теги часто меняются. Тег docker compose pull, который перескакивает через два релиза, может изменить endpoint, от которого зависит ваш агент, и вы потратите вечер на отладку, принимая это за проблему в самом агенте. Фиксируйте образ на теге релиза и обновляйтесь только тогда, когда решите сами, предварительно ознакомившись с примечаниями к выпуску.

Развертывание Open Connector за TLS на собственном VPS

Перед запуском контейнера вам потребуются:

  • Docker с плагином Compose на Ubuntu 24.04 или аналогичном дистрибутиве
  • доменное имя, A-запись которого указывает на этот VPS, например connect.example.com
  • обратный прокси-сервер, который уже выполняет TLS termination (завершение TLS) для этого домена
  • два случайных секрета, сгенерированных ниже

В руководстве Traefik reverse proxy for multiple Docker Compose apps описана настройка прокси. Полный процесс настройки сертификатов для одного приложения разобран в руководстве n8n on a VPS with Docker and 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 (network address translation) до того, как пакеты попадут в цепочку фильтрации ufw, поэтому ufw deny 3000 не закрывает этот порт — это ловушка, описанная в why Docker ports bypass ufw. Указание 127.0.0.1:3000:3000 публикует сервис только на интерфейсе loopback, а ваш обратный прокси подключается с того же хоста.

Параметр :? помечает каждую переменную как обязательную, поэтому стек откажется запускаться при отсутствии .env, вместо того чтобы работать с незашифрованными учетными данными. Хранение значений в .env, а не в файле compose — это стандартная практика, описанная в Docker Compose env files and secrets.

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 означает, что отображение портов осталось исходным, и шлюз отвечает всему интернету напрямую. Ошибка Connection refused при проверке работоспособности означает, что контейнер еще не начал прослушивание, поэтому изучите логи, прежде чем настраивать прокси.

Метки 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 должен совпадать с именем резолвера в вашей статической конфигурации Traefik, иначе маршрутизатор запустится без сертификата.

Почему OAuth требует наличия реального имени хоста

Параметр OOMOL_CONNECT_ORIGIN — это настройка, которую часто пропускают, что приводит к сбоям OAuth, выглядящим как ошибка на стороне провайдера. Среда выполнения формирует URI перенаправления (redirect URI) на основе этого источника (origin) в формате <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, а значит, адрес должен быть доступен из внешней сети. Провайдеры отклоняют простые http:// для любых целей, кроме localhost. Именно поэтому для данного развертывания требуются имя хоста и сертификат. Установите origin до первого запуска, так как значение считывается при старте: после редактирования .env или compose.yaml выполните docker compose up -d, чтобы применить изменения.

Подключение первого провайдера через OAuth

Сначала создайте OAuth-приложение на стороне провайдера. В GitHub путь выглядит так: Settings, затем Developer settings, затем OAuth Apps, и наконец New OAuth App. Установите URL для callback-авторизации в https://connect.example.com/oauth/callback. Сохраните client ID и client secret.

Каждый вызов /api требует наличия токена администратора, поэтому экспортируйте его один раз для текущей сессии оболочки.

export ADMIN_TOKEN='paste-the-admin-token'
curl -s https://connect.example.com/api/oauth/configs \
  -H "authorization: Bearer $ADMIN_TOKEN"

Этот список показывает URI перенаправления, который ожидается средой выполнения для каждого провайдера. Это самый быстрый способ проверить, что ваши изменения вступили в силу. Если по-прежнему отображается 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. Откройте его в браузере, подтвердите области доступа (scopes), и провайдер перенаправит браузер обратно на /oauth/callback, где среда выполнения обменяет код и сохранит учетные данные. Веб-консоль на вашем узле выполняет те же действия через форму, используя тот же токен администратора. Провайдеры, использующие обычный API key, пропускают этот этап: PUT /api/connections/<service> с параметром {"authType":"api_key","values":{"apiKey":"..."}} сохраняет ключ напрямую.

Назначьте каждому агенту токен времени выполнения вместо учетных данных

Агент проходит аутентификацию на шлюзе с помощью токена времени выполнения, который создается через admin 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 на обратном прокси-сервере, разрешив его только для IP-адресов ваших агентов. Только /oauth/callback должен оставаться открытым для внешнего мира, так как это единственный путь, необходимый для редиректа браузера провайдера.

Сократите список действий до необходимых агенту

Шлюз, за которым скрываются тысячи провайдеров, представляет собой широкую поверхность атаки для языковой модели. Она становится еще шире, когда модель начинает читать текст, написанный не ею, поскольку страница, возвращенная вашим собственным экземпляром SearXNG, отвечающим на веб-поиски агента, может содержать инструкции, нацеленные на любые действия, доступные агенту. Тот же принцип сдержанности, который заставляет кодирующего агента вносить минимально необходимые изменения, должен применяться и к его правам доступа: предоставляйте только те немногие действия, которые действительно нужны для работы, и ничего сверх этого. Сузить круг возможностей позволяют два параметра контроля.

OOMOL_CONNECT_ALLOWED_ACTIONS принимает список разрешенных действий через запятую и поддерживает service.* и *. OOMOL_CONNECT_BLOCKED_ACTIONS — это список запрещенных действий, и он имеет приоритет. Установка списка разрешенных в github.get_current_user,github.list_issues означает, что любое другое действие будет отклонено, независимо от запроса агента, что является гранью между ошибкой и инцидентом. Токены времени выполнения (runtime tokens) имеют собственные правила действий поверх глобальных, и их список allowedProxies по умолчанию пуст, поэтому POST /v1/proxy/:service будет отклонено, пока вы его не разрешите. Эта конечная точка прокси пересылает необработанный запрос провайдеру с прикрепленными учетными данными, поэтому оставляйте ее пустой, если только она не требуется конкретному агенту.

OOMOL_CONNECT_ALLOW_PRIVATE_NETWORK по умолчанию имеет значение false, что предотвращает обращение соединения с self-hosted провайдером к частным адресам, таким как служба метаданных облака по адресу 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, что обеспечит его шифрование перед передачей, так как этот архив является хранилищем учетных данных.

Среда выполнения сохраняет записи о недавних действиях в качестве аудита, по умолчанию до 5000 записей, чтобы консоль могла показать, какой агент и когда выполнял задачу. Этот лог — первое, что нужно изучить, если агент ведет себя странно. Также настройте страницу статуса Uptime Kuma для https://connect.example.com/health. Когда шлюз перестает отвечать, агенты начинают выдавать ошибки, которые сложно интерпретировать, и знание о том, что шлюз недоступен, сэкономит час времени на чтение вывода агентов.

Что может сломаться и какие сообщения вы увидите

redirect_uri_mismatch у провайдера. Исходный адрес и зарегистрированный callback 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-битный ключ, режим Galois/Counter Mode).

Ничего не расшифровывается после восстановления. Ключ шифрования был изменен или утерян. По замыслу разработчиков, он никогда не записывается рядом с данными, поэтому пути восстановления не существует, и обращение в поддержку не поможет. Переподключите всех провайдеров. Ротация поддерживается через отдельную переменную ключа и команду работы с данными в среде выполнения, поэтому перед ротацией ознакомьтесь с примечаниями к текущему релизу.

Агент выдает ошибку при обращении к действию, которое отображается в каталоге. Обнаружение и выполнение — это разные процессы. Действие может присутствовать в 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:// hostname перед первым запуском и зарегистрируйте <origin>/oauth/callback в OAuth-приложении провайдера.

Что произойдет, если я потеряю ключ шифрования Open Connector?

Сохраненные учетные данные невозможно расшифровать, восстановления не существует. Ключ намеренно никогда не хранится вместе с данными, поэтому никто, имеющий доступ к базе данных, не сможет их прочитать, включая вас. Единственный вариант — установить новый ключ и заново подключить каждого провайдера. Храните ключ в менеджере паролей, а базу данных — в ротации резервных копий, так как для восстановления нужны оба компонента.

Может ли мой AI agent увидеть токен доступа провайдера?

Нет, если он делает вызовы через шлюз. Агент проходит аутентификацию с помощью runtime-токена, начинающегося с oct_, а шлюз внедряет учетные данные провайдера в исходящий запрос на сервере, возвращая только ответ. Это свойство нарушают две вещи: эндпоинт /v1/proxy/:service, который пересылает необработанные запросы с прикрепленными учетными данными (поэтому его права доступа по умолчанию пусты), и самостоятельная вставка API key в агента, что полностью исключает шлюз.

Должен ли шлюз быть доступен из публичного интернета?

Только /oauth/callback должен быть доступен. Опубликуйте порт контейнера на 127.0.0.1, чтобы правила NAT в Docker не могли выставить его за пределы вашего брандмауэра, и установите перед ним reverse proxy. Затем протестируйте один вызов действия без заголовка authorization. Если он будет успешным, ограничьте /api, /v1 и /mcp на прокси адресами, которые используют ваши агенты, пока не останутся только аутентифицированные вызовы.

Готов ли Open Connector к использованию в production?

Он распространяется по лицензии Apache 2.0 и быстро развивается: репозиторий появился 29 июня 2026 года, а версия v1.3.3 вышла 30 июля 2026 года, поэтому рассматривайте каждый номер версии в этом руководстве как срез на 1 августа 2026 года. Запускайте его, зафиксировав версию тегом, никогда не используйте latest или tip, читайте примечания к выпуску перед каждым обновлением и храните резервную копию тома, которую вы хотя бы раз восстанавливали. Архитектура надежна для сервера, которым вы владеете, а риск заключается в частоте обновлений, а не в самой архитектуре.