Панель управления и правки руками на одной машине: чем это кончится
Сервер числится «под панелью» — ISPmanager, cPanel, VMmanager, Plesk, — но по факту им управляют два человека двумя разными способами: один кликает в веб-интерфейсе, второй время от времени заходит по SSH и правит то, что панель не умеет или умеет неудобно. Какое-то время это работает без видимых проблем. А потом однажды утром сайт отдаёт 413 на загрузке файла, cron перестаёт слать отчёт, или firewall внезапно пропускает то, что вчера блокировал — и никто не понимает почему, ведь «мы же ничего не трогали». Ниже — почему сочетание панели и ручных правок на одной машине почти всегда кончается именно так, где конкретно это бьёт и как выстроить работу, чтобы два способа управления сервером не воевали друг с другом.
Содержание
- Почему один файл не выдерживает двух хозяев
- Не только nginx: где ещё бьются панель и SSH
- Что именно запускает перезапись
- Как понять, что расхождение уже произошло
- Правило одного источника: как выбрать для каждого ресурса
- Что делать, если правки и панель уже спорят на живом сервере
- Когда смешанный режим вообще не работает
Почему один файл не выдерживает двух хозяев
Панель управления хостингом не редактирует конфигурацию сервера — она её генерирует заново из собственного внутреннего представления. У ISPmanager и VMmanager это записи в собственной базе (доступны через mgrctl), у cPanel — данные в /var/cpanel/userdata/, у Plesk — таблицы во внутренней PostgreSQL/MySQL панели. Когда вы меняете что-то через веб-интерфейс — версию PHP, лимит на сайт, правило firewall, запись DNS, — панель сохраняет новое значение в своей базе, а затем берёт шаблон и перезаписывает итоговый файл на диске: /etc/nginx/vhosts/..., crontab пользователя, зону DNS, набор правил iptables. Не патчит построчно — генерирует с нуля из того, что знает.
Проблема в том, что панель знает только то, что записано в её собственной базе. Если вы зашли по SSH и дописали строку прямо в файл на диске — панель об этом ничего не узнала. Для неё это как будто не существует. При следующей генерации (а поводов для неё, как разберём ниже, гораздо больше, чем кажется) панель перезапишет файл по своему шаблону, и ваша строка исчезнет молча, без ошибки, без предупреждения — просто потому, что панель честно воспроизвела то, что хранит у себя, а не то, что реально лежало на диске секунду назад.
Это не баг конкретного продукта и не признак «плохой» панели — так устроена сама модель «единого источника правды» в веб-интерфейсе. У неё нет способа узнать про изменения в обход себя, если только она специально не спроектирована отслеживать дрейф конфигурации (а таких панелей на рынке VPS практически нет). Отдельный конкретный разбор именно этого механизма на примере nginx есть в статье «Панель управления сломала конфиг nginx: разбор конфликта» — если у вас уже случился именно этот инцидент, пошаговая диагностика там. Здесь же цель другая: показать, что nginx — только один из множества мест, где сталкиваются два способа управления одним сервером, и разобрать общую логику, а не единичный случай.
Не только nginx: где ещё бьются панель и SSH
Конфликт возникает всюду, где панель считает себя единственным владельцем ресурса, а на сервере есть параллельный канал изменений через консоль:
| Ресурс | Где хранит «правду» панель | Что перезаписывается на диске | Типичный симптом конфликта |
|---|---|---|---|
| nginx/Apache vhost | БД панели → шаблон | /etc/nginx/vhosts/domain.conf | пропадают ручные location, client_max_body_size |
| DNS-зона (BIND/PowerDNS под панелью) | таблица записей в БД панели | zone-файл или API DNS-сервера | ручные TXT/SRV-записи исчезают после «Пересобрать зону» |
| Cron системного пользователя | раздел «Задания cron» | crontab этого пользователя | задача из crontab -e пропадает при следующем сохранении в панели |
| Пользователи и права БД | раздел «Пользователи БД» | mysql.user / pg_roles | панель не видит ручной GRANT и может сбросить пароль «неизвестному» пользователю |
| Firewall | модуль «Firewall» (обёртка над iptables/nftables/ufw) | цепочки iptables/nft | правило из iptables -A теряется при перезапуске модуля |
| SSL-сертификаты | своя история выпуска в БД панели | /etc/letsencrypt/ или хранилище панели | параллельный certbot renew и продление панели спорят, кто выпустил актуальный сертификат |
| PHP-FPM пул | селектор версии PHP на сайт | .ini/.conf пула (pm.max_children) | ручная настройка пула слетает при смене версии PHP |
Общий паттерн виден сразу: если у ресурса есть форма в панели — у него почти наверняка есть и файл на диске, который панель считает «своим» и вправе перезаписать в любой момент. Похожая история бывает и вне мира панелей хостинга — например, Docker точно так же самовольно переписывает цепочки iptables мимо правил, выставленных через ufw, и открывает порты, которые администратор считал закрытыми; разбор этого механизма — в статье «Docker переписал правила iptables и открыл базу в интернет». Суть та же: два процесса считают себя единственным владельцем одного и того же системного ресурса, и рано или поздно младший по времени последней записи побеждает.
Нужен сервер под эту задачу?
Разверните VPS MAATRIX за пару минут: NVMe, AMD EPYC, root-доступ, локации UK, США, Франция и РФ. Оплата картой РФ и по СБП.
Арендовать серверЧто именно запускает перезапись
Ловушка в том, что перегенерация файла случается не только тогда, когда вы явно меняете именно этот сайт или именно это правило. Реальные триггеры шире:
- любое сохранение формы в соответствующем разделе панели — даже не связанной напрямую с изменённым файлом: например, смена контактного email в настройках сайта в ISPmanager у части версий тоже пересобирает vhost целиком;
- плановая синхронизация состояния, которую многие панели гоняют по расписанию (раз в час или раз в сутки) — сверка внутренней БД с диском и приведение диска «к порядку», без вашего участия и без уведомления;
- обновление самой панели или пакета шаблонов — новая версия nginx-шаблонов, firewall-модуля или DNS-движка регенерирует все конфиги под новый формат;
- восстановление сайта/сервиса из бэкапа средствами панели — бэкап хранит состояние панельной БД на момент снятия копии, и восстановление откатывает диск к этому состоянию, стирая всё, что было сделано руками после бэкапа;
- переактивация лицензии после её истечения или переноса на другой аккаунт — часто сопровождается полным ресинком конфигурации у панелей, где лицензия завязана на проверку целостности установки.
Из этого следует практический вывод: «мы же ничего сегодня не меняли в панели» — не аргумент. Регенерация могла случиться по расписанию, по обновлению или по любому изменению в соседнем разделе, которое казалось не связанным с вашей ручной правкой.
Как понять, что расхождение уже произошло
Универсальный первый шаг — сверить время изменения файла со временем ваших SSH-сессий:
# когда реально менялся файл
stat -c '%y %n' /etc/nginx/vhosts/example.com.conf
# когда вы заходили на сервер
last -F | head -20
Если файл менялся в момент, когда никто не был залогинен интерактивно — правку сделал процесс панели, а не человек руками. Дальше диагностика зависит от конкретного ресурса:
# cron: что реально стоит у пользователя сейчас
crontab -l -u www-data
# firewall: реальные правила прямо сейчас, а не то, что показывает панель
iptables-save | grep -i DROP
# или для nftables
nft list ruleset
# MySQL: реальные пользователи и хосты в системной таблице
mysql -e "SELECT user, host FROM mysql.user;"
# DNS: что реально отдаёт резолвер, а не что записано в панели
dig TXT example.com @127.0.0.1
Сравните вывод с тем, что показывает интерфейс панели в соответствующем разделе. Расхождение — верный признак: либо панель уже перезаписала ручную правку, либо панель отображает устаревшее состояние, потому что не видит изменений, сделанных в обход неё. Если конфиги под git — сравнение упрощается до git diff или git log -p по нужному файлу; если нет — стоит завести хотя бы git init в основных каталогах конфигурации (/etc/nginx, зона DNS, дамп crontab по расписанию) именно затем, чтобы в следующий раз не гадать, а посмотреть историю.
Правило одного источника: как выбрать для каждого ресурса
Смешанный режим не обязательно плох сам по себе — плохо, когда для одного и того же файла нет явной договорённости, кто им управляет. Рабочая практика — пройтись по всем ресурсам сервера и явно решить для каждого один из трёх вариантов:
- Только через панель. Подходит, если стандартных настроек хватает и специфика проекта не требует ничего за пределами форм интерфейса. Не заходить в соответствующий файл руками вообще, даже «на минутку».
- Через предусмотренный панелью escape-hatch. У большинства панелей для типовых ресурсов есть отдельный файл или директория, которую генератор не трогает:
vhosts-includesу ISPmanager для nginx, кастомный шаблон у HestiaCP, отдельный «Custom rules»-раздел в некоторых firewall-модулях, дополнительная TXT/SRV-запись через API панели вместо ручного редактирования зоны. Если такой механизм есть — используйте именно его, а не прямую правку генерируемого файла. - Только вручную, вне зоны ответственности панели. Если у ресурса вообще нет escape-hatch, а кастомизация нужна регулярно — честнее явно исключить этот ресурс из-под управления панелью: например, завести отдельного системного пользователя с собственным crontab, которым панель не управляет, вместо того чтобы регулярно проигрывать гонку с интерфейсом.
Практический шаг — свести решение по всем ресурсам сервера в одну таблицу и держать её рядом с документацией по серверу:
nginx vhost для site1.example.com → include-файл vhosts-includes/site1.conf
DNS-зона example.com → только через панель (API для TXT записей)
cron www-data → только через панель
cron отдельного сервисного юзера → только вручную, панель не управляет этим юзером
firewall (базовые правила) → только через панель
firewall (VPN-подсеть) → через custom rules панели, если есть; иначе — отдельный fw-скрипт вне зоны панели
Это не бюрократия ради бумаги — без такой таблицы через полгода никто не вспомнит, почему один cron живёт в панели, а другой — нет, и следующий человек снова случайно отредактирует не тот файл не тем способом.
Что делать, если правки и панель уже спорят на живом сервере
Если конфликт уже произошёл и нужно вернуть предсказуемость, порядок действий одинаков независимо от того, какой это ресурс — nginx, cron, firewall или DNS:
- Определите, что именно разошлось — сравните текущее состояние с тем, что должно быть, командами из раздела диагностики выше.
- Восстановите нужное состояние — из git-истории, из бэкапа, из памяти команды. Не полагайтесь на то, что панель сама «подхватит» правильное значение — она не знает о правках мимо себя.
- Примените восстановленное не напрямую в генерируемый файл, а через выбранный канал — escape-hatch панели, форму панели или зону вне её ответственности. Прямая правка в генерируемый файл в этот момент — гарантия, что через день-два история повторится.
- Проверьте результат конкретной командой, а не общим «вроде работает»:
nginx -tи тестовая загрузка файла для vhost,crontab -lдля cron,digс внешнего резолвера для DNS, тестовое подключение с постороннего IP для firewall. - Зафиксируйте итог — обновите таблицу владения ресурсами и, если ещё не сделано, добавьте изменённый каталог конфигурации в git хотя бы одним стартовым коммитом-снапшотом.
Если правка через SSH была сделана как временная затычка «пока не найдём время сделать по-нормальному» — такие затычки и есть основной источник конфликтов, потому что о них забывают раньше, чем находят время перенести их в правильный канал.
Когда смешанный режим вообще не работает
Иногда правильный ответ — не выстраивать процесс вокруг сосуществования панели и ручных правок, а отказаться от одного из двух способов полностью:
- Небольшая команда без глубокой unix-экспертизы — как правило, безопаснее держаться исключительно панели и не заходить в конфиги по SSH вообще, даже если что-то кажется «проще поправить руками». Каждая такая правка в команде без привычки к git и code review рано или поздно потеряется молча.
- Проект с регулярной нестандартной конфигурацией (специфичные
location-блоки, кастомные firewall-цепочки, нетиповые cron-расписания на десятки задач) — здесь смешанный режим с грамотно расставленными escape-hatch'ами работает, но требует дисциплины: документированной таблицы владения, версионирования конфигов, привычки проверять escape-hatch раньше, чем открывать генерируемый файл. - Проект, где нестандартной логики становится больше, чем панель способна обслужить через escape-hatch'и — это сигнал не бороться с панелью дальше, а осознанно перейти на чистый сервер без неё, приняв на себя её рутинные задачи вручную или через собственную автоматизацию (Ansible, Terraform, простые shell-скрипты с идемпотентными проверками). Более широкое сравнение обоих подходов, включая стоимость поддержки и типичные сценарии, где выгоднее каждый вариант, — в статье «Панель управления против чистого сервера».
Есть и обратная ситуация, которую стоит держать в уме отдельно: если панель на сервере осталась после подрядчика и никто в компании не может с уверенностью сказать, кто и как её обслуживает — там на первый план выходят не конфликты конфигураций, а более базовые риски: чужая лицензия, забытый пароль администратора, устаревшая версия без патчей безопасности. Этот случай подробно разобран в статье «Подрядчик поставил панель управления и ушёл: чем это опасно» — если ваша ситуация ближе к «унаследовали сервер и не знаем, что на нём вообще настроено», начните оттуда.
Нужен сервер под эту задачу?
Разверните VPS MAATRIX за пару минут: NVMe, AMD EPYC, root-доступ, локации UK, США, Франция и РФ. Оплата картой РФ и по СБП.
Арендовать серверНужны сами нейросети для контента?
Генерируйте изображения, видео и озвучку нейросетями на falapi.io — десятки моделей в одном окне. Оплата картой РФ и по СБП.
Частые вопросы
Escape-hatch есть для одного ресурса (nginx), но нет для другого (firewall) — что тогда?
Решайте по каждому ресурсу отдельно, а не единым правилом. Для nginx — include-файл, для firewall с малым числом правил — держите всё в панели, а если правил много и они нестандартные — выведите модуль полностью вне зоны ответственности панели и управляйте им отдельным nftables-конфигом под git.
Это касается только «слабых» панелей, а условный cPanel так не делает?
Нет, логика единого источника правды — свойство любой панели с генерируемыми конфигами. У cPanel это WHM-шаблоны и /var/cpanel/userdata/, у Plesk — своя модель, у ISPmanager — mgrctl и БД. Различается удобство escape-hatch'ов, а не сам факт перезаписи.
Можно исключить один сайт из-под управления панели, оставив остальные под ней?
Да, большинство панелей позволяют не заводить сайт в свою систему учёта вовсе. Минус — вы теряете удобства панели именно для него (SSL-автопродление, статистику), решение стоит принимать осознанно.
Что если правки в обход панели делают несколько сотрудников?
Таблица владения ресурсами становится обязательным минимумом — без неё каждый будет считать «своим» удобный лично ему способ, и конфликты пойдут не только между человеком и панелью, но и между сотрудниками. Полезная привычка — явно писать в общем канале, когда и где сделана правка в обход панели.
Как быстро проверить весь сервер на расхождения, а не разбирать по одному ресурсу?
Быстрого универсального способа нет — панели редко дают встроенный diff между своей БД и диском. Практичный минимум — git-репозиторий в ключевых конфигурационных каталогах с ежедневным автокоммитом через cron; тогда расхождение видно по истории, даже если вы не следили за ним в реальном времени.
Обсудить статью, задать вопрос или начать новую тему
Есть вопрос по этой статье, идея для обсуждения или просто хотите поделиться опытом? Сообщество MAATRIX ждёт. Для общения, пожалуйста, зарегистрируйтесь в нашем личном кабинете.
Перейти в сообщество →