Мультисайтинг в Drupal


Мне показалось странным, что на хабре эта тема практически не освещена и я постараюсь немного исправить эту ситуацию.

Я не сторонник англицизма, но в нашем языке нет даже похожего термина. Вкратце мультисайтинг можно определить как возможность использовать файлы движка для разных сайтов. Не стану разбираться в этимологии этого слова, но осмелюсь предположить, что его появление было связано с Drupal. Одним из наиболее распространённых примеров мультисайтинга может быть использование общей базы данных пользователей на нескольких сайтах. В друпале мультисайтинг реализован привлекательно, с точки зрения простоты и удобства, о чём я и решил написать.

Вместо вступления


На мой взгляд, Drupal – это пластилин, из которого при желании можно слепить очень симпатичные вещицы. Хоть мой опыт общения с друпалом не так уж и велик, но мне пока не случалось встретить задачу, которую не удалось бы решить с его помощью. Должен признать, что если уровень знаний/мотивации/опыта разработчика малы, то из этого пластилина скорее всего получится кучка известной нетонущей массы, но речь совсем не об этом.

Как это делается?


Нужно отметить логическую грамотность построения структуры папок Drupal. Ядро отделено от собственного кода, весь код отделён от разметки. Мультисайтинг предусмотрен друпалом «из коробки», для чего существует папка sites в корневой директории. В этой папке должны располагаться файлы настроек сайтов, находящихся в связке с основным сайтом. Люди, хоть раз устанавливавшие Drupal, знают, что друпал требует создания файла settings.php в папке

sites/default

В данном случае название папки 'default' определяет его принадлежность к «основному» сайту.
В случае, когда нужно организовать мультисайтинг создаются папки с именами доменов рядом с 'default’ и туда копируется файлы settings.php из sites/all/default/default.settings.php

sites/first.example.ru/settings.php
sites/second.example.ru/settings.php
.
.
.
sites/n.example.ru/settings.php


в которых указываются специфичные настройки для данного сайта. Темы и модули, которые необходимо сделать доступными только для указанного сайта помещаются в соответствующие папки

sites/first.example.ru/themes/
sites/first.example.ru/modules/


Темы и модули, размещённые в папке

sites/all

будут доступны всем сайтам в мультисайтинговой связке. Таким образом можно существенно сократить время на их обновление.

Важно! Document root у всех сайтов в связке должен быть один – корневая директория с установленным друпалом (там, где лежит index.php). Так же возможен вариант симлинка на эту папку.

Как назвать папки?


В процессе поиска файлов settings.php друпал «обрезает» имена поддоменов слева направо, а имена подпапок справа налево. Из примера должно стать понятно, что под этим имеется ввиду.

Допустим, сайт у нас должен быть установлен в

www.example.ru/mysite/test

Друпал будет искать файл settings.php в следующих папках в указанной последовательности:

1. sites/www.example.ru.mysite.test
2. sites/example.ru.mysite.test
3. sites/ru.mysite.test

4. sites/www.example.ru.mysite
5. sites/example.ru.mysite
6. sites/ru.mysite

7. sites/www.example.ru
8. sites/example.ru
9. sites/ru

10. sites/default


Первый найденный файл будет использован, остальные проигнорированы. Из примера видно, что для работы сайта example.ru достаточно разместить settings.php в

sites/example.ru/settings.php

и не нужно дублировать его в

sites/www.example.ru/settings.php

т.к. и по обращению через example.ru, и по обращению www.example.ru друпал найдёт один и тот же файл.

В случае, если необходимо привязать сайт, установленный на нестандартный порт, порт указывается как дополнительный поддомен. Так, для сайта

www.example.ru:8080/mysite/test/

папка с файлом settings.php должна быть

sites/8080.www.example.ru.mysite.test

От себя добавлю, что я бы не советовал связывать сайты, установленные в подпапку, т.к. их корректное функционирование не гарантируется (о чём сказано в документации). Есть, конечно, рекомендации по исправлению возможных ошибок, такие как создать симлинк document root для www.example.ru.mysite на document root для www.example.ru:

(из document root для www.example.ru)
ln -s . mysite

но это не панацея и выбирать нужно этот метод только при крайней необходимости.

Что менять в settings.php?


1. Если мы хотим использовать абсолютно независимые сайты

то в settings.php в $db_url указываем отдельную БД. Пользователь так же может быть другим. Наличие или отсутствие префикса здесь не имеет никакого значения, но, опять же добавлю от себя, присваивать префиксы к БД сайта — это, хоть и не большая, но дань безопасности и не стоит этим пренебрегать.

2. Если мы хотим использовать сайты с общей БД или с общими таблицами

a. если сайты будут использовать одну и ту же БД

то нужно использовать разные префиксы для уникальных таблиц и одинаковые для общих. Например, common_ у нас задуман как префикс для общих таблиц пользователей и профилей, default_ для собственных таблиц БД основного сайта, а first_ для собственных таблиц БД сайта first.example.ru.

В sites/first.ru/settings.php пишем:

// $db_prefix = '';

$db_prefix = array(
"default" => "first_",
"users" => "common_",
"sessions" => "common_",
"authmap" => "common_",
"profile_fields" => "common_",
"profile_values" => "common_",
);


В sites/default/settings.php

// $db_prefix = '';

$db_prefix = array(
"default" => "default_",
"users" => "common_",
"sessions" => "common_",
"authmap" => "common_",
"profile_fields" => "common_",
"profile_values" => "common_",
);

Таким образом, сайт first.example.ru будет использовать общую c сайтом example.ru базу пользователей и их профилей. Но не стоит увлекаться этим способом, т.к. в среднем с каждым новым сайтом в связке число таблиц будет увеличиваться на 60-70. Нетрудно посчитать что будет с БД уже при десяти сайтах. Прибавьте к этому ещё и зависимость всех сайтов от корректной работы одной БД.

b. если сайты будут использовать разные БД и некоторые общие таблицы.

Допустим, нам необходимо использовать:
  • общие представления (созданные модулем views)
  • общую базу пользователей и их профилей для сайтов example.ru и fisrt.example.ru

и допустим, что:
  • наименование БД для example.ru – example
  • префикс таблиц для example.ru – example_,
  • наименование БД для first_example.ru – first
  • префикс таблиц таблиц для fisrt.example.ru – first_.

В sites/first.ru/settings.php пишем:

// $db_prefix = '';

$db_prefix = array(
"default" => "first_",
"users" => "example.example_",
"sessions" => "example.example_",
"authmap" => "example.example_",
"profile_fields" => "example.example_",
"profile_values" => "example.example_",
"views_display" => "example.example_",
"views_view" => "example.example_",

);


В sites/default/settings.php

$db_prefix = 'example_';

Таким обазом, для first.example.ru данные о представлениях и пользователях будут браться из БД example, а все остальные – из БД example.ru

Важно! Точка здесь интерепретируется друпалом как конец названия БД, поэтому не стоит создавать префикс с точкой.

Заключение


Мультисайтинг друпала довольно просто настраивается и стабильно работает. Мне не приходилось встречаться с проблемами, несмотря на то, что для реализации поставленной задачи мне потребовалось объединить таблицы views_display, views_view, blocks и blocks_roles, в то время как Влад Савицкий классифицировал blocks* как таблицы, объединять которые нельзя, а views_* как таблицы, объединять которые нужно с большой осторожностью.
Макс Кириленко же считает, что «Мультисайтниг на общих таблицах недокументированная возможность Друпала, в ней больше проблем чем достоинств». Но его статья относится к Drupal 5 и, возможно, причина именно в этом.
Жду комментариев по этому поводу.

Два пригодившихся мне модуля по теме:

Multisite search — позволяет индексировать содержимое сайтов в связке и произвоить поиск по ним
Multisite login — позволяет сохранять авторизацию для всех сайтов в связке даже на разных доменах

UPD: pvasili советует быть внимательным при обновлении модулей в папке /sites/all (обязательно запускать update.php на всех доменах, использующих эту папку).
UPD: Cначала друпал будет искать модуль в sites/example.ru/modules, а уже после в /sites/all/modules
UPD: Для обновления через drush andyceo написал скрипт
UPD: shuba описал полезное нововведение для Drupal 7
Поделиться публикацией

Похожие публикации

Комментарии 26

    +1
    Прямо «с языка» тему сняли. Но у Вас тема более полная чем мой черновик.
    Спасибо!
        0
        В избранное! Как раз сейчас делает подобное. Есть Главный сайт и есть сателлиты по направлениям. Спасибо!
          0
          Подобное может быть реализовано простым образом не только на друпале.
            +1
            И добро пожаловать на Хабр! :)
              0
              Возможно вы и правы, но в исвестных мне CMS/CMF подобное не может быть реализовано простым образом :)
              +2
              бравться — поправьте

              Забыли добавить:
              — про обновления модулей и тем. Нужно быть внимательным при обновлении модулей в папке /sites/all (обязательно запускать update.php на всех доменах, использующих эту папку).
              — что будет вначале браться из /sites/all/modules или /sites/site.ru/modules
              — обновления через drush
                +1
                А для этого я написал скриптик и теперь проблемы в прошлом.

                github.com/andyceo/bash_scripts/blob/master/drushupdb.sh
                  0
                  Спасибо, исправился :)
                    0
                    Предыдущий комментарий, конечно, относился к pvasili.
                    andyceo, вам за скрипт отдельное спасибо!
                  0
                  Кстати, если сайтов довольно много, можно ли настроить 1 общий крон?
                  Или на каждый прописывать отдельно?
                    0
                    Cron лучше настраивать для каждого сайта отдельно.
                    +3
                    В версии 7 директории уже не нужно называть по именам доменов.
                    Если в 6 версии нужно было создавать:
                    sites/example1.com
                    sites/example2.com
                    То в семерке:
                    sites/example1
                    sites/example2
                    и в файле sites.php прописать:
                    <?php
                    $sites = array(
                    'example1.com' => 'example1',
                    'example2.com' => 'example2',
                    );
                    ?>

                    Стало гораздо удобнее при переносе с локальной машины на хостинг или при изменении адреса, т.к. не меняются урлы файлов.

                    А для 6 есть патч.
                      0
                      У меня вполне отлично 20 сайтов в одной БД (около 250 таблиц) — суммарный трафик не большой, но проблем вообще никаких пока. Когда вырастет нагрузка — всегда можно перенести в отдельную базу.
                      Опытным путем определил для себя таблицы, которые можно делать общими (Drupal 6):

                      default, access, actions, actions_aid, authmap, imagecache_action, imagecache_preset, filter_formats, languages, locales_source, locales_target, l10n_update_file, l10n_update_project, permission, role, sessions, term_data, term_hierarchy, term_relation, term_synonym, users, users_roles, vocabulary, watchdog, wysiwyg, wysiwyg_user.

                      Скорее всего какие-то из них не стоило делать общими (например, модуль Database logging, включенный по-умолчанию, ругается на watchdog — но я его выключаю — чтобы не плодить лишних таблиц). Особенно удобны переводы, настройки wysiwyg и профили imagecache. Но на практике проблем не возникает пока.

                      Для того, чтобы не было проблем при установке — можно устанавливать с настройками для одного префикса на все таблицы (создаст все таблицы с новым префиксом). Потом добавлять префиксы общих таблиц и удалять только что созданные, т.к. они уже заменены старыми.
                        0
                        Добавлю.
                        Для управления контентом на мулитисайте удобно пользоваться модулем Domain Access.
                          0
                          Да, модуль интересный. Я правильно понял, что он может использоваться только на одной общей базе с разделением «собственных» таблиц сайтов с помощью префиксов?
                          0
                          давно искал внятную статью о мультисайтинге в друпал +1
                            0
                            Если вы используете различные темы для сайтов, то не мешало бы определить их напрямую в settings.php и настроить выполнение регулярных процедур cron.php минимум на раз в сутки.
                              0
                              Вам приходилось сталкиваться с проблемами с этим связанными? Чем обусловлена необходимость выполнения крона раз в сутки?
                                0
                                Именно из-за проблем, связанных с «отваливанием» тем, пришлось искать выход в «кроне».
                                В деталях не разбирался, ибо другие задачи подгоняют.
                                  0
                                  одно «но». это в случае, когда для всех сайтов таблицы общие. у меня была задача один и тот же контент представить на разных доменах с отличающимся дизайном.
                                0
                                В мультисайтинге Друпала есть одно неприятное свойство — трудно переименовать «не главные» сайты. Допустим, был сайт на поддомене, надо перенсти на домен 2го уровня (example.com.ru —> example.ru) или из папки на домен (exammple.ru.subsite —>example2.ru). Эти строчки в пути (sites/example.com.ru/...) хранятся в контенте (картинки) в файлах (таблица files) и нет легкого способа их изменить. Это если mysqldump не относить к легким, но и тогда будут проблемы (google/yandex image search, например, потеряют ваши картинки). Основной сайт (default) — никаких проблем, ему вообще все равно какой у него адрес.

                                На этот случай хотелось бы видеть какой-то способ назначить любому сайту определенную папку, но я такого навскидку не нашел.
                                  0
                                  а если определить хранилище файлов в корне сайта /files?
                                    0
                                    можно, наверно, но это надо делать заранее, по факту уже поздно метаться.
                                    ну и это нарушает концепцию «весь сайт в одной папке»
                                      0
                                      Естественно заранее думать нужно :)
                                      Если вы меняете поддомены то: в любом случае, контент у вас будет для поисковиков на другом сайте([суб]домене). Пока оно там ещё будет отзеркалено, да ещё и правильно, да ещё и будет определено главное зеркало правильно…
                                      При создании нового сайта, лучше менять сразу папку статики и temp на что-нибудь не привязанное к имени или организовывать CDN.

                                      Сейчас можете в папке /sites/example.com.ru убрать settings.php, а всю статику оставить. Ваша старая статика будет видна по своим старым путям. Для нового — сделайте новую и пропишите к ней путь в /admin/settings/file-system.
                                      Можно попробовать оставить 2 домена в мультисайтинге(если нужно старое сохранить) с общими таблицами, только нужно настроить запрет создания материалов из старого поддомена (поиграть с ролями в разных доменах). Тут уж на что фантазии хватит :).
                                  +1
                                  Есть проблема с безопасностью: если взломан один сайт (или там завёлся недобросовестный админ), через него взламываются все остальные.

                                  Только полноправные пользователи могут оставлять комментарии. Войдите, пожалуйста.

                                  Самое читаемое