Тема
Сайты без git
Как дать агенту доступ к сайту, у которого нет git-репозитория: агент читает код, логи и выбранные таблицы базы прямо на сервере через SSH-шлюз.
Когда нужен шлюз
Обычно агент работает с git-репозиторием на машине с runner. Если сайт живёт только на хостинге, без репозитория, шлюз даёт агенту доступ к нему на чтение:
- код сайта: список файлов и чтение строк файла;
- логи: последние строки, с фильтром по подстроке;
- база данных: выборка из таблиц и колонок, которые вы разрешили. Модуль базы включается отдельно.
Только чтение
Через шлюз агент не меняет файлы на сервере и не выполняет команды. Shell и SSH-ключ ему не выдаются. Шлюз подходит, чтобы разобраться в ошибке, найти причину и предложить правку.
Что понадобится
| Где | Что нужно |
|---|---|
| Сервер сайта | Обычный SSH-доступ пользователя хостинга, root не нужен. Утилиты awk, grep, sed, tail, ls и realpath или readlink |
| Сервер сайта, для базы | Клиент mysql, PHP с расширением mysqli или Docker, если база в контейнере |
| Ваш компьютер | Вход на сервер по SSH, описанный в ~/.ssh/config под коротким именем (alias) |
| Runner | Linux и изоляция агентов 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
*.logtext
/wp-config.php
/wp-content/uploads/
/wp-content/cache/
/wp-content/backup*/
*.sql
*.logtext
/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 | Имя сервера в шлюзе. Агент выбирает по нему, если у проекта несколько серверов |
--host | Alias сервера из ~/.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-доступа к серверу:
- Выполните install у себя с флагом
--dir <временный каталог>. - Перенесите каталог
<временный каталог>/<имя>/в каталог шлюза runner от имени пользователя runner. Права каталога —0700. - Удалите локальную копию и перезапустите 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.