Меня зовут Евгений Семёнов, я технический директор компании «АйТи Фреш». Мы больше пятнадцати лет занимаемся IT-аутсорсингом для московских компаний до 50 рабочих мест и держим собственные серверы в дата-центре МТС. В первой статье серии я объяснял, почему восемь из десяти клиентских сайтов мы делаем на WordPress. Сегодня — чистая практика: внутренний регламент, по которому наши инженеры разворачивают WordPress 7.0 в продакшен, от выбора площадки до первого проверенного бэкапа. Все команды и конфиги ниже — рабочие, именно их мы гоняем на своей панели HestiaCP. Можете повторить шаг за шагом сами или отдать статью подрядчику как техзадание.
Два сценария размещения и как мы выбираем
Первое решение принимается до того, как скачан хоть один файл: где сайт будет жить. Вариантов для малого бизнеса ровно два, и выбор между ними — вопрос арифметики, а не религии.
Shared-хостинг за 200–500 рублей в месяц: когда его достаточно
Визитка, сайт услуг, корпоративный блог — всё, что держит до ~5 тысяч визитов в сутки, — прекрасно живёт на обычном виртуальном хостинге. За 200–500 рублей в месяц вы получаете панель управления, свежий PHP, базу данных, автоматический SSL и чужую головную боль про обновления серверного софта. Минусы известны: соседи по серверу, лимиты на процессы и память, невозможность тонко настроить окружение. Для сайта-визитки эти минусы не стоят разницы в цене.
VPS с панелью: когда сайтов несколько или нужен WooCommerce
VPS от 500–1000 рублей в месяц мы берём в трёх случаях: сайтов больше одного (на своём сервере каждый следующий сайт бесплатен), нужен WooCommerce с его аппетитом к PHP-воркерам, или клиенту важна изоляция от соседей. Панель управления обязательна — поддерживать клиентский сайт руками в консоли дорого и хрупко. Мы используем бесплатную HestiaCP (на ней построен и наш собственный хостинг), из коммерческих альтернатив в РФ распространён ISPmanager. Панель даёт то же удобство, что shared-хостинг — сайты, базы, почта, SSL в пару кликов, — но сервер целиком ваш.
| Критерий | Shared-хостинг | VPS + панель |
|---|---|---|
| Цена | 200–500 ₽/мес за сайт | 500–1500 ₽/мес за сервер целиком |
| Кому подходит | визитка, сайт услуг, блог | несколько сайтов, WooCommerce, трафик от 5 тыс. визитов/сутки |
| Доступ | FTP/SSH в рамках аккаунта | root, любые настройки |
| Ответственность за сервер | хостер | вы или ваш подрядчик |
Требования WordPress 7.0: на чём его вообще можно запускать
WordPress 7.0 «Armstrong» вышел 20 мая 2026 года, и с ним минимальные требования подросли. Формальный минимум — PHP 7.4 и MySQL 8.0 либо MariaDB 10.6. Важный нюанс, о котором хостеры не предупреждают: сайты на PHP 7.2 и 7.3 автообновление до 7.0 не получают вовсе — они молча остаются на security-ветке 6.9. Если ваш сайт «давно не просил обновиться», проверьте версию PHP: возможно, он уже отрезан от мажорных релизов.
Минимум — это «заведётся», а не «хорошо поедет». Разработчики рекомендуют PHP 8.3+ и MySQL 8.4 LTS либо MariaDB 11.4 LTS. Наш стандарт для новых площадок: мы ставим PHP 8.3 и MariaDB 11.4 — обе ветки с долгосрочной поддержкой, обе дают ощутимый прирост скорости против минимума. Ещё два обязательных пункта: HTTPS (без него в 2026-м сайт не существует ни для браузеров, ни для поисковиков) и свежий корректирующий релиз — 9 июля 2026 года вышел 7.0.1 с 31 багфиксом и 3 патчами безопасности, новые сайты разворачиваем сразу на нём. Следующий мажорный релиз 7.1 назначен на 19 августа 2026-го, но ждать его новым проектам незачем.
Совет: прежде чем оплачивать хостинг на год вперёд, откройте в панели список доступных версий PHP. Если максимум — 8.1 или, хуже, 7.4, хостер живёт прошлым, и через год-два вы упрётесь в это ограничение снова, уже с работающим сайтом на руках.
Готовим площадку: LEMP-стек за 20 минут
Дальше идёт сценарий VPS — на shared-хостинге эти шаги за вас уже сделал хостер. Наш стек классический LEMP: Linux, nginx, MariaDB, PHP-FPM. Панель HestiaCP разворачивает его сама, но понимать, что она делает под капотом, обязан каждый, кто подписывается сайт сопровождать.
nginx против Apache: наш выбор и почему
Исторически WordPress «женат» на Apache: правила красивых ссылок лежат в .htaccess, и большинство инструкций в интернете написано под него. Мы тем не менее ставим nginx, и причина инженерная: nginx не перечитывает .htaccess на каждый запрос (этого файла у него просто нет), статику отдаёт заметно дешевле по памяти, а вся маршрутизация WordPress укладывается в одну строку try_files. Вот скелет server-блока, который мы используем:
# /etc/nginx/conf.d/client-site.conf — минимум для WordPress
server {
listen 443 ssl http2;
server_name client-site.ru www.client-site.ru;
root /home/client/web/client-site.ru/public_html;
index index.php;
# красивые ссылки WordPress — вся магия в одной строке
location / {
try_files $uri $uri/ /index.php?$args;
}
location ~ \.php$ {
include fastcgi_params;
fastcgi_param SCRIPT_FILENAME $document_root$fastcgi_script_name;
fastcgi_pass unix:/run/php/php8.3-fpm-client.sock;
}
# статика — мимо PHP, с длинным кешем
location ~* \.(css|js|png|jpg|webp|avif|svg|woff2)$ {
expires 30d;
access_log off;
}
# закрываем служебное
location ~ /\.(?!well-known) { deny all; }
location = /xmlrpc.php { deny all; }
}
Последняя строка — не паранойя. Файл xmlrpc.php почти никому не нужен уже лет десять, а брутфорс-боты долбятся в него круглосуточно; закрыв его на уровне nginx, вы срезаете львиную долю мусорного трафика ещё до запуска PHP.
PHP-FPM: отдельный пул на каждый сайт
Главное правило сервера с несколькими сайтами: один сайт — один пул PHP-FPM со своим системным пользователем. Тогда взлом одного сайта не превращается в эпидемию — процессы соседа физически не могут писать в чужие каталоги. HestiaCP делает это по умолчанию; если настраиваете руками, вот наши базовые значения:
; /etc/php/8.3/fpm/pool.d/client-site.conf
[client-site]
user = client
group = client
listen = /run/php/php8.3-fpm-client.sock
pm = ondemand
pm.max_children = 10
pm.process_idle_timeout = 30s
php_admin_value[memory_limit] = 256M
php_admin_value[upload_max_filesize] = 64M
php_admin_value[post_max_size] = 64M
php_admin_value[opcache.validate_timestamps] = 0
Про последнюю строку — честная оговорка. opcache.validate_timestamps = 0 даёт максимум скорости: PHP не проверяет файлы на изменения и исполняет код из кеша. Но после любого обновления плагина кеш надо сбрасывать (перезагрузкой FPM), иначе сайт продолжит крутить старый код. На сайтах, где клиент сам ставит обновления из админки, мы оставляем проверку включённой с opcache.revalidate_freq = 60 — чуть медленнее, зато без сюрпризов.
База: отдельный пользователь с правами только на свою БД
Вторая типовая ошибка после «всё от root» — один пользователь MariaDB на все сайты сервера. SQL-инъекция в одном заброшенном плагине откроет тогда все базы разом. Правильно так:
CREATE DATABASE client_wp
CHARACTER SET utf8mb4 COLLATE utf8mb4_unicode_ci;
CREATE USER 'client_wp'@'localhost'
IDENTIFIED BY 'длинный-случайный-пароль-из-менеджера';
GRANT ALL PRIVILEGES ON client_wp.* TO 'client_wp'@'localhost';
FLUSH PRIVILEGES;
Права — только на свою базу, подключение — только с localhost. Пароль генерирует менеджер паролей, и туда же он сразу записывается: «временных» паролей в нашем регламенте не существует, потому что нет ничего более постоянного, чем временное.
Установка через WP-CLI, а не через браузер
Классическая установка — скачать архив, распаковать, открыть сайт в браузере, заполнить формочку — работает, но не воспроизводится. WP-CLI, официальный консольный инструмент WordPress, превращает установку в четыре команды, которые можно положить в скрипт, повторить на staging-копии и вписать в документацию. Наши инженеры браузерный установщик не открывают вообще:
cd /home/client/web/client-site.ru/public_html
# ядро с русской локалью
wp core download --locale=ru_RU
# wp-config.php: доступы к БД + свой префикс таблиц
wp config create --dbname=client_wp --dbuser=client_wp \
--dbpass='пароль-из-менеджера' --dbprefix=itf7_ --locale=ru_RU
# установка: URL, название, администратор
wp core install --url=https://client-site.ru \
--title='Название компании' --admin_user=cl_admin \
--admin_email=admin@client-site.ru --prompt=admin_password
# языковой пакет и активация
wp language core install ru_RU --activate
Обратите внимание на две детали. Пароль администратора передаётся через --prompt, а не открытым текстом в командной строке — иначе он навсегда останется в истории shell. И логин админа — не «admin»: словарные логины боты перебирают в первую очередь, зачем дарить им половину пары логин-пароль.
Почему мы фиксируем версию ядра в паспорте сайта
Сразу после установки вывод wp core version --extra уходит в «паспорт сайта» — внутренний документ клиента, где записаны версии ядра, PHP и базы, список плагинов с датами установки и все доступы. Звучит бюрократично, а экономит часы: когда через год сайт закапризничает, первый вопрос диагностики — «что и когда обновлялось», и ответ должен находиться за минуту, а не выпрашиваться у предыдущего подрядчика.
«Пятиминутная установка» двадцать лет спустя
WordPress в своё время прославился «знаменитой пятиминутной установкой» — по меркам середины нулевых это была фантастика, конкуренты требовали часа возни с конфигами. Ирония в том, что сегодня пять минут — это медленно: скриптованная установка через WP-CLI занимает меньше минуты. Но главная её ценность не скорость, а одинаковость: два сайта, поставленные одним скриптом, отличаются только контентом. Это фундамент дешёвой поддержки.
wp-config.php: харднинг до запуска, а не после взлома
Свежеустановленный WordPress работоспособен, но по умолчанию доверчив. Пять минут работы с wp-config.php до передачи сайта клиенту закрывают самые частые векторы, которые мы видим при разборах чужих взломов.
Соли и ключи
Восемь секретных ключей в wp-config.php подписывают cookie сессий. wp config create генерирует их автоматически, но если сайт достался вам «в наследство» или случился инцидент — одна команда wp config shuffle-salts перевыпускает все ключи и мгновенно разлогинивает всех, включая злоумышленника с украденной cookie. Мы выполняем её при каждом приёме чужого сайта на обслуживание.
Три константы, которые мы дописываем всегда
/* редактор файлов в админке — выключить: укравший пароль
не сможет вписать бэкдор прямо в файлы темы */
define('DISALLOW_FILE_EDIT', true);
/* лимит ревизий: без него каждая правка страницы
вечно хранится в БД и раздувает её на гигабайты */
define('WP_POST_REVISIONS', 10);
/* минорные обновления ядра — автоматически */
define('WP_AUTO_UPDATE_CORE', 'minor');
Сюда же относится префикс таблиц: не wp_, а свой — мы задали itf7_ ещё на этапе wp config create. Это не защита, а фильтр от самых примитивных автоматических инъекций, бьющих по именам таблиц по умолчанию. Но фильтр бесплатный, отказываться странно.
FS_METHOD: грабля с обновлениями на shared
Если WordPress при попытке обновить плагин вдруг спрашивает «данные FTP» — вы наступили на классику: файлы сайта принадлежат одному системному пользователю, а PHP работает от другого. Ядро, не сумев писать напрямую, откатывается на метод ftpext. Правильное лечение — не вбивать FTP-пароль в конфиг (мы находили его там открытым текстом не раз), а привести владельца файлов в соответствие с пользователем PHP-FPM и явно закрепить define('FS_METHOD', 'direct');.
Права на файлы: 644/755 и никакого root
Типовая ошибка после ручного переноса: архив распаковали от root — и вся файловая структура принадлежит root. Дальше два сценария, оба плохие. Либо ничего не обновляется (см. выше), либо предыдущий админ «починил» это через chmod 777 — и теперь писать в каталоги сайта может любой процесс сервера. Канон такой:
chown -R client:client /home/client/web/client-site.ru/public_html
cd /home/client/web/client-site.ru/public_html
find . -type d -exec chmod 755 {} \;
find . -type f -exec chmod 644 {} \;
chmod 600 wp-config.php
Каталоги 755, файлы 644, конфиг с паролем от базы — 600. Владелец — пользователь сайта, тот же, от которого работает его пул PHP-FPM.
Обязательный минимум плагинов: шесть, а не сорок
Каждый плагин — чужой код с полными правами внутри вашего сайта, поэтому наш стандартный набор при сдаче — ровно шесть позиций, и на каждую новую хотелку клиента мы сначала отвечаем вопросом «а что удалим взамен?». Как я разбирал в обзоре WordPress 2026, девять из десяти взломов приходят через заброшенные плагины и темы — короткий список сам по себе мера безопасности. Каждый плагин сверх первого десятка — минус к скорости и плюс к поверхности атаки.
| № | Роль | Зачем обязателен |
|---|---|---|
| 1 | Кэширование страниц | отдаёт готовый HTML вместо исполнения PHP на каждый визит; на shared это разница между «летает» и «лёг при первом наплыве» |
| 2 | SEO-плагин | карта сайта, метатеги, разметка Schema.org — без него сайт для поисковиков полуслеп |
| 3 | Форма обратной связи | заявки — смысл существования корпоративного сайта |
| 4 | SMTP-почта | без него письма с форм не доходят — разбор ниже |
| 5 | Антиспам для форм | иначе через неделю в заявках будет 95% ботов, и клиент перестанет их читать — вместе с настоящими |
| 6 | Бэкапы | копия файлов и БД по расписанию на внешнее хранилище |
Про SMTP — подробнее, потому что «сайт сломан, заявки не приходят» — самая частая жалоба на новых сайтах. По умолчанию WordPress шлёт почту функцией mail() прямо с хостинга: IP shared-сервера изгажен соседями-спамерами, у письма нет ни SPF, ни DKIM — и оно честно уезжает в спам или отбрасывается на входе. Мы всегда переключаем отправку на SMTP реального почтового сервера клиента (или нашего, если своей почты у клиента нет): письмо уходит с легитимного домена с подписями, и доставляемость перестаёт быть лотереей.
Конкретные названия плагинов я сознательно не навязываю: в каждой роли есть два-три живых конкурента, и расклад меняется от года к году. Критерии выбора те же, что для тем: обновление за последние полгода, большая база установок, живая поддержка.
Тема: готовая, детская или блочная
Критерии выбора темы из каталога
Тема — самый большой кусок стороннего кода на сайте, поэтому выбираем её по анкете, а не по красоте демо-страницы:
- обновлялась за последние 6 месяцев — заброшенная тема не получит совместимости со следующими релизами ядра и PHP;
- от ~50 тысяч активных установок — массовость означает, что баги находят и чинят раньше, чем они дойдут до вас;
- заявлена совместимость с веткой 7.x — после мажорного релиза это уже не формальность;
- без строительного мусора — тема, которая тянет за собой пять «обязательных» плагинов и мегабайты скриптов, обернётся тормозами, какой бы красивой ни была.
Child-тема: страховка от потери правок
Любая правка файлов темы напрямую живёт до первого её обновления — обновление молча перезаписывает файлы. Поэтому все кастомизации — только в дочерней (child) теме. Это папка из двух файлов, создаётся за пять минут:
/* wp-content/themes/client-child/style.css */
/*
Theme Name: Client Child
Template: parent-theme-slug
*/
/* wp-content/themes/client-child/functions.php */
<?php
add_action('wp_enqueue_scripts', function () {
wp_enqueue_style('parent-style',
get_template_directory_uri() . '/style.css');
});
Родительская тема обновляется штатно, ваши правки живут отдельно и переживают любые апдейты. Сайты, где CSS правили прямо в родительской теме, мы узнаём мгновенно — по фразе клиента «после обновления всё съехало».
FSE-темы: когда блочное редактирование всего сайта — рано
Блочные FSE-темы позволяют редактировать в Gutenberg не только контент, но и шапку, подвал, сетки архивов — весь сайт целиком, без строчки кода. Технология зрелая, и новые проекты «с нуля» мы всё чаще делаем именно на них. Но даём такую свободу не всем: FSE — для клиентов, у которых контентом занимается один вдумчивый человек. Там, где «сайт правят раз в квартал всем офисом», ставим классическую тему с child-надстройкой: возможность одним движением мыши перекроить подвал сайта — обоюдоострая.
HTTPS и домен: сертификат, редиректы и переезд URL
Сертификат — Let's Encrypt, бесплатно и из панели: HestiaCP выпускает и продлевает его сама, вмешательство требуется ноль раз в год. Руками через certbot тоже можно, но тогда автопродление обязано сидеть в cron, и его надо проверить заранее: просроченный сертификат — самый глупый способ уронить сайт в выходные.
Сразу же решаем вопрос зеркал: сайт должен отвечать по одному каноническому адресу, а остальные варианты — http://, с www и без — отдавать 301-редирект на него. Иначе поисковики размажут вес между четырьмя «разными» сайтами.
wp search-replace: почему нельзя простым SQL UPDATE
При смене адреса — переезде с технического поддомена на боевой домен или с http на https — старый URL зашит в базе тысячами копий. Соблазн выполнить UPDATE ... REPLACE(...) велик, и это классическая ошибка. Часть данных WordPress хранит сериализованными: строка записана вместе со своей длиной, что-то вроде s:26:"http://client-site.ru/img/". Замените текст простым REPLACE — длина перестанет совпадать с содержимым, и PHP молча выбросит такие данные: слетают настройки темы, виджеты, поля плагинов. wp search-replace разбирает сериализованные структуры и пересчитывает длины сам:
# сначала репетиция — ничего не меняет, показывает масштаб
wp search-replace 'http://client-site.ru' 'https://client-site.ru' \
--all-tables --dry-run
# убедились — выполняем
wp search-replace 'http://client-site.ru' 'https://client-site.ru' \
--all-tables
И перед боевым запуском — бэкап базы, всегда: wp db export занимает секунды, а спасает часы.
Чек-лист сдачи сайта клиенту
Сайт считается сданным не когда «выглядит готовым», а когда закрыт каждый пункт этого списка. Он висит у нас в регламенте, и подписывает его инженер, а не менеджер:
- HTTPS работает и продлевается сам — проверено, что автопродление реально отработало, а не «должно работать»;
- бэкап настроен и восстановление проверено — копия файлов и базы уезжает на независимое хранилище, и мы хотя бы раз развернули её на тестовой площадке;
- админ-доступ есть у клиента, а не только у подрядчика — отдельная учётная запись администратора на почту клиента;
- все пароли — в менеджере паролей клиента: хостинг, домен, админка, база, SMTP;
- SMTP работает: тестовое письмо с формы дошло до реального ящика, а не до папки «Спам»;
- формы доходят: каждая форма сайта отправлена и получена;
- robots.txt и карта сайта на месте, сайт открыт для индексации — галочку «попросить поисковики не индексировать» после разработки забывают снять пугающе часто;
- мониторинг доступности включён: если сайт упадёт, первым узнает подрядчик, а не клиент от своего покупателя.
Философия списка одна: сайт принадлежит клиенту. Домен зарегистрирован на компанию клиента, доступы у клиента, документация у клиента. Мы регулярно принимаем сайты, где всё это осталось у пропавшего подрядчика, — каждый такой случай стоит клиенту недель переписки, а иногда и домена.
Сколько это стоит и сколько занимает
Честная разбивка типового проекта «корпоративный сайт услуг на готовой теме» по нашей практике:
| Этап | Трудоёмкость | Комментарий |
|---|---|---|
| Площадка: хостинг или VPS, DNS, LEMP, SSL | ~2 часа | на shared быстрее; на VPS с панелью — в те же два часа |
| Установка, харднинг, шесть плагинов | ~3 часа | всё по регламенту выше; скриптованная часть — минуты |
| Тема, структура, наполнение | 1–2 дня | основное время: тексты, фото, страницы услуг — зависит от готовности материалов у клиента |
| Чек-лист сдачи, паспорт сайта | ~2 часа | включая проверку восстановления бэкапа |
Итого 1–3 рабочих дня и типовой бюджет 40–80 тысяч рублей силами подрядчика — против «бесплатного» конструктора с вечной арендой и потолком возможностей или заказной разработки от 300 тысяч. Самая честная строка сметы — третья: техника разворачивается за полдня по регламенту, а сроки делает контент. Если тексты и фотографии у клиента готовы, сайт выходит в продакшен за неделю с запасом.
Дальше в серии — переезд на WordPress с конструкторов и старых самописных движков без потери позиций в поиске, и эксплуатация: обновления, мониторинг, защита. А если разворачивать по этой инструкции некому или некогда — напишите: развернём по своему же регламенту и сдадим по этому же чек-листу. Telegram @ITfresh_Boss или +7 903 729-62-41.
Оставить комментарий