Mutualisation : un SPIP pour plusieurs sites

Procédure pour partager le noyau de SPIP entre plusieurs sites.

Partager les fichiers de SPIP entre plusieurs sites, ce que l’on appelle une mutualisation, permet un gain d’espace disque important, ainsi qu’une possibilité de mise à jour de SPIP simple de l’ensemble des sites en ne mettant à jour que le noyau.

SPIP permet de mutualiser ses fichiers.
(les restaurations peuvent se réaliser d’un SPIP à l’autre comme s’il n’était pas mutualisé).

Le concept...

Les dossiers nécessaires au fonctionnement du noyau SPIP (ecrire, prive, squelettes-dist), et ceux marquant l’activité d’un site (config, IMG, tmp, local) sont clairement identifiables et séparés.
C’est cette séparation qui permet d’avoir plusieurs sites SPIP autonomes pour un même noyau de SPIP.

Cette autonomie repose sur quatre répertoires par site dans lesquels SPIP va écrire les données résultant de l’activité du site. On distingue les données temporaires et permanentes d’une part, et les données accessibles par HTTP et celles qui ne le sont pas d’autre part. Les deux répertoires inaccessibles par HTTP seront protégés par un .htaccess installé automatiquement par SPIP (les administrateurs du serveur peuvent mettre ces répertoires en dehors de l’arborescence servie par HTTP).

Ces quatre répertoires sont distincts et nommés par les constantes PHP suivantes :

define('_NOM_TEMPORAIRES_INACCESSIBLES', "tmp/");
define('_NOM_TEMPORAIRES_ACCESSIBLES', "local/");
define('_NOM_PERMANENTS_INACCESSIBLES', "config/");
define('_NOM_PERMANENTS_ACCESSIBLES', "IMG/");

Dans une installation simple de SPIP, ces répertoires sont créés à la racine du site avec les valeurs par défaut ci-dessus.
La mutualisation des sources de SPIP repose sur l’association de quatre répertoires spécifiques à chaque site, déduits de leurs URL.

Initialisation de la mutualisation

Cette association est effectuée par une fonction,
spip_initialisation. Elle admet quatre arguments indiquant la localisation des quatre répertoires fondamentaux, et construit à partir de ceux-ci les constantes servant au fonctionnement de SPIP.
Dans une installation simple, ces quatre arguments sont les quatre constantes ci-dessus. La fonction spip_initialisation est appelée juste après le chargement de mes_options.php,
et refuse silencieusement de s’exécuter si elle a déjà été appelée.
En conséquence, si dans ce fichier cette
fonction est appliquée sur des arguments différents déduits de l’URL du site, on aura autant d’utilisation des sources de SPIP que d’URL de site.
On peut aussi définir dans ce fichier les constantes servant au fonctionnement de SPIP, ces définitions ayant priorité sur celles qu’essaiera de définir spip_initialisation.

Le code ci-dessous, placé dans le fichier config/mes_options.php prend le nom de domaine et exécute une mutualisation sur les quatre répertoires tmp, local, config et IMG placés dans le dossier sites/nom_du_domaine/.
Auparavant, la définition de quelques constantes permet de centraliser les fichiers de journalisation de tous les sites dans un unique répertoire, log, et non dans sites/nom_du_domaine/tmp/ pour chacun. Cette centralisation n’a rien d’obligatoire mais se révèle utile ; elle peut s’appliquer aussi aux répertoires d’aide et de sauvegarde.

<?php
$rep = 'sites/';
$site = $_SERVER['HTTP_HOST'];
$path = _DIR_RACINE . $rep . $site . '/';

// ordre de recherche des chemins
define('_SPIP_PATH',
	$path . ':' .
	_DIR_RACINE .':' . 
	_DIR_RACINE .'squelettes-dist/:' .
	_DIR_RACINE .'prive/:' .
	_DIR_RESTREINT);

// ajout du dossier squelette
if (is_dir($path . 'squelettes'))
	$GLOBALS['dossier_squelettes'] = $rep . $site . '/squelettes';

// exemple de logs a la racine pour tous les sites
define('_FILE_LOG_SUFFIX', '_' . $site . '.log');
define('_DIR_LOG',  _DIR_RACINE . 'log/');

// prefixes des cookie et des tables :
$cookie_prefix = str_replace('.', '_', $site); 
$table_prefix = 'spip';

// exectution du fichier config/mes_option.php du site mutualise
if (is_readable($f = $path . _NOM_PERMANENTS_INACCESSIBLES . _NOM_CONFIG . '.php')) 
	include($f); 

// demarrage du site
spip_initialisation(
	($path . _NOM_PERMANENTS_INACCESSIBLES),
	($path . _NOM_PERMANENTS_ACCESSIBLES),
	($path . _NOM_TEMPORAIRES_INACCESSIBLES),
	($path . _NOM_TEMPORAIRES_ACCESSIBLES)
);
?>

Mutualiser des domaines ou des sous-domaines

Pour mutualiser plusieurs domaines ou sous-domaines, vous devez tous les diriger vers le répertoire physique contenant SPIP. Par exemple, http://example.org/, http://example.net/ et http://sous_domaine.example.net/, pour les mutualiser, doivent tous pointer sur le même répertoire, comme /var/www/spip/.

Ce dossier contient donc SPIP ainsi qu’un fichier config/mes_options.php pour activer la mutualisation. En reprenant l’exemple de code donné au dessus, il faudra alors créer les dossiers sites et log ainsi que sites/example.org, sites/example.net et sites/sous_domaine.example.net avec dans chacun d’eux les répertoires config, local, IMG et tmp accessibles en écriture. Il n’y a rien d’autre à réaliser. En allant sur l’un des sites, SPIP devrait vous proposer son installation.

Si vous souhaitez pouvoir activer des types d’url différents, comme les « url arborescentes » ou les « url propres », il sera nécessaire de créer un fichier d’accès Http, qui est fourni dans la distribution sous le nom de htaccess.txt : il suffit de le renommer en .htaccess pour le mettre en œuvre. Il s’appliquera à tous les sites mutualisés, mais il est possible d’avoir des accès différenciés en configurant astucieusement le serveur (voir plus bas). Dans les deux cas,
tout cela ne fonctionnera que si votre serveur accepte d’exécuter toutes les directives présentes dans ce fichier, notamment celles concernant
la réécriture d’url (« url rewriting »).

Mutualiser les répertoires d’un domaine

Chaque dossier (virtuel) d’un domaine, en analysant correctement l’URL, peut aussi devenir un site SPIP mutualisé. Il faut pour cela que l’URL du dossier soit redirigée de façon transparente vers la racine du SPIP. C’est le rôle du fichier .htaccess modifié. Ainsi http://example.com/premier_site/ et http://example.com/second_site/ peuvent être chacun des sites SPIP mutualisés (et http://example.com/ aussi).

Dans un premier temps, il faut renommer le fichier htaccess.txt en .htaccess et le modifier pour indiquer que les répertoires qui sont virtuels doivent pointer à la racine de SPIP. Pour cela, ajouter dans la partie « Réglages personnalisés » soit le code générique qui traite tous les répertoires virtuels (mais http://example.com/premier_site sans / final renverra une erreur), soit un code indiquant les noms des dossiers (pas d’erreur si aucun / final) :

// code générique
RewriteCond %{REQUEST_URI} !^/(config|ecrire|IMG|prive|plugins|plugins-dist|sites|squelettes-dist|squelettes|tmp|lib|local|mutualisation)/(.*)
RewriteRule ^[^/]+/(.*) /$1 [QSA,L]

// OU code spécifique
RewriteRule ^(premier_site|second_site)$ /$1/ [R,L]
RewriteRule ^(premier_site|second_site)/(.*) /$2 [QSA,L]

Dans un second temps, il faut créer une mutualisation en analysant dans le fichier config/mes_options.php l’url transmise. Voici un exemple pour avoir les sites mutualisés dans sites/exemple.com, sites/premier_site et sites/second_site :

<?php
if ( 
	(
		preg_match(',^/([\.a-zA-Z0-9_-]+)/,', $_SERVER['REQUEST_URI'], $r)
		AND !is_dir(_DIR_RACINE . $r[1])
	)
) {
	$site = $r[1];
} else {
	$site = $_SERVER['HTTP_HOST'];
}

$rep = 'sites/';
$path = _DIR_RACINE . $rep . $site . '/';

// ordre de recherche des chemins
define('_SPIP_PATH',
	$path . ':' .
	_DIR_RACINE .':' . 
	_DIR_RACINE .'squelettes-dist/:' .


	_DIR_RACINE .'prive/:' .
	_DIR_RESTREINT);

// ajout du dossier squelette
if (is_dir($path . 'squelettes'))
	$GLOBALS['dossier_squelettes'] = $rep . $site . '/squelettes';

// prefixes des cookie et des tables :
$cookie_prefix = str_replace('.', '_', $site); 
$table_prefix = 'spip';

// exectution du fichier config/mes_option.php du site mutualise
if (is_readable($f = $path . _NOM_PERMANENTS_INACCESSIBLES . _NOM_CONFIG . '.php')) 
	include($f); 

// demarrage du site
spip_initialisation(
	($path . _NOM_PERMANENTS_INACCESSIBLES),
	($path . _NOM_PERMANENTS_ACCESSIBLES),
	($path . _NOM_TEMPORAIRES_INACCESSIBLES),
	($path . _NOM_TEMPORAIRES_ACCESSIBLES)
);
?>

Préfixe des tables

Les exemples présentés nécessitent autant de bases de données que de sites mutualisés. Cependant, il est possible d’installer tous les sites dans une même base de données, en préfixant les noms de leurs tables d’un préfixe unique.

L’exemple ci-dessous crée un préfixe de 8 caractères : un préfixe avec les 4 premières lettres du site, suivi de 4 autres caractères.

$table_prefix = substr(str_replace('.', '_', $site),0,4) . substr(md5($site),0,4);

Fichier config/mes_options.php

Toute modification du fichier config/mes_options.php du noyau SPIP affectera les options de tous les sites hébergés.

Par exemple, mettre dans ce fichier :
$type_urls = ’propres’ ;

donnera par défaut à tous les sites ce type d’URL... Mais chaque site peut le changer dans son propre /sites/repertoire_du_site/config/mes_options.php.

Configurer Apache pour les domaines et sous-domaines

La mutualisation côté serveur, pour ce qui concerne la gestion des sous-domaines ou des domaines reste simple. Il suffit de créer une redirection entre le nom de domaine et le répertoire physique où est stocké SPIP.

Voici un exemple de configuration (minimale) pour un serveur nommé ’exemple.tld’ utilisant des sous-domaines. Le fichier de configuration est à créer dans /etc/apache2/sites_availables/exemple.tld, qu’il faut ensuite activer

sudo a2ensite exemple.tld
sudo /etc/init.d/apache2 reload

SPIP est installé dans cet exemple dans ’/var/www/spip/’.

<VirtualHost *>
	ServerName exemple.tld
	ServerAdmin webmaster@localhost
	ServerAlias *.exemple.tld
	
	DocumentRoot /var/www/spip/
	<Directory /var/www/spip/>
		Options Indexes FollowSymLinks MultiViews
		AllowOverride All
		Order allow,deny
		allow from all
	</Directory>

</VirtualHost>

Si vous voulez en plus avoir des fichiers d’accès différenciés, il suffit d’utiliser la directive AccessFileName à l’intérieur de la directive
VirtualHost, de sorte que le fichier d’accès du site S se nomme par exemple .htaccess-S.

Note sur les sauvegardes et les restaurations

Chaque site copie par défaut ses fichiers de sauvegardes dans le répertoire
/sites/premier_site/tmp/dump (ou /sites/premier_site/tmp/upload/login pour les sauvegardes d’un administrateur restreint).

Les restaurations se font par le même dossier. Le chemin des images est aussi correctement pris en compte .

Auteur Committo, Ergo Sum., Matthieu Marcillaud Publié le : Mis à jour : 20/04/23

Traductions : català, English, français, Nederlands