WordPress multisite как платформа: как построить мультитенантную SaaS-систему (когда одного сайта мало)

Вы разрабатываете SaaS-сервис для малого бизнеса, платформу для онлайн-курсов или конструктор сайтов. Каждому клиенту нужен его собственный, изолированный сайт с личным доменом, данными и настройками, но на единой кодовой базе. Разворачивать для каждого отдельный инстанс WordPress — администрирование превратится в кошмар. Решение — мультитенантная архитектура на базе WordPress Multisite. Это режим, когда одно ядро WordPress управляет сетью из сотен или тысяч независимых сайтов. Давайте разберемся, как правильно построить такую систему, какие подводные камни ждут и как сделать её масштабируемой и безопасной.


Часть 1: Multisite vs Отдельные установки. Когда это нужно?

WordPress Multisite — это режим работы, при котором у вас одна база данных (с особыми префиксами таблиц для каждого подсайта) и одна общая папка с файлами (темы, плагины, загрузки в wp-content/uploads/sites/{ID}/).

Идеальные сценарии для Multisite:

  1. Корпоративные сети: Компания с головным сайтом и десятками сайтов филиалов/отделов.

  2. Образовательные платформы: Где каждый курс или группа студентов получает свой блог.

  3. SaaS-конструкторы сайтов: Выдаёте клиентам доступ к их подсайту с кастомизируемой темой.

  4. Новостные порталы с городскими версиями: city1.site.rucity2.site.ru.

  5. Большие сообщества с личными блогами (как WordPress.com).

Когда НЕ нужно использовать Multisite:

  • Сайты с кардинально разными требованиями к плагинам и темам.

  • Если вам критически важна полная изоляция сбоев (падение одного сайта не должно влиять на другие).

  • Когда клиентам нужен полный FTP/админский доступ к своим файлам (в Multisite это риск безопасности для всей сети).

Часть 2: Включение Multisite и базовая архитектура

Включение требует правки wp-config.php и .htaccess (для Apache).

  1. Добавьте в wp-config.php перед /* That's all, stop editing! */:

    php
    define('WP_ALLOW_MULTISITE', true);
  2. В админке появится новый раздел «Инструменты → Настройка сети». Выберите структуру:

    • Поддомены (site1.main.com): Требует настройки wildcard DNS (*.main.com), что сложнее, но чище с точки зрения изоляции cookie.

    • Подпапки (main.com/site1/): Проще в настройке, не требует wildcard DNS, но все сайты в одном домене.

  3. Скопируйте сгенерированный код в wp-config.php и .htaccess.

  4. Важные константы для контроля:

    php
    define('MULTISITE', true); define('SUBDOMAIN_INSTALL', false); // true для поддоменов define('DOMAIN_CURRENT_SITE', 'main.com'); define('PATH_CURRENT_SITE', '/'); define('SITE_ID_CURRENT_SITE', 1); define('BLOG_ID_CURRENT_SITE', 1); // Ограничиваем использование тем/плагинов только суперадмином define('ALLOW_UNFILTERED_UPLOADS', false); // Опасная опция!

Часть 3: Управление сетью: суперадмин, темы, плагины

  • Суперадминистратор (Super Admin): Новый уровень привилегий. Видит пункт «Сеть администрирования». Может управлять всеми сайтами, включать/отключать темы и плагины для всей сети.

  • Плагины и темы: Устанавливаются на уровне сети. Суперадмин может «включить для сети» (плагин активен на всех сайтах) или «включить» для отдельных сайтов. Невозможно загрузить плагин только для одного сайта — только для всех.

  • Обновления: Обновления ядра, тем и плагинов делает только суперадмин для всей сети сразу. Это и плюс (централизованно), и минус (нужно тестировать, чтобы не сломать всё).

Часть 4: Изоляция данных и кастомизация для каждого сайта (тенанта)

1. Данные пользователей:

  • По умолчанию пользователи сети — глобальные. Зарегистрировавшись на одном сайте, они есть в базе, но не являются участниками других сайтов.

  • Можно добавить пользователя на другой сайт с другой ролью.

  • Проблема: Пользователь заходит в свой профиль — он общий для всей сети. Если вам нужна полная изоляция профилей — это сложно.

2. Медиафайлы: Изолированы по умолчанию. Загрузки сайта с ID=3 идут в wp-content/uploads/sites/3/2024/05/photo.jpg.

3. Настройки (опции): Каждый сайт имеет свою таблицу wp_{id}_options. Настройки полностью изолированы.

4. Проблема: «Сайто-специфичные» плагины и темы.

  • Темы: Суперадмин загружает тему, затем на странице конкретного сайта может её включить и кастомизировать (через кастомайзер). Но у всех сайтов будет один и тот же functions.php этой темы.

  • Решение для уникального кода: Используйте mu-plugins (must-use plugins). Файлы из wp-content/mu-plugins/ загружаются автоматически для всех сайтов. Внутри такого плагина можно писать логику, зависящую от get_current_blog_id().

php
// wp-content/mu-plugins/tenant-specific.php add_action('init', 'my_tenant_logic'); function my_tenant_logic() { $current_blog_id = get_current_blog_id(); if ($current_blog_id == 5) { // Код только для сайта с ID=5 define('SPECIAL_FEATURE', true); } }

Часть 5: Производительность и масштабирование для сотен сайтов

Здесь Multisite показывает свои ахиллесовы пяты.

  1. Кэширование объекта (Object Caching) — ОБЯЗАТЕЛЬНО. Без кэша каждое обращение к switch_to_blog() (переключение контекста между сайтами) порождает массу запросов к wp_{id}_optionsRedis или Memcached с плагином типа Redis Object Cache критически важны.

  2. Оптимизация базы данных:

    • Таблица wp_blogs и wp_site — маленькие.

    • Главные «тяжеловесы» — wp_{id}_postswp_{id}_postmetawp_{id}_options.

    • При 1000 сайтов у вас 1000 таблиц _options. Запросы нужно тщательно оптимизировать.

  3. Выделение ресурсов: На одном сервере «шумный сосед» (сайт с высокой посещаемостью) может замедлить все остальные. Решения:

    • Вынос медиафайлов в CDN (например, Cloudflare R2, S3) через плагин.

    • Горизонтальное масштабирование БД: Репликация чтения, выделение мастер-сервера для записи.

    • Расслоение по серверам: Критически важные сайты — на отдельном VPS.

  4. Поиск: Стандартный поиск ищет только в рамках текущего сайта. Для глобального поиска по сети нужны решения вроде ElasticPress с поддержкой Multisite.

Часть 6: Безопасность: если взломают один сайт?

Это самый большой страх. В классической установке взлом одного сайта изолирован. В Multisite — угроза всей сети, так как общее ядро и плагины.

Меры защиты:

  1. Строгий контроль плагинов и тем. Только проверенные, обновляемые решения. Любой уязвимый плагин — угроза всем.

  2. Отдельные БД на критически важных клиентов. Технически сложно, но можно настроить wp-config.php на переключение между разными БД в зависимости от BLOG_ID. Или использовать плагины типа HyperDB.

  3. Регулярные аудиты безопасности и обновления.

  4. Сильная изоляция файлов uploads (правильные права CHMOD).

  5. WAF (Web Application Firewall) на уровне сервера или облака (Cloudflare).

Часть 7: Домены и брендинг: как дать клиенту свой домен?

По умолчанию — поддомены или подпапки. Клиент хочет svoi-sait.ru.

  1. Плагин «WordPress MU Domain Mapping» — классическое решение.

    • Суперадмин в настройках сети назначает, что сайт с ID=7 должен отображаться по домену svoi-sait.ru.

    • В DNS клиента настраивается A-запись или CNAME на IP-адрес вашего сервера.

    • Важно: Нужно настроить веб-сервер (Nginx/Apache), чтобы он принимал трафик на этот домен и направлял его в корень WordPress.

  2. Nginx конфиг для domain mapping (пример):

    nginx
    server { listen 80; server_name svoi-sait.ru www.svoi-sait.ru; root /var/www/main.com; # Общий корень для всей сети index index.php; # Стандартные правила обработки WordPress Multisite location / { try_files $uri $uri/ /index.php?$args; } location ~ \.php$ { include fastcgi_params; fastcgi_pass unix:/var/run/php/php8.1-fpm.sock; fastcgi_param SCRIPT_FILENAME $document_root$fastcgi_script_name; } }

Заключение

WordPress Multisite — это мощный инструмент для построения платформ, а не просто «нескольких сайтов». Он требует операторского, а не пользовательского, уровня знаний.

Стоит ли за это браться?

  • ДА, если у вас однородные сайты с одинаковыми требованиями, и вы готовы к роли суперадмина-оператора.

  • НЕТ, если каждый клиент — «особенный» и хочет полный контроль, или если вы не готовы к глубокому погружению в инфраструктуру.

Если решились: Начните с пилотного проекта на 5-10 не самых критичных сайтов. Настройте Redis-кэш, протестируйте процедуру обновлений, отработайте backup/restore отдельного сайта. И только потом масштабируйтесь.