Почему «поставили и забыли» с Drupal не работает
Меня зовут Евгений Семёнов, я технический директор ITfresh. Мы занимаемся IT-аутсорсингом для московских компаний до пятидесяти рабочих мест, держим собственные серверы в дата-центре МТС и уже больше пятнадцати лет сопровождаем чужие сайты вместе со всей инфраструктурой вокруг них. Это статья про самую скучную и одновременно самую важную часть жизни любого сайта на Drupal — про то, что происходит после запуска. Про будни, за которые клиент платит абонентскую плату и обычно не понимает, что именно получает.
У Drupal есть черта, которой нет почти ни у одной массовой CMS: официальная команда безопасности, которая публикует уязвимости открыто, по расписанию и с подробным описанием. Это огромная сила — вы всегда знаете, что именно нашли, насколько это критично и как закрыть. Но ровно та же открытость оборачивается риском для тех, кто не следит за обновлениями. В день публикации advisory уязвимость становится известна не только вам, но и всем, кто сканирует интернет в поисках лёгкой добычи. От выхода бюллетеня до массовых попыток эксплуатации на незакрытых сайтах проходят не недели, а часы.
История это подтверждала не раз. Уязвимости класса Drupalgeddon 2014 и 2018 годов вошли в учебники именно потому, что показали разницу между теми, кто обновился в первые сутки, и теми, кто «поставил и забыл». Вторые получали дефейс, майнеры или бэкдоры в кодовой базе. Вывод, к которому мы пришли на практике, звучит так: Drupal без регламента сопровождения опаснее, чем WordPress без регламента. Не потому что он хуже — потому что о его дырах узнают одновременно и защитник, и нападающий, и выигрывает тот, кто быстрее.
Регламент обновлений: как мы это делаем
Обновления — это не «когда дойдут руки», а календарь с жёсткими сроками реакции. Первое, что мы делаем при постановке сайта на сопровождение, — подписываем его на официальную рассылку security advisories. Бюллетени по ядру Drupal традиционно выходят по средам, и эта среда для нас — рабочий день, в который дежурный инженер первым делом открывает список свежих SA и смотрит, касается ли что-то из них наших сайтов.
Дальше работает классификация по критичности и типу. Мы делим все обновления на три корзины с разными сроками:
| Тип обновления | Срок реакции | Как выполняем |
|---|---|---|
| Security-патч ядра (highly critical / critical) | в течение 24 часов | внеочередное окно, обкатка на стенде, выкладка ночью |
| Security-патч contrib-модуля | до 72 часов | плановое ускоренное окно, зависит от того, включён ли уязвимый функционал |
| Минорные версии, фичи, не-security исправления | плановое окно раз в месяц | пакетно, вместе с регламентным обслуживанием |
Технически обновление у нас всегда проходит один и тот же путь и никогда не делается сразу на бою. Сначала — точная копия сайта на тестовом стенде, где мы обновляем зависимости через Composer, прогоняем сайт руками и автотестами, смотрим, не сломалась ли вёрстка и критичные сценарии (форма заявки, вход в личный кабинет, оформление). Только после этого — выкладка на прод с применением обновлений базы и импортом конфигурации.
# на тестовом стенде — обновляем ядро и модули
composer update drupal/core-* --with-all-dependencies
composer update drupal/webform drupal/metatag
# применяем миграции БД и импортируем конфиг
vendor/bin/drush updatedb -y
vendor/bin/drush config:import -y
vendor/bin/drush cache:rebuild
# прогон, ручная проверка, затем те же шаги на проде в окне обслуживания
Автообновления Drupal CMS: что они покрывают
В дистрибутиве Drupal CMS (актуальная ветка 2.0 вышла в июне 2026 года на ядре Drupal 11) из коробки идёт подсистема Automatic Updates. Для небольшого сайта-визитки, где нет самописных модулей, это отличная страховка: система сама умеет накатывать патчи ядра. Мы включаем её на простых проектах и очень рекомендуем всем, у кого нет подрядчика на сопровождении, — это лучше, чем ничего.
Но на серьёзном проде с интеграциями, самописным кодом и десятками contrib-модулей мы автообновления ядра оставляем в режиме уведомлений, а накат делаем руками. Причина простая: автообновление не знает про ваш конкретный набор модулей и не прогонит ваши бизнес-сценарии. Один неудачный патч, применённый ночью без присмотра на боевом сайте магазина, стоит дороже, чем сутки контролируемого ожидания. Автоматика хороша там, где цена ошибки низкая.
Подготовка к Drupal 12: начинаем заранее
Drupal 12.0.0 выходит на неделе 7 декабря 2026 года и потребует PHP 8.5, а также свежих версий СУБД — PostgreSQL 18, MySQL 8.0, MariaDB 10.11 или SQLite 3.45. Одновременно, 9 декабря 2026 года, заканчивается поддержка Drupal 10. Это значит, что сайты на «десятке» нужно перевести на Drupal 11 заранее, а сайты на «одиннадцатой» — готовить к переходу на двенадцатую, не откладывая на последнюю неделю.
Инструмент подготовки — модуль Upgrade Status. Он показывает, какие модули уже совместимы со следующей мажорной версией, а какие используют устаревший (deprecated) код и требуют доработки. Мы прогоняем его на каждом сайте за несколько месяцев до релиза, составляем список «долгов» и вычищаем их постепенно, в рамках плановых окон, а не авралом за неделю до дедлайна. Drupal 11, кстати, будет поддерживаться примерно до середины-конца 2028 года, так что запас времени есть — но он не бесконечен.
Бэкапы по схеме 3-2-1: что именно бэкапить в Drupal
Резервная копия Drupal-сайта — это не один файл. Сайт состоит из трёх принципиально разных частей, и каждую нужно сохранять своим способом:
| Компонент | Что это | Как бэкапим |
|---|---|---|
| База данных | весь контент, настройки, пользователи, сессии | ежедневный дамп mariadb-dump / mysqldump |
Каталог файлов sites/default/files | загруженные картинки, документы, медиа | инкрементальная синхронизация файлов |
| Кодовая база | ядро, модули, тема, composer.json/lock | git-репозиторий; vendor восстанавливается через composer install |
Отдельно бэкапить папку vendor смысла нет — она детерминированно восстанавливается командой composer install из зафиксированного composer.lock. А вот про каталог загруженных файлов забывают чаще всего, и потом на восстановленном сайте зияют пустые рамки вместо картинок.
Наша рабочая схема — классическая 3-2-1: три копии, на двух разных носителях, одна из которых — вне площадки. На практике это выглядит так: ночной дамп базы и синхронизация файлов на локальный диск сервера, затем копия улетает на независимый FTP-сток, физически стоящий в другом дата-центре, ротация — тридцать дней. Даже если основная площадка целиком выйдет из строя, у нас есть вчерашний слепок в другом городе.
# ночной бэкап: дамп БД + архив файлов
DATE=$(date +%F)
mariadb-dump --single-transaction --quick drupal_db | gzip > /backup/db-$DATE.sql.gz
tar czf /backup/files-$DATE.tar.gz -C /var/www/drupal/web/sites/default files
# копия на удалённый сток в другом ЦОД + ротация 30 дней
rsync -a /backup/ backup@ftp-dc2:/itfresh/site/
find /backup -type f -mtime +30 -delete
Конфигурация в git как «нулевой» бэкап структуры
В Drupal вся структура сайта — типы контента, поля, представления Views, настройки модулей — выгружается в YAML-файлы механизмом Configuration Management. Мы держим этот экспорт в git рядом с кодом. Это даёт две вещи. Во-первых, любое изменение структуры видно в истории: кто, когда и что поменял. Во-вторых, при восстановлении структура накатывается командой drush config:import детерминированно, без ручного пересобирания настроек. По сути это «нулевой» уровень бэкапа — резервная копия того, как сайт устроен, отдельно от того, что в нём лежит.
Hardening: закручиваем гайки
Обновления закрывают известные дыры, а hardening уменьшает поверхность атаки и цену ошибки. Это разовая работа при запуске плюс ежеквартальная ревизия. Вот наш базовый чек-лист, который мы проходим по каждому сайту:
| Что делаем | Зачем |
|---|---|
Код — read-only для PHP-процесса, запись только в files | взломщик не сможет дописать бэкдор в модуль или тему |
settings.php с правами 440 | файл с паролем БД не читается посторонними процессами |
Прописан trusted_host_patterns | защита от подмены заголовка Host и связанных атак |
Запрет исполнения PHP в каталоге files на уровне nginx | залитый через дыру «аватар».php не выполнится |
| Переименован путь входа + fail2ban по логам | боты не находят /user/login и не перебирают пароли |
| Двухфакторная аутентификация админов (модуль TFA) | украденный пароль сам по себе не даёт доступа |
| Ревизия учётных записей раз в квартал | убираем уволенных, лишние права, забытые тестовые аккаунты |
Отдельно про исполнение PHP в каталоге загрузок — это одна из самых частых точек входа. Даже если валидацию форм обошли и залили вредоносный файл, он не должен выполниться. На nginx это делается коротким правилом:
location ~ ^/sites/.*/files/.*\.php$ {
deny all;
return 403;
}
Модуль Security Kit и HTTP-заголовки
Модуль Security Kit (Seckit) закрывает целый класс клиентских атак через правильные заголовки: Content-Security-Policy ограничивает, откуда грузятся скрипты, X-Frame-Options защищает от кликджекинга, настраиваются политики referrer и другие мелочи. Это не заменяет обновления, но заметно усложняет жизнь тем, кто пытается встроить в ваши страницы чужой JavaScript.
Чего делать не надо
Самая частая ошибка — подменять обновления «безопасностью через неизвестность». Переименовали админку, спрятали версию Drupal в мете, поставили пароль на весь сайт через .htaccess — и решили, что теперь можно не обновляться. Это самообман. Скрытие пути входа осмысленно только как дополнение к fail2ban против брутфорса, но оно ни на секунду не защищает от эксплуатации известной уязвимости в модуле. Обновления первичны, всё остальное — вторично.
Мониторинг: что мы смотрим по каждому сайту
Сопровождать сайт вслепую нельзя. Минимальный набор датчиков, который мы вешаем на каждый проект, выглядит так:
- Внешний uptime-чек — раз в минуту дёргаем главную из внешней точки. Упало — алерт дежурному, а не «клиент позвонил через два часа».
- Срок действия TLS-сертификата — предупреждение за две недели до истечения. Просроченный сертификат — это красный замок в браузере у всех посетителей и мгновенная потеря доверия.
- Статус-отчёт Drupal — встроенная страница
/admin/reports/statusдля нас источник правды: она сама сообщает о доступных обновлениях безопасности, проблемах с правами, устаревшем PHP. - Лог watchdog в syslog, а не в базу — иначе таблица логов раздувает БД. Пишем в syslog и собираем централизованно.
- Контроль cron — если системный крон Drupal молчит дольше трёх часов, приходит алерт: значит, не идут отложенные задачи, индексация поиска, отправка почты.
По каждому датчику определён порог реакции и кто дежурит. Алерт без ответственного — это просто шум, который со временем начинают игнорировать.
Типовые деградации и их лечение
Есть набор болячек, которые встречаются на Drupal-сайтах из раза в раз. Распухшие таблицы cache_* — лечится корректной настройкой времени жизни кеша и его периодической очисткой. Зависший batch-процесс (импорт, массовое обновление) — держит блокировку и мешает работе, снимается вручную. Забитая таблица сессий — от ботов, которые создают тысячи анонимных сессий; помогает вынос сессий в отдельное хранилище и агрессивная очистка. Все три сценария мы отлавливаем по росту размера базы на графиках задолго до того, как они превращаются в «сайт тормозит».
Производительность в долгую: сайт не должен «стареть»
Сайт незаметно деградирует год за годом: база пухнет, кеш работает всё хуже, запросы становятся тяжелее. Чтобы этого не происходило, раз в квартал мы проводим ревизию производительности и смотрим на конкретные метрики:
- размер базы в целом и таблиц
cache_*в частности — резкий рост сигнализирует о проблеме; - включена ли агрегация и минификация CSS/JS — на проде она должна быть включена всегда;
- hit rate у opcache — если кеш байткода часто промахивается, PHP компилирует одно и то же по кругу;
- медленные запросы MariaDB из slow query log — источник большинства тормозов.
Отдельный вопрос — когда добавлять Redis для кеша и сессий. Ответ: когда база реально становится узким местом под нагрузкой, а не «на всякий случай». Очень часто тормозит не отсутствие Redis, а кривой Views с сотней джойнов, который кто-то собрал мышкой без понимания, во что это разворачивается в SQL. Сначала мы чиним такие запросы, и лишь потом, если нагрузка объективно высокая, подключаем внешний кеш. По нашему опыту, для типового корпоративного сайта на приличном VPS нормой считается время до первого байта (TTFB) в пределах пары сотен миллисекунд; если оно уползает к секунде и выше — это повод для разбирательства, а не «так и должно быть».
Обновление PHP и операционной системы под сайтом
Здесь кроется ловушка, о которой владельцы бизнеса обычно не думают: жизненный цикл PHP короче жизненного цикла сайта. Корпоративный сайт живёт пять-семь лет, а за это время сменяется два-три мажорных релиза PHP, каждый со своим сроком поддержки. Держать под сайтом версию PHP, которая уже не получает патчей безопасности, — значит оставить дыру, которую никаким обновлением Drupal не закрыть.
Матрица совместимости, из которой мы исходим:
| Версия Drupal | Минимум PHP | Рекомендуемо | Статус |
|---|---|---|---|
| Drupal 10 | PHP 8.1 | PHP 8.3 | EOL 9 декабря 2026 — переводить на 11 |
| Drupal 11 | PHP 8.3 | PHP 8.4 (в 11.1/11.2) | актуальная, поддержка ~до 2028 |
| Drupal 12 | PHP 8.5 | PHP 8.5 | релиз — неделя 7 декабря 2026 |
Порядок обновления PHP тот же, что и у самого Drupal: сначала стенд с новой версией, полный прогон сайта, проверка совместимости модулей, и только потом — прод. Точно так же мы поступаем с операционной системой: переезжаем с одного LTS-релиза Debian или Ubuntu на следующий заблаговременно, не дожидаясь окончания поддержки. Мы принципиально не оставляем сайты жить на EOL-системах, даже если «оно работает». «Работает» до первого эксплойта в неподдерживаемом компоненте, после которого чинить приходится уже не сайт, а последствия взлома.
Сколько это стоит и как выглядит SLA
Теперь про деньги — для владельца бизнеса это главный раздел. Абонентская плата за сопровождение Drupal складывается из нескольких предсказуемых частей:
| Статья | Что входит |
|---|---|
| Мониторинг | датчики, дежурство, реакция на инциденты по SLA |
| Окна обновлений | отслеживание advisories, обкатка на стенде, выкладка |
| Бэкапы | ежедневные копии, хранение вне площадки, квартальные учения по восстановлению |
| Пул часов | N часов работ в месяц на правки, доработки, консультации |
Честно скажу: сопровождение Drupal у нас стоит примерно на 30–50% дороже, чем сопровождение аналогичного сайта на WordPress. Причина не в жадности, а в рынке труда: специалистов по Drupal объективно меньше, их квалификация и ставка выше, а порог входа в проект глубже. Зато и инцидентов, при правильном регламенте, кратно меньше.
Окупается это стоимостью одного-единственного инцидента. Взлом сайта — это не только его восстановление. Это простой, потеря заявок, разбирательство, не попал ли сайт в чёрные списки, не утекли ли персональные данные клиентов (а это уже 152-ФЗ и штрафы). Один такой случай перекрывает годы аккуратной абонентки.
Оставить комментарий