Антипаттерн: конфиги правятся сразу на проде
Заходите по SSH на боевой сервер, открываете /etc/nginx/sites-available/mysite в nano, меняете пару строк «на глаз», сохраняете и перезапускаете сервис. Если сайт сразу не упал — считается, что всё в порядке. Это самый распространённый антипаттерн эксплуатации, и он мстит не сразу, а через неделю-две, когда никто уже не помнит, что и зачем менялось. Разберём, что именно идёт не так и как выстроить процесс, который не ломается при первой же опечатке.
Содержание
Как это выглядит на практике
Картина повторяется на сотнях серверов почти дословно. Нужно поправить таймаут проксирования или добавить новый location — и вместо того, чтобы оформить это как изменение, администратор идёт кратчайшим путём:
ssh user@prod-server
sudo nano /etc/nginx/sites-available/mysite
# поправили пару строк, сохранили Ctrl+O, вышли Ctrl+X
sudo systemctl reload nginx
# сайт открылся — значит, всё в порядке
То же самое происходит с systemd-юнитами (sudo nano /etc/systemd/system/myapp.service → systemctl daemon-reload → systemctl restart myapp) и с конфигами приложений — .env, config.yaml, PHP-FPM пулами. Логика везде одна: «я знаю, что меняю, это мелочь, зачем усложнять».
Проблема не в том, что правка была неверной — в конкретный момент она вполне может сработать. Проблема в том, что весь процесс не оставляет следов и не проверяет себя заранее. Если полгода назад так правили конфиг пять раз подряд, а потом ещё три раза правил другой человек — у вас на диске лежит файл, который является суммой семи никак не задокументированных решений. Ниже — что из этого вытекает и как это лечится, желательно даже до того, как понадобится второй сервер или третий администратор.
Проблема №1: нет истории изменений
Файл на диске — это моментальный снимок, а не история. nano не хранит предыдущие версии, vim без специальной настройки — тоже. Единственный способ узнать, что изменилось, — помнить это в голове или найти запись в чате, если повезло её оставить.
Через неделю после правки на сайте начинает происходить что-то странное: growing memory у одного из воркеров, странный редирект, медленный ответ на конкретном location. Первый вопрос при разборе инцидента — «что менялось за последнее время?» — часто остаётся без ответа. Никакого git log, никакого diff между «было» и «стало», никакой возможности откатиться одной командой к последней рабочей версии. Единственный вариант отката — переписать конфиг заново по памяти, а память — ненадёжный источник правды, особенно если правок было несколько и делали их разные люди.
Дальше это усугубляется: обнаружив проблему, тот же администратор часто правит конфиг ещё раз — «на глаз» отменяя изменение, которое, как ему кажется, всё сломало. Если он ошибся и откатил не то — история потеряна ещё глубже, потому что теперь неизвестна уже не только исходная рабочая версия, но и последовательность правок поверх неё.
Нужен сервер под эту задачу?
Разверните VPS MAATRIX за пару минут: NVMe, AMD EPYC, root-доступ, локации UK, США, Франция и РФ. Оплата картой РФ и по СБП.
Арендовать серверПроблема №2: опечатка обнаруживается только на reload
Между «я поправил файл» и «сервис применил изменения» в этой схеме нет ни одной проверки. Синтаксис проверяется исключительно тем, упадёт сервис или нет — то есть постфактум, командой systemctl reload или restart.
Для nginx это не так фатально: reload штатно проверяет конфиг перед применением и откажется применять его при синтаксической ошибке, оставив рабочий процесс со старой конфигурацией. Но это не защищает от логических ошибок — неправильного proxy_pass, перепутанного порта, лишнего return 301 — они пройдут проверку синтаксиса и сломают сайт уже после reload, просто без падения самого nginx.
Для systemd-юнитов ситуация хуже: systemctl daemon-reload не проверяет содержимое конкретного .service-файла на смысловые ошибки, а systemctl restart может попытаться запустить сервис с уже сломанной конфигурацией. Если демон не поднимется — сервис просто не работает до тех пор, пока это не заметят и не исправят руками, то есть простой начинается прямо в момент правки, а не когда-то потом.
Похожая история с конфигами приложений: опечатка в .env (лишний пробел, неверный тип значения, пропущенная переменная) обнаруживается только когда приложение либо не стартует, либо стартует, но падает на первом же реальном запросе — уже с живым трафиком.
# правильная последовательность для nginx —
# но в антипаттерне этот шаг просто пропускают
sudo nginx -t
# syntax is ok
# test is successful
sudo systemctl reload nginx
Разница в одну команду nginx -t перед reload — это разница между «увидел ошибку до применения» и «узнал об ошибке от пользователей, которые не могут открыть сайт».
Проблема №3: конфигурацию невозможно воспроизвести
Конфиг, который живёт только на одном сервере в виде накопленных ручных правок, невозможно скопировать никуда, кроме как вручную — файл за файлом, строку за строкой, вместе со всеми чужими правками месячной давности, смысл которых уже никто не помнит.
Это становится настоящей проблемой в трёх типичных ситуациях:
- Добавление второго сервера. Нужно поднять реплику под балансировку или для отказоустойчивости — а «эталонной» конфигурации не существует, есть только то, что накопилось на проде за последний год.
- Переезд на новый сервер. При миграции на новый сервер конфиги обычно просто копируют как есть — вместе со всем техническим долгом, забытыми workaround'ами под давно решённые проблемы и настройками, смысл которых утрачен.
- Восстановление после сбоя. Если сервер потерян целиком, а бэкап конфигов не велся отдельно от бэкапа диска целиком, восстановление превращается в археологию — вспомнить, а что вообще было настроено нестандартно.
Конфигурация в таком виде существует не как артефакт, а как состояние конкретной машины в конкретный момент времени. Она не документирована, не описана декларативно и не может быть применена к другому серверу без риска что-то упустить.
Проблема №4: правки нескольких администраторов конфликтуют
Как только над проектом работает больше одного человека с доступом на сервер, схема «зашёл-поправил-вышел» превращается в гонку. Два администратора могут одновременно открыть один и тот же файл в nano, каждый внести свою правку и сохранить — победит тот, кто сохранил последним, а правка первого просто исчезнет без единого сообщения об этом.
Даже без буквально одновременного редактирования проблема остаётся: администратор А утром поправил таймауты в location /api, администратор Б вечером того же дня, не зная об утренней правке, «упростил» тот же блок, вернув его к старому виду. Наутро таймауты снова не те, что нужны, а никто не понимает, почему — ведь «вчера же было исправлено».
Отсутствие единого источника правды означает, что каждый администратор работает с собственным пониманием того, что сейчас находится в файле, и это понимание расходится с реальностью тем быстрее, чем больше людей имеет доступ к серверу.
Как делать правильно: git, nginx -t и деплой-скрипт
Базовое решение не требует сложной инфраструктуры — оно требует всего лишь перестать редактировать боевой файл напрямую. Основные шаги:
1. Конфиги — в git-репозитории, даже простом и локальном.
mkdir -p ~/configs/nginx && cd ~/configs/nginx
git init
cp /etc/nginx/sites-available/mysite ./mysite.conf
git add mysite.conf
git commit -m "Начальная версия конфига mysite"
Не обязательно сразу заводить GitLab или GitHub — репозиторий может жить прямо на сервере или на рабочей машине администратора, синхронизируясь через git push/git pull на простой bare-репозиторий. Важен сам факт: каждая правка — это коммит с сообщением, а не молчаливое изменение файла на диске.
2. Правки — локально или в отдельной ветке, а не в проде вслепую.
git checkout -b fix-proxy-timeout
# правим mysite.conf в любом редакторе
git diff
# видим ровно то, что изменилось — построчно
git commit -am "Увеличен proxy_read_timeout до 300s для /api"
git diff — это именно то, чего не хватает в схеме с nano: точное, построчное сравнение «было» и «стало» перед тем, как что-либо применяется к живому серверу.
3. Проверка синтаксиса — обязательный шаг перед reload.
sudo cp mysite.conf /etc/nginx/sites-available/mysite
sudo nginx -t
Если тест не прошёл — правка не применяется, старый рабочий конфиг продолжает обслуживать трафик. Только после test is successful имеет смысл идти дальше:
sudo systemctl reload nginx
4. Простейший скрипт деплоя конфига с проверкой.
Даже без Ansible можно избавиться от ручного копирования и забытых проверок с помощью небольшого shell-скрипта:
#!/usr/bin/env bash
set -euo pipefail
CONF_NAME="mysite"
SRC="./nginx/${CONF_NAME}.conf"
DST="/etc/nginx/sites-available/${CONF_NAME}"
if [ ! -f "$SRC" ]; then
echo "Файл $SRC не найден, деплой отменён" >&2
exit 1
fi
sudo cp "$DST" "${DST}.bak.$(date +%Y%m%d%H%M%S)"
sudo cp "$SRC" "$DST"
if sudo nginx -t; then
sudo systemctl reload nginx
echo "Конфиг ${CONF_NAME} применён и nginx перезагружен"
else
echo "nginx -t провалился, откатываю предыдущую версию" >&2
sudo cp "${DST}.bak."*"" "$DST" 2>/dev/null || true
exit 1
fi
Такой скрипт решает сразу три проблемы из четырёх разобранных выше: он делает резервную копию перед заменой (частичная защита от потери истории), проверяет синтаксис перед reload и превращает деплой в воспроизводимое действие, а не в ручную последовательность команд, которую каждый раз выполняют чуть по-разному.
5. Для зрелого процесса — инструменты конфигурационного управления.
Когда серверов становится больше одного, а изменений — больше, чем можно уследить руками, имеет смысл описывать конфигурацию декларативно и применять её инструментом вроде Ansible (или аналогов — Salt, Chef, Puppet):
# playbook.yml — фрагмент
- name: Deploy nginx config
hosts: web
become: true
tasks:
- name: Copy vhost config
copy:
src: files/mysite.conf
dest: /etc/nginx/sites-available/mysite
notify: Validate and reload nginx
handlers:
- name: Validate and reload nginx
block:
- name: Check nginx config syntax
command: nginx -t
- name: Reload nginx
service:
name: nginx
state: reloaded
Здесь проверка синтаксиса и reload идут внутри одного handler'а: если nginx -t завершается с ошибкой, Ansible остановит выполнение и не даст команде reload выполниться на сломанной конфигурации. То же самое можно применить к десяткам серверов одной командой ansible-playbook, и результат будет идентичным на каждом — потому что конфигурация описана один раз, а не собрана из истории ручных правок.
Нужен сервер под эту задачу?
Разверните VPS MAATRIX за пару минут: NVMe, AMD EPYC, root-доступ, локации UK, США, Франция и РФ. Оплата картой РФ и по СБП.
Арендовать серверНужны сами нейросети для контента?
Генерируйте изображения, видео и озвучку нейросетями на falapi.io — десятки моделей в одном окне. Оплата картой РФ и по СБП.
Частые вопросы
А что, если сервер один и правки редкие — обязательно ли заводить git?
Даже для одного сервера git даёт то, чего не даст ничего другое: историю с датами и сообщениями, возможность посмотреть diff и откатиться одной командой. Локальный репозиторий занимает пару минут на настройку и полностью окупается при первом же «а что тут вообще менялось».
Можно ли обойтись без Ansible, если серверов немного?
Да — для одного-двух серверов достаточно связки git + nginx -t + простого деплой-скрипта, показанного выше. Ansible имеет смысл, когда серверов становится больше трёх-четырёх или когда конфигурацию нужно применять регулярно и предсказуемо.
nginx -t проверяет вообще всё, что может пойти не так?
Нет — она проверяет синтаксис и в целом валидность директив, но не логические ошибки вроде неверного proxy_pass на несуществующий бэкенд. Для таких случаев после reload стоит сразу проверить реальный ответ сервиса (curl на нужный location), а не полагаться только на успешный тест конфигурации.
А если конфиг правит панель управления (ISPmanager, aaPanel, cPanel)?
Такие панели часто перезаписывают файлы целиком при следующем сохранении через интерфейс, теряя ручные правки, сделанные в обход панели. Если используете панель, либо вносите изменения только через неё, либо выносите нестандартные блоки в отдельные include-файлы, которые панель не трогает — но всё равно держите их в git.
Что делать, если бардак с конфигами уже накопился и распутывать его страшно?
Начните с малого: скопируйте текущее рабочее состояние в git одним коммитом «as is», не пытаясь сразу привести всё в идеальный вид. Это уже даёт точку отсчёта — дальше можно постепенно наводить порядок, каждый раз коммитя изменения, вместо того чтобы откладывать «большую уборку» на потом.
Обсудить статью, задать вопрос или начать новую тему
Есть вопрос по этой статье, идея для обсуждения или просто хотите поделиться опытом? Сообщество MAATRIX ждёт. Для общения, пожалуйста, зарегистрируйтесь в нашем личном кабинете.
Перейти в сообщество →