Skip to content

Сайты без git ​

Как дать агенту доступ к сайту, у которого нет git-репозитория: агент читает код, логи и выбранные таблицы базы прямо на сервере через SSH-шлюз.

Когда нужен шлюз ​

Обычно агент работает с git-репозиторием на машине с runner. Если сайт живёт только на хостинге, без репозитория, шлюз даёт агенту доступ к нему на чтение:

  • код сайта: список файлов и чтение строк файла;
  • логи: последние строки, с фильтром по подстроке;
  • база данных: выборка из таблиц и колонок, которые вы разрешили. Модуль базы включается отдельно.

Только чтение

Через шлюз агент не меняет файлы на сервере и не выполняет команды. Shell и SSH-ключ ему не выдаются. Шлюз подходит, чтобы разобраться в ошибке, найти причину и предложить правку.

Что понадобится ​

ГдеЧто нужно
Сервер сайтаОбычный SSH-доступ пользователя хостинга, root не нужен. Утилиты awk, grep, sed, tail, ls и realpath или readlink
Сервер сайта, для базыКлиент mysql, PHP с расширением mysqli или Docker, если база в контейнере
Ваш компьютерВход на сервер по SSH, описанный в ~/.ssh/config под коротким именем (alias)
RunnerLinux и изоляция агентов bubblewrap или systemd, см. ниже

Изоляция runner ​

Шлюз включается, только если песочница runner надёжно прячет от агента ключ шлюза. Изоляцию задаёт флаг -isolation или переменная QUEUEWARDEN_ISOLATION:

ЗначениеШлюз
bubblewrap, systemdработает
autoработает, если runner выбрал bubblewrap или systemd
none (по умолчанию)выключен
container, appcontainer (Windows)выключен

Если условие не выполнено, runner выключает шлюз целиком и пишет причину в журнал. Журнал показывает команда qw logs.

Подключить сервер ​

Подключение делается на машине, с которой у вас есть SSH-доступ к серверу. Понадобятся два файла: настройки шлюза и правила скрытия.

Настройки: gateway.conf ​

text
root /home/user/site.ru/htdocs/www
max_bytes 262144
log error /home/user/site.ru/htdocs/www/core/cache/logs/error.log
log access /home/user/site.ru/logs/access_log*
db_client mysql
db_table modx_users id username active
db_table modx_system_settings key value namespace
db_mask modx_system_settings key (password|secret|token|apikey|api_key|_key)
СтрокаЧто задаёт
root <путь>Корень кода: абсолютный путь без ссылок. Выше корня агент не читает, ссылки наружу тоже не работают
max_bytes <число>Предел размера одного ответа в байтах. По умолчанию 262144
log <имя> <путь>Лог под именем из латиницы, цифр, _ и -. В пути можно *: берутся до трёх самых новых файлов, архивы пропускаются
db_client <клиент>Включает модуль базы: mysql, абсолютный путь к php или docker <контейнер> [mariadb|mysql]. Без этой строки базы нет
db_table <таблица> <колонки>Таблица и колонки, которые агенту можно читать
db_mask <таблица> <колонка> <выражение>Если значение колонки подходит под регулярное выражение, остальные колонки строки скрываются

Доступ к базе — файл в формате my.cnf: в секции [client] поля host, port, user, password, в секции [mysql] — database. Его передают при подключении, на сервер он ложится с правами 0600. Локальную копию после подключения удалите.

Если клиента базы на сервере нет, модуль выключается сам: остальное работает.

База в Docker

Вариант docker нужен, когда клиента базы на самом сервере нет. Пользователю хостинга тогда нужен доступ к Docker, а это фактически права root. Используйте его, только если у учётной записи они уже есть.

Правила скрытия ​

Файл в синтаксисе .gitignore: *, **, ?, !-исключения, / в начале и в конце. Скрытое агент не видит в списке файлов и не читает. На логи правила не действуют: их определяет строка log.

Скрыто всегда, и ! это не открывает: .ssh, .git, .env*, *.pem, *.key, id_*, .htpasswd, .netrc, .my.cnf, .pgpass, *.p12, *.pfx и каталог самого шлюза.

Начните с набора под свой движок:

text
/core/config/
/config.core.php
/manager/config.core.php
/connectors/config.core.php
/core/cache/
/core/packages/
/assets/components/*/cache/
*.sql
*.sql.gz
*.log
text
/wp-config.php
/wp-content/uploads/
/wp-content/cache/
/wp-content/backup*/
*.sql
*.log
text
/config/
/config*.php
/vendor/
/storage/
*.sql
*.log

Добавьте сюда всё, где лежат пароли и ключи: резервные копии, дампы, свои конфиги.

Установка ​

sh
qw gateway install --name shop --host shop-prod --project <ключ проекта> \
  --rules ./rules --config ./gateway.conf --db-cnf ./db.cnf
ФлагЧто указать
--nameИмя сервера в шлюзе. Агент выбирает по нему, если у проекта несколько серверов
--hostAlias сервера из ~/.ssh/config. Из него же берутся адрес, пользователь и порт
--projectКлюч проекта доски. Сервер увидят только агенты задач этого проекта
--rulesФайл правил скрытия
--configФайл gateway.conf
--db-cnfДоступ к базе. Не нужен, если базы нет

Команда создаёт для сервера отдельный ключ, ставит на сервер обёртку и дописывает ключ в ~/.ssh/authorized_keys с ограничением: по этому ключу сервер запускает только обёртку. Затем проверяет, что ограничение действительно работает: произвольная команда, shell, sftp, scp и проброс портов отбиваются, файлы .env и выход за корень не читаются, каждый лог отвечает.

Если проверка не прошла, install откатывает всё, что сделал, и сообщает причину.

После установки перезапустите runner: раны увидят сервер только после перезапуска.

Управление ​

КомандаЧто делает
qw gateway listПодключённые серверы и их проекты
qw gateway check --name shopПовторяет проверку ключом шлюза
qw gateway uninstall --name shopУбирает обёртку с сервера, строку ключа и локальные файлы

После uninstall тоже перезапустите runner.

На одной учётной записи хостинга можно подключить несколько сайтов: у каждого подключения свой каталог, корень, логи и база.

Runner на другой машине ​

Если на машине с runner нет вашего SSH-доступа к серверу:

  1. Выполните install у себя с флагом --dir <временный каталог>.
  2. Перенесите каталог <временный каталог>/<имя>/ в каталог шлюза runner от имени пользователя runner. Права каталога — 0700.
  3. Удалите локальную копию и перезапустите runner.

Каталог шлюза runner меняет флаг -gateway-dir или переменная QUEUEWARDEN_GATEWAY_DIR. Значение off выключает шлюз.

Как агент работает с сервером ​

Когда runner берёт задачу проекта, к которому привязан сервер, агент получает MCP-сервер ssh-gateway. Доступ живёт, пока идёт запуск. Агенты задач других проектов этот сервер не видят.

ИнструментЧто делает
server_infoКорень кода, имена логов, таблицы и колонки базы
logs_tailПоследние строки лога: по умолчанию 100, не больше 2000. Можно фильтр по подстроке
code_listСодержимое каталога от корня кода
code_readСтроки файла: сколько пропустить и сколько вернуть, по умолчанию 400, не больше 2000
db_queryВыборка из разрешённой таблицы и колонок, условие только на равенство, по умолчанию 50 строк, не больше 500

Если у проекта несколько серверов, агент указывает, к какому обращается.

Всё, что уходит агенту — код, логи, строки базы, имена файлов, — на сервере проходит маскировку: токены, пары вида password=…, адреса почты, номера карт и телефонов заменяются звёздочками.

Маскировка не заменяет правила

Маскировка ищет секреты по шаблонам и может что-то пропустить. Файлы с паролями и ключами скрывайте правилами.

На сервер держится одно SSH-соединение, оно живёт 5 минут после последнего запроса. Так хостинг не заблокирует адрес runner за частые подключения.

Агент вне runner ​

Команда qw gateway mcp отдаёт те же инструменты по stdio агенту, который работает не через runner, например интеграции с CRM. Такой агент видит все подключённые серверы, а не серверы одного проекта. Песочницу здесь никто не проверяет: у такого агента не должно быть shell и чтения файлов вне отведённых ему каталогов.

Ограничения ​

  • Только чтение: менять файлы и выполнять команды на сервере агент не может.
  • Нужен runner на Linux с изоляцией bubblewrap или systemd. На Windows и без изоляции шлюз не работает.
  • Подключение — только командой qw gateway на компьютере, в интерфейсе доски его нет.
  • Сервер привязан к одному проекту доски.
  • Ответ не больше max_bytes, у логов — не больше трёх самых новых файлов.
  • В выборке из базы — одно условие на равенство. Значение — буквы, цифры и _.:@/-.
  • Имена файлов, похожие на длинный токен, приходят замаскированными, например ***.tar.gz.