Отправка рабочего nginx.conf во внешний сервис ради подсказки означает передать неизвестному лицу структуру инфраструктуры: внутренние адреса, имена хостов, порты, пути и логику маршрутизации. Даже при добросовестном провайдере это лишняя копия конфигурации в чужом журнале. Локальная модель ставится на собственный сервер, работает офлайн и разбирает конфиг, не покидая машину. Ниже собран порядок действий и пределы её полномочий.
Почему нейросети нужен напарник в виде штатного валидатора
Первое, с чем стоит разобраться до установки чего бы то ни было: модель не проверяет конфигурацию, она её комментирует. Разница принципиальна.
У Nginx и systemd уже есть встроенные средства проверки, и они детерминированы. Nginx разбирает файл целиком, строит внутреннее дерево и сообщает точную строку с ошибкой:
nginx -t
Для systemd есть свой аналог, который разбирает юнит и сообщает о нераспознанных директивах:
systemd-analyze verify /etc/systemd/system/myservice.service
Оба инструмента дают ответ, который не меняется от запуска к запуску. Ответ модели вероятностный, и она может уверенно назвать корректную директиву несуществующей, особенно если её обучали на другой ветке.
Отсюда рабочая схема. Сначала прогон штатным валидатором, и только потом разбор остатка моделью. Валидатор ловит синтаксис, модель объясняет смысл, предлагает упрощения и находит места, где конфигурация формально верна, но ведёт себя не так, как задумано.
Пример полезного вывода, который валидатор не даст никогда: в блоке location стоит proxy_pass без завершающего слэша при rewrite правил, и запросы уходят на бэкенд с удвоенным путём. Синтаксис при этом безупречен.
Установка локального движка моделей и выбор размера под железо
Ollama ставится одной строкой и поднимает локальный сервис на порту 11434:
curl -fsSL https://ollama.com/install.sh | sh
systemctl enable --now ollama
Проверка работоспособности занимает несколько секунд:
curl -s http://127.0.0.1:11434/api/tags
Выбор модели упирается в объём оперативной памяти. Ориентиры для семимиллиардных моделей такие: вариант с четырёхбитным квантованием весит около 4,7 ГБ и требует порядка 6 ГБ памяти в работе, трёхмиллиардная модель укладывается в 2 ГБ, полуторамиллиардная в гигабайт. Для разбора конфигов на сервере с 8 ГБ памяти разумно взять модель среднего размера из ветки, обученной на коде.
ollama pull qwen2.5-coder:7b
ollama run qwen2.5-coder:7b "Объясни одной фразой, что делает директива proxy_buffering off"
Отдельно стоит сказать про скорость. На процессоре без видеокарты семимиллиардная модель выдаёт несколько токенов в секунду, и развёрнутый ответ на большой конфиг собирается минуту или две. Это терпимо для разового разбора и неприемлемо для интерактивной работы. Для интерактива берут модель меньшего размера, а тяжёлую оставляют для ночного аудита.
Проверить, что ничего не уходит наружу, легко: достаточно отключить сетевой интерфейс и повторить запрос. Локальная модель продолжит отвечать.
Подключение ShellGPT к локальному бэкенду вместо внешнего API
ShellGPT это обёртка, которая превращает модель в обычную консольную команду. Устанавливается через менеджер пакетов Python:
python3 -m venv ~/.venv/sgpt
~/.venv/sgpt/bin/pip install shell-gpt
ln -s ~/.venv/sgpt/bin/sgpt ~/.local/bin/sgpt
Конфигурация лежит в ~/.config/shell_gpt/.sgptrc, и для локальной работы в ней достаточно поменять три строки:
DEFAULT_MODEL=qwen2.5-coder:7b
LLM_PROVIDER=ollama
OLLAMA_API_BASE_URL=http://127.0.0.1:11434
После этого запрос уходит не во внешний сервис, а на локальный порт. Проверяется одной командой:
sgpt "чем отличается location /api от location /api/ при proxy_pass"
Полезных режимов у инструмента два. Первый, обычный запрос с текстом в аргументе. Второй, потоковая обработка входа, когда текст подаётся через конвейер:
cat /etc/nginx/nginx.conf | sgpt "найди места, где отсутствует ограничение размера тела запроса"
Второй режим удобнее для разбора файлов, поскольку конфигурацию не приходится вставлять в командную строку вручную, а значит, она не попадает в историю оболочки.
История команд отдельная тема. Конфиг с внутренними адресами, отправленный аргументом, навсегда остаётся в ~/.bash_history, а передача через конвейер этот след убирает.
Разбор конфигурации Nginx конвейером из трёх шагов
Одиночный запрос к модели редко даёт полезный результат, потому что модели не хватает контекста о том, что уже проверено. Рабочий конвейер состоит из трёх шагов и оформляется небольшим скриптом:
#!/usr/bin/env bash
set -euo pipefail
CONF="${1:-/etc/nginx/nginx.conf}"
echo "== Шаг 1. Штатная проверка синтаксиса =="
if ! nginx -t -c "$CONF" 2>&1; then
echo "Синтаксис не прошёл, дальше разбирать нечего"
exit 1
fi
echo "== Шаг 2. Проверка на утечку внутренних адресов в запрос =="
sgpt --no-cache "Перечисли только те строки конфигурации ниже, где наружу отдаются \
внутренние адреса, версии ПО или служебные заголовки. Если таких нет, ответь НЕТ.
$(cat "$CONF")"
echo "== Шаг 3. Замечания по логике =="
sgpt --no-cache "Конфигурация прошла nginx -t. Укажи места, где поведение может \
отличаться от ожидаемого: порядок location, отсутствие слэша в proxy_pass, \
лишние rewrite, неочевидный приоритет правил. Отвечай списком строк файла.
$(cat "$CONF")"
Детали здесь не косметические. Флаг --no-cache отключает сохранение запроса в кэше инструмента и снижает число копий конфигурации на диске. Упоминание пройденной проверки в третьем запросе избавляет модель от соблазна перечислять синтаксические придирки, которые уже отработал валидатор.
Первый шаг с выходом по ошибке важен по другой причине. Если синтаксис сломан, любые рассуждения модели о логике бессмысленны, а время на их генерацию тратится впустую.
Размер конфига стоит держать в пределах окна контекста. Для модели с окном в 32 тысячи токенов это несколько тысяч строк, чего обычно хватает.
Реальный nginx.conf редко хранит всё в одном месте. Обычно в нём несколько строк include, а содержимое разложено по каталогам conf.d и sites-enabled. Скормить такой файл модели целиком значит отправить ей текст без включённых частей, и разбор окажется бесполезным.
Штатный дамп показывает конфигурацию после раскрытия всех включений:
nginx -T 2>/dev/null > /tmp/nginx-full.conf
wc -l /tmp/nginx-full.conf
grep -c 'server_name' /tmp/nginx-full.conf
Флаг -T выводит всё дерево с пометками о том, какой файл откуда взят. Пометки помогают понять, к какому файлу относится найденное замечание.
Если развёрнутый вид не влезает в окно контекста, разбирают по одному серверному блоку. Скрипт режет файл по меткам конфигурационных файлов и прогоняет каждый кусок отдельным запросом, складывая ответы в один отчёт.
Проверка юнитов systemd и поиск типовых ошибок в таймерах
С systemd картина похожая, но со своей спецификой. Ошибки в юнитах чаще не синтаксические, а семантические: служба стартует раньше, чем поднимается сеть, или перезапускается бесконечно из-за неверной политики.
Штатная проверка:
systemd-analyze verify /etc/systemd/system/backup.service
Разбор моделью даёт больше, если скормить ей сразу и юнит, и вывод проверки, и текущее состояние:
{
cat /etc/systemd/system/backup.service
echo "---"
cat /etc/systemd/system/backup.timer
echo "---"
systemctl status backup.service --no-pager -l || true
echo "---"
journalctl -u backup.service -n 50 --no-pager
} | sgpt "Найди причину, по которой служба не отрабатывает по расписанию. \
Укажи конкретные директивы и предложи исправление."
Подача журнала вместе с конфигом повышает качество ответа. Модель видит не абстрактный юнит, а реальные сообщения о завершении с кодом.
Типовые находки в таких разборах повторяются. Отсутствие After=network-online.target у службы, которая обращается к сетевому хранилищу. Persistent=true в таймере, из-за которого пропущенный запуск компенсируется сразу после включения машины. Restart=always без RestartSec, превращающий падающую службу в генератор нагрузки.
Ни одно из этих замечаний не является синтаксической ошибкой, и штатный валидатор про них молчит.
Где проходит граница полномочий модели и как её не перейти
Локальная модель не хуже внешней по уровню фантазии, и в этом главная опасность. Она так же уверенно придумывает директивы, которых не существует в используемой ветке, и так же склонна предлагать решения из чужой версии.
Практическое следствие простое: предложенные правки применяются только через проверочный прогон, а не напрямую в рабочий файл. Безопасный порядок выглядит так.
cp /etc/nginx/nginx.conf /tmp/nginx.conf.candidate
# правки вносятся в копию
nginx -t -c /tmp/nginx.conf.candidate
Только после успешной проверки копия заменяет рабочий файл, и делается это через systemctl reload, а не restart, чтобы не обрывать текущие соединения.
Остальные ограничения удобно держать перед глазами коротким перечнем:
- Секреты модели не показывают, токены и пароли к бэкендам выносят в отдельные файлы с правами 600, а в конфигурации оставляют только ссылки на них, иначе результат разбора осядет в терминальной прокрутке и в отчётах;
- Вердикт о несуществовании директивы перепроверяют по справочнику своей ветки, поскольку модель обучена на снимке знаний определённой давности, а stable 1.30.6 и mainline 1.31.8 различаются набором параметров;
- Правку применяют к копии файла и только после успешного nginx -t переносят на рабочее место, а службу перечитывают через reload, а не через restart, чтобы не обрывать текущие соединения;
- Модель спрашивают о конкретике, а не в целом, потому что вопрос про таймауты в одном блоке location даёт разбор, а просьба посмотреть конфиг целиком возвращает общие рассуждения.
Ответ локальной модели стоит проверять так же придирчиво, как и ответ внешнего сервиса. Помогает понижение температуры генерации до нуля, тогда на один и тот же вопрос модель отвечает одинаково, и расхождение между прогонами перестаёт маскировать неуверенность.
Признак качества ответа простой: модель ссылается на конкретные строки и директивы, а не рассуждает в общем. Нет упоминаний реального содержимого файла значит запрос сформулирован слишком широко.
Второй приём, встречный вопрос. После получения совета стоит попросить обоснование и указать, к каким последствиям приведёт правка. Модель, которая уверенно выдумала директиву, на таком вопросе обычно начинает противоречить себе, и это заметно сразу.
Третий приём, повторный прогон через день. Настоящая находка воспроизводится, а выдуманная часто меняет формулировку или исчезает.
Встраивание проверки в ежедневный рабочий процесс
Основная выгода появляется, когда проверка становится частью рутины.
Первый уровень, git. Конфигурации хранятся в репозитории, а применение изменений идёт через фиксацию с понятным сообщением. Откат в этом случае занимает одну команду, а история отвечает на вопрос, кто и зачем поменял таймаут.
Второй уровень, проверка перед фиксацией. Хук вызывает валидатор и не даёт записать сломанную конфигурацию:
#!/usr/bin/env bash
# .git/hooks/pre-commit
for f in $(git diff --cached --name-only | grep -E '\.conf$'); do
nginx -t -c "$(pwd)/$f" || exit 1
done
Третий уровень, периодический аудит по расписанию. Раз в сутки cron запускает скрипт, который собирает список конфигурационных файлов, прогоняет их через валидатор и через модель, а результат складывает в текстовый отчёт:
0 4 * * * /usr/local/sbin/conf-audit.sh >> /var/log/conf-audit.log 2>&1
Ценность аудита не в поиске поломок, их ловит валидатор, а в накопленной истории замечаний. Через месяц видно, какие части конфигурации модель стабильно считает подозрительными, и это повод разобрать их руками.
Локальный помощник в консоли не заменяет знание предмета. Он снимает рутинную часть работы и подсвечивает места, куда стоит посмотреть внимательнее, при этом конфигурация остаётся внутри собственного периметра и не уходит в чужие журналы. Для сервера, который обслуживает реальные проекты, это свойство оказывается важнее удобства.