Как запустить несколько сайтов на одном сервере с той же базой кода в PHP?

Я создал специальную специализированную CMS с несколькими клиентами на ней, каждый со своим собственным доменным именем, веб-сайтом, областью администрирования и базой данных, но все из которых находятся на одном сервере.

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

Звучит здорово до сих пор?

Хорошо, когда я недавно решил обновить все сайты клиентов, это стало серьезной болью. Очевидно, я должен был изменить код для каждой установки. Для крупного обновления это нормально, но для частых настроек и т.д. Дублирование усилий загрузки становится очень раздражающим.... Я надеюсь, что когда-нибудь у вас будет десятки или сотни клиентов, поэтому код в конечном итоге должен быть централизован, чтобы меняя его в одном месте, он обновляет его везде... как это сделать?

Ответ 1

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

Затем вы можете разместить этот каталог исходного кода и просто создать для него символические ссылки.

Например, ваша структура каталогов может выглядеть так:

/var/www/src/index.php
/var/www/src/more_source.php
/var/www/clients/client_a/settings.php
/var/www/clients/client_a/src -> ../../src/
/var/www/clients/client_b/settings.php
/var/www/clients/client_b/src -> ../../src/

Если вы выберете эту структуру, единственное, что вам нужно будет изменить, - это включить для settings.php(например, от require "settings.php" до require "../settings.php").

Ответ 2

Лично у меня есть клиентская таблица в базе данных, которая содержит текущий номер версии кода, который они запускают. Когда пользователь входит в систему, он устанавливает cookie под названием CodeVersion, указывающий версию кода для этого клиента (например, "v5-09-00" ). В Apache.htaccess у меня есть:

RewriteEngine on

RewriteCond %{HTTP_COOKIE} CodeVersion=([^;]+) [NC]
RewriteRule ^(.*)$ http://v%1.%{HTTP_HOST}/${escape:$1} [R=302,P,L]

и в файле локальных хостов я:

127.0.0.1    myservername       myservername.myserverdomain.com

127.0.0.1    v5-08-00.myservername  v5-08-00.myservername.myserverdomain.com
127.0.0.1    v5-09-00.myservername  v5-09-00.myservername.myserverdomain.com
127.0.0.1    v5-10-00.myservername  v5-10-00.myservername.myserverdomain.com

который обрабатывает локальное перенаправление внутри Apache на запись в vhosts

Файл vhosts устанавливает среду для каждой версии кода:

<VirtualHost *:80>
    ServerAdmin [email protected]
    DocumentRoot /usr/local/apache/htdocs_5-09-00
    ServerName v5-09-00.myservername.myserverdomain.com
    ServerAlias v5-09-00.myservername
    ErrorLog logs/myservername-error_log_5-09-00
    CustomLog logs/myservername-access_log_5-09-00 common
    php_value include_path ".:/php/includes:/usr/local/include/5-09-00/API:/usr/local/include/5-09-00/library:/usr/local/include/5-09-00/businesslogic:/usr/local/include/5-09-00/configuration:/usr/local/include/5-09-00/library/PHPExcel/Classes"
</VirtualHost>

<Directory "/usr/local/apache/htdocs_5-09-00">
    Options Indexes FollowSymLinks ExecCGI
    AllowOverride All
    Order allow,deny
    Allow from all
</Directory>

В каждом наборе каталогов я могу иметь символические ссылки, указывающие на общий код, и фактические файлы php/ini для конкретного кода или конфигурации клиента.

Ответ 3

Просто чтобы вы знали, что у меня была эта проблема раньше. Легко заразиться некоторыми ошибками phantom.htaccess или открытыми эксплойтами до других клиентов, если вы решите настроить через это.

Я рекомендую хранить все отдельно между клиентами.

Поэтому дайте им свой FTP, базу данных и кодовую базу. Не складывайте все в одну папку и думайте, что конфигурация поможет. Кажется, это так сексуально, но когда у вас есть одна небольшая проблема, у вас такая же проблема на всех клиентских сайтах, но если у вас есть одна проблема у клиента, и все остается раздельным, то другие клиенты не чувствуют это обязательно.

Вы можете запустить основную базу кода на отдельном тестовом сервере для выполнения обновлений, а затем просто исправить файлы FTP клиента и базу данных SQL.

Но держите это просто и отдельно!

Ответ 4

Я бы разделился на library (ваш рабочий код) и config (три строки для каждого пользователя, возможно, соединения с базой данных и т.п.).

Разделите library на универсальное местоположение, например /home/library (в * nix), и разрешите атрибут чтения другим учетным записям пользователей.

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

например config: (по одному на сайт)

<?php
require_once('/home/library/include.php');
//Line 1 config
//Line 2 config
//Line 3 config
?>

Если ваша библиотека кода также используется для рендеринга содержимого (index.php и т.д.), у вас есть два варианта: (1) создать symlinks между веб-папками каждого сайта и источником library или (2) отделите свой код на основные функциональные возможности и код рендеринга.

Симлинковая связь создает системную связь между двумя точками на диске (она похожа на указатель). Правильно созданная ссылка позволяет вам получить доступ к папке под другим именем, чтобы вы могли создать /home/user1/library, /home/user2/library /home/user3/library, и все они указывают и содержат содержимое /home/library (они не являются копиями данных).

Я был бы включен, чтобы пойти с № 2, хотя это займет больше работы. Ваш library выполняет эту работу, но рендеринг сайта выполняется вторым фрагментом кода, который предоставляется на основе каждого сайта (вероятно, включая вышеупомянутый config), что обеспечивает большую гибкость на сайте по сайту (даже если вы еще не предвидели, что это нужно). В качестве побочного эффекта вы находитесь на пути к многоуровневому приложению.

Ответ 5

Альтернативный подход - использование заглушек. Просто переместите общий код, например, библиотеку в общий каталог. Затем для каждого отдельного сайта создайте полые скрипты .php, которые включают только общий код:

  // file: index.php
  include(".../shared/index.php");

Вам нужно будет повторить это для каждой точки входа приложения. Таким образом, у вас почти пустые скрипты на каждом сайте, и все изменения в общей кодовой базе автоматически применяются ко всем настройкам. Просто пусть config.php отличается между установками.

Для статических файлов (изображений, css и т.д.) я бы также использовал симлинковый подход или RewriteRule.

Ответ 6

Когда я делаю что-то подобное, у меня есть каждая клиентская папка на веб-сервере как рабочая копия SVN (я использую SVN как свою систему управления версиями, очевидно). Затем, когда я сделал некоторые обновления, протестировал и пометил выпуск, я просто переключу клиентскую папку на новую версию. SVN автоматически отменяет все изменения для меня. Существует одно предостережение: убедитесь, что вы настроили свой веб-сервер, чтобы не разрешать показ содержимого папок .svn в каждом каталоге (или эквивалент для вашего VCS по выбору, если таковой имеется). Я считаю, что сначала прочитал эту технику в официальных документах SVN, поэтому я считаю, что это санкционировано их разработчиками, но я не могу найти ссылку на нее в документах прямо сейчас.

Ответ 7

Если вы поместите свой код в систему контроля версий, то каждый клиентский сайт может быть отдельной проверкой. Вы можете проверить свои изменения и направить их на каждый клиент (или тестовый сайт), выполнив обновление корня версии (или используя экспорт) в корне. Затем вы можете обновлять и тестировать каждый клиент по одному, чтобы убедиться, что исправление исправлено.

Ответ 8

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

Решение по управлению развертыванием может быть лучше, чем прямое совместное использование кода. (если вы используете Drupal, например, вы можете использовать Aegir для управления всеми развертываниями и обновлениями вашего сайта)

Тем не менее, в некоторых случаях полезно использовать код. Я сделал что-то подобное на предыдущей задаче, где они хотели, чтобы несколько сайтов использовали одну общую базу кода. Мы сделали это, чтобы поместить разделяемые библиотеки в папку на сервере, и каждому сайту была предоставлена ​​символическая ссылка на эту папку, поэтому он рассматривал ее как локальную папку. Довольно легко сделать, и довольно легко управлять.

Ответ 9

Как насчет того, что использует тот же код, но у каждого есть свой mysql.
Например, http://mycms.com/myuser/ приносит префикс myuser_ в таблицы, таким образом, позволяет 1 структуру src и несколько сайтов. Вам понадобится .htaccess, хотя