Carnet Wiki

La mutualisation facile ...

Version 31 — Octobre 2007 — olivier

A savoir

- Il existe plusieurs moyens pour mutualiser un site Spip.
-  Cette page décrit une méthode s’appuyant sur un plugin, et donne un lein vers une autre méthode, mais vous n’avez pas besoin de changer de page pour réussir votre mutualisation.
-  En cas de difficultés, consultez les archives sur la liste Spip user, et, sinon, posez des questions claires, avec un sujet explicite.

Résumé

- Installez les fichiers de SPIP dans un répertoire ; appelons-le spip/, c’est la racine de votre système :
svn co svn://trac.rezo.net/spip/spip/ spip/ ;

Typiquement, ce dossier contient votre site, chez moi c’est /var/www/monsite et mon virualhost pointe dessus, donc on ne peut pas remonter plus haut avec un navigateur.

- Installez les fichiers de SPIP dans un répertoire ; appelons-le spip/, c’est la racine de votre système :

svn co svn://trac.rezo.net/spip/spip /  spip/</code >  ;
 - Installez les fichiers de mutualisation facile en les chargeant depuis la zone, vers un répertoire quelconque  :
_ <code>svn co svn://zone.spip.org/spip-zone/_plugins_/_test_/mutualisation/ spip/mutualisation/

 ;

-  Je ne suis qu’un piètre utilisateur Windows, en conséquence je fais appel à la légendaire solidarité windaubienne pour voler à votre secours.
J’ai installé un client graphique style tortoisesvn (qui est super d’ailleurs et qui n’a pas d’équivalent linux, arghh ;) )
Donc pour installer les fichiers de mutualisation il vous faudra Récupérer une copie de travail en les chargeant depuis la zone, vers un répertoire quelconque (que vous avez créé) via la commande svn checkout
Puis copier / coller le code suivant svn://zone.spip.org/spip-zone/_plugins_/_test_/mutualisation

-* Faites pointer les URLs à mutualiser vers le répertoire racine spip/ (VirtualHost) ;

  • Créez un répertoire sites/ à l’intérieur du répertoire racine, dans lequel le serveur peut écrire.
  • Assurez-vous d’avoir un utilisateur MySQL autorisé à créer des bases de données (optionnel) ;

-* Créez le fichier spip/config/mes_options.php en vous inspirant du contenu présent dans le fichier mutualisation//mes_options.php.txt

    • Vous n’aurez que les variables à modifier, c’est à dire les login/pass pour MySQL..., et les drapeaux true/false.
    • Avec l’utilisation de ce plugin, la notion de Site Maitre/Site principale n’existe pas. Il y a seulement un site Spip à la racine (non accessible) et des sites mutualisés dans /sites/%{SERVER_NAME}/ (accessibles avec http://%{SERVER_NAME} )

- Faites pointer les URLs à mutualiser vers le répertoire racine spip/ (VirtualHost) ;
-  Créez un répertoire sites/ à l’intérieur du répertoire racine, dans lequel le serveur peut écrire.
- Assurez-vous d’avoir un utilisateur MySQL autorisé à créer des bases de données (optionnel) ;
-  Créez le fichier spip/config/mes_options.
php en vous inspirant du contenu présent dans le fichier mutualisation//mes_options.php.-* txt
-  
Dupliquez le fichier htaccess.txt en .htaccess (sous peine d’obtenir une erreur lors de l’appel à l’url /oui durant l’installation d’un spip mutualisé). A noter que pour que le .htaccess fonctionne il faut que le module rewrite d’apache soit activé et que la surcharge de règle de ré-écriture via .htaccess soit autorisé (directive AllowOverride d’Apache).
-** A noter également que le htaccess.txt dont il est question ici est celui distribué dans chaque version de Spip.- Assurez vous que l’ensemble de votre arborescence dispose des bons droits : typiquement le propriétaire des fichiers est l’utilisateur utilisé par apache et dispose des droits en lecture, écriture, exécution (dans le cas contraire, utiliser les commandes chown -R et chmod -R)

-* Assurez vous que l’ensemble de votre arborescence dispose des bons droits : typiquement le propriétaire des fichiers est l’utilisateur utilisé par apache et dispose des droits en lecture, écriture, exécution (dans le cas contraire, utiliser les commandes chown -R et chmod -R)

La mutualisation, qu’est ce ?

Supposons que vous avez plusieurs sites sous SPIP... Vous pouvez bien sûr installer les fichiers de SPIP en plusieurs exemplaires, mais vous perdez ainsi de la place et surtout de la facilité de maintenance.

Mutualiser des sites SPIP, c’est mettre en commun ce qui peut l’être (le moteur de squelette, l’interface privée etc), tout en proposant des données séparées.

Comment mutualiser ?

-* Il existe déja une documentation complète (mais complexe) sur la Mutualisation du noyau SPIP. Ce code est en train d’être revu, dans la branche de développement de SPIP 1.9.3, de manière à simplifier le procédé. Vous n’en avez pas besoin pour réussir votre mutualisation.

Voici où nous en sommes, à la révision 9330 de SPIP et 12308 du plugin :

-* - Installez les fichiers de SPIP dans un répertoire, comme vous le ferez classiquement ; appelons-le spip/, c’est la racine de votre système ( tous les virtualhost pointent dans ce répertoire ).
.
-* - Créez un répertoire sites/ à l’intérieur du répertoire racine.

j’ai changé un nom de variable $site en $domaine pour que ce soit plus clair.

Le principe est simple : à chaque site, qu’on identifiera par une variable <code>$domaine</code code>$site</code >, correspond à un répertoire <code>sites/$domaine/</code code>sites/$site/</code > ; ce répertoire contient lui-même les quatre sous-répertoires de données du site :
-  <code>spip/sites/$domaine/config/</code code>spip/sites/$site/config/</code > contient les données de connexion connect.php et éventuellement le fichier mes_options.php du site ;
-  

spip/sites/$domaine/IMG/&lt;/code <code>spip/sites/$site/IMG/&lt;/code > contient les images et documents associés aux articles de ce site;
- <code>spip/sites/$domaine/tmp/&lt;/code <code>spip/sites/$site/tmp/&lt;/code > contient les fichiers cache de tout type;
- <code>spip/sites/$domaine/local/&lt;/code <code>spip/sites/$site/local/&lt;/code > contient les images calculées (vignettes réduites, formules TeX...).


{fin de la modification de la variable, il est tard, alors je préfère écrire ce que je modifie ici}


{{Comment identifier un site?}}


Prenons l'exemple d'un système mutualisé qui sert les pages pour différents noms de domaines, chose.tld et truc.tld.


Il faut, tout d'abord, que <code>http://chose.tld/

et http://truc.tld/ pointent tous deux vers la racine du système : pour cela il faut :

  1. que le DNS pointe vers le serveur ;
  2. que le serveur soit configuré de manière à servir ces domaines depuis notre répertoire spip/ (directive VirtualHost, commande « Héberger un domaine » d’AlternC, etc.)
    Voir article 2194

Voici en quelques copies d’écran les paramétrages utilisés pour scriibe (ceci est un exemple, il y a d’autres moyens d’y arriver) .

config dns
On choisit d’utiliser les dns de gandi
les dns de gandi
L’adresse des 3 serveurs dns de gandi
Redirection vers le serveur
Ici on indique l’adresse ip du serveur vers lequel les adresses seront redirigées. A noter l’Etoile qui permet de rediriger n’importe quel adresse *.scriibe.net vers le serveur qui héberge la mutualisation

Une fois ceci effectué, nous avons donc deux sites, tous deux servis par la même installation de SPIP. Bien évidemment, si on installe le site maintenant, il répondra de la même manière aux deux noms de domaines, il faut donc agir avant de procéder à l’installation du site.

On commence par créer un fichier central de configuration, dans spip/config/mes_options.php, qui contient :

<?php
    require _DIR_RACINE . 'mutualisation/mutualiser.php';
    demarrer_site($_SERVER['HTTP_HOST']);
?>

Si votre fichier mes_options.php est dans /ecrire, ça fonctionnera aussi très bien

Cette configuration est exécutée à chaque hit sur un fichier de SPIP, et définit les répertoires où le script ira chercher les images, la connexion à la base de données etc, comme indiqué plus haut.

En l’occurrence, nous avons décidé que chaque site serait représenté par la valeur de $_SERVER['HTTP_HOST'], c’est-à-dire truc.tld ou chose.tld. Si le site n’est pas installé (le répertoire spip/sites/truc.tld/ n’existe pas), la commande demarrer_site($site) le signale et vous demande de créer ce répertoire ainsi que les quatre sous-répertoires indispensables.

<blockquote class="spip">

www ou pas ?

Il est possible de décider que l’url http://www.chose.tld/ doit être identifiée avec l’url http://chose.tld/, en d’autres termes qu’il ne s’agit que d’un seul et même site ; il faut dans ce cas être un peu plus subtil :

<?php
   require _DIR_RACINE . 'mutualisation/mutualiser.php';
    $site = str_replace('www.', '', $_SERVER['HTTP_HOST']);
    demarrer_site($site);
?>

Cependant, une autre possibilité est largement préférable : il faut rediriger http://www.chose.tld/ vers http://chose.tld/ (ou l’inverse), en faisant par exemple :

<?php
   require _DIR_RACINE . 'mutualisation/mutualiser.php';
    $site = str_replace('www.', '', $_SERVER['HTTP_HOST']);
    if ($site != $_SERVER['HTTP_HOST']) {
         include_spip('inc/headers');
        redirige_par_entete('http://'.$site.'/');
    }
    demarrer_site($site);
?>
</blockquote>

et dans ce cas les répertoires créés seront spip/sites/chose.tld/...

Pour faire un compliqué ( possibilités )
Quoiqu’il en soit, le système de nommage du site est ouvert et peut se baser sur ce que l’on veut ; si on héberge par exemple sur ce système mutualisé tous les sites des sections locales de chose.tld, par exemple antananarivo.chose.tld, capetown.chose.tld, beijing.chose.tld, on fera :

notez que ici , c’est un exemple , si vous débutez ne le faites pas
<
cadre > </cadre >
< ? php
require _DIR_RACINE . ’mutualisation/mutualiser.php’ ;
if (!preg_match(’,^(www\.) ?(.*)\.chose.tld$,’, $_SERVER[’HTTP_HOST’], $r))
die (« Erreur : ce site n’est pas une chose.tld : ».$_SERVER[’HTTP_HOST’]) ;
demarrer_site($r[2]) ; // $r[2] correspond au (.*) de l’expression rationnelle
 ?<cadre ></cadre > < ?

et dans ce cas les répertoires créés seront spip/sites/antanarivo/, spip/sites/capetown/, spip/sites/beijing/...

Ou placer mes_options.php ? .
pour ce faire j’ai recopié le fichier fourni mes_options.php.txt dans /spip/config/mes_options.php et cela permet de retrouver les dossiers automatiquement si les vhosts sont créés bien sur.

Partager une même base de données ?

Il est bien clair que les sites ne doivent pas mélanger leurs données ; en revanche il est possible (mais pas forcément souhaitable) de n’utiliser qu’une seule et unique base de données pour l’ensemble des sites d’un même système de mutualisation. On séparera alors les différents sites en utilisant des tables dont les noms seront préfixés différemment.

Pour utiliser les préfixes de table, dans notre exemple ci-dessus, on utilisera antanarivo comme préfixe pour les tables du site antanarivo, etc ; ainsi dans la base de données (unique), on aura des tables antanarivo_articles pour les articles du site antanarivo, et beijing_articles pour les articles du site beijing.

Pour faire cela, il suffit d’indiquer l’option suivante, dans l’appel à demarrer_site() :

    demarrer_site($site, array('table_prefix' => true)); 

Cette option « rabote » un peu la variable $site de manière à en faire un préfixe valide pour MySQL (12 caractères, lettres ou chiffres, pas de points ni de tiret, commence par une lettre). Le préfixe est enregistré dans la variable globale de SPIP $GLOBALS['table_prefix'].

Pour tenter de garantir l’unicité (tant que possible), si le nom du site est trop long (saint-gravier-la-bruyarde), le préfixe sera de la forme 'saintg'+6 derniers caractères de la clé md5($site), afin d’éviter un clash avec saint-gravier-le-feuillu. Afin d’éviter de confondre deux sites comme a.b.domaine.tld et ab.domaine.tld, la fonction appose aussi un bout de md5 si le nom du site contient des caractères autres que lettres ou chiffres (un point, par exemple).

Si l’on utilise des bases différentes, on peut aussi changer le préfixe, mais pour le coup ça n’a pas d’importance. C’est lors de la connexion initiale (« installation du site ») qu’on précisera la base à employer, après l’avoir éventuellement créée, depuis SPIP ou dans l’interface AlternC.

Héberger des sites pour d’autres personnes

Dès lors que l’on veut héberger des sites pour d’autres que soi-même, on est confronté au processus d’installation de SPIP qui exige le login, mot de passe de la base de données, et permet ensuite à celle qui installe de choisir sa base parmi la liste des bases disponibles. S’il faut créer une base par utilisateur, ou si on doit prendre le risque de laisser l’installation partir sur les données d’un autre site (suite à une fausse manipe de sélection de la base ou du préfixe), on perd un des avantages de la mutualisation.

Considérons ici le scénario d’une seule base de données partagée par tous les sites : SPIP permet désormais de préciser dans mes_options.php une ou plusieurs des données de connexion à la base :

define ('_INSTALL_HOST_DB', 'localhost');
define ('_INSTALL_USER_DB', 'truc.tld');
define ('_INSTALL_PASS_DB', '1234FGH78');
define ('_INSTALL_NAME_DB', 'touslestructld');

Ces données étant ainsi figées, l’installation de SPIP ne les demande pas à la personne qui installe le site, mais lui signale que la donnée est fournie par l’hébergeur. Cette astuce est aussi bien pratique si on veut installer beaucoup de sites pour soi-même : on peut par exemple définir _INSTALL_HOST_DB, _INSTALL_USER_DB, _INSTALL_PASS_DB, mais laisser libre le nom de la base, pour pouvoir la créer/choisir à chaque installation (mais alors attention à la sécurité de la chose : mal géré, ça peut devenir catastrophique).

Création automatique du site

Les réglages précédents indiquent comment on gère l’association entre une URL, un site et une base de données. Il reste à voir comment créer automatiquement le site, sans avoir à aller par FTP créer des sous-répertoires etc.

Création automatique des sous-répertoires. C’est très simple, pour que le répertoire spip/sites/xxxx/ et ses sous-répertoires soient créés à la volée lors de la première connexion sur le site (au premier hit, une fois le DNS et le VHost/VirtualServer installés), il suffit de l’indiquer dans les options de la fonction demarrer_site() :

demarrer_site($site, array(
     'creer_site' => true
));

La première visite sur le site créera automatiquement les répertoires nécessaires, et il vous suffira d’aller dans ecrire/ pour lancer l’installation.

Attention ici à la sécurité : il faut absolument éviter d’avoir à la fois un domaine pas encore installé, les mots de passe SQL définis et un accès lire à toutes les bases ou tables de votre base mutualisée ; dans un tel cas en effet n’importe qui peut venir prendre le contrôle de n’importe quel site hébergé, ce qui fait mauvais effet...

Toutefois, le système est verrouillé par un code d’activation qui sera demandé au visiteur qui souhaite créer le site. Par défaut ce code est ecureuil, mais vous pouvez le supprimer en indiquant, dans demarrer_site(), l’option 'code' => '', ou le modifier en indiquant 'code' => 'rhooo' ou tout autre secret. (Et, si le code est activé, il faut que le visiteur accepte les cookies pour pouvoir créer son site.)

Création automatique de la base de donnée

Le système peut aussi créer la base à la demande. A condition que tous les codes d’accès à la base de données soient définis, et que l’utilisateur MySQL ainsi défini ait les droits suffisants pour créer de nouvelles bases, l’option 'creer_base' => true permet de créer la base à la volée avant de déclencher l’installation. Il est alors recommandé de nommer la table de a façon suivante :
define ('_INSTALL_NAME_DB', 'mutu_'.prefixe_mutualisation($site));
ce qui donnera des tables nommées spip_articles dans la base mutu_capetown.

Attention, En l’état du code, _INSTALL_NAME_DB est utilisé pour _INSTALL_USER_DB et peut dépasser la limite de 16 caractères de MySQL pour le nom d’un utilisateur.
Solution dans le mes_options :
define ('_INSTALL_USER_DB', prefixe_mutualisation($site));

Création automatique d’un utilisateur sur la base de donnée créé automatiquement

Le système peut créer un utilisateur mysql à la demande. Pour cela, il faut renseigner l’option 'creer_user_base' => true. Toutefois, comme c’est le script qui s’occupe de créer les constantes _INSTALL_USER_DB (sur la valeur de _INSTALL_NAME_DB) et _INSTALL_PASS_DB (mot de passe aléatoire), il faut utiliser d’autres identifiants de connexion, à savoir un utilisateur mysql pouvant et créer une base et créer des utilisateurs. On définit ainsi _INSTALL_USER_DB_ROOT et _INSTALL_PASS_DB_ROOT, à la place des précédents, ce qui peut donner :

if (!defined("_ECRIRE_INC_VERSION")) return;
require _DIR_RACINE . 'mutualisation/mutualiser.php';


// mutualise http://serveur/spip/le_site/
if ( 
		preg_match(',^/spip/([\.a-zA-Z0-9_-]+)/,', $_SERVER['REQUEST_URI'], $r)
		AND !is_dir(_DIR_RACINE . $r[1])
) {
	// definir les prefixe des tables aussi lorsque ce n'est pas une installation.
	$GLOBALS['table_prefix'] = 'spip'; 
	
	// rep plugin (decocher pour qu'il soit dans /sites/le_site/plugins et non mutualises dans /plugins)
	#define('_DIR_PLUGINS', _DIR_RACINE . 'sites/' . $r[1] . '/plugins/');
	
	// rep Aide (aide commune aux sites ?)
	define('_DIR_AIDE', _DIR_RACINE . _NOM_TEMPORAIRES_INACCESSIBLES . "cache/aide/");


// params installation
	define ('_INSTALL_HOST_DB', 'localhost');
	define ('_INSTALL_USER_DB_ROOT', 'marcimat');
	define ('_INSTALL_PASS_DB_ROOT', 'blablabla');
	define ('_INSTALL_NAME_DB', 'mutu_'.prefixe_mutualisation($r[1]));
	define ('_INSTALL_TABLE_PREFIX', 'spip');
	
	// demarrage mutu
	demarrer_site($r[1], 
		array(
			'cookie_prefix' => true, 
			'table_prefix' => false,
			'creer_site' => true,
			'creer_base' => true,
			'creer_user_base' => true,
			'repertoire' => 'sites',
			'mail' => 'mon@mail.org'
		) 
	);
}

Envoi d’un email lorsqu’un site est créé

Envoyer des mails à la création d’un site. L’option 'email' => 'fil@rezo.net' tente d’envoyer un email à cette adresse à chaque création automatique d’une base ou des répertoires d’un site.

TODO 1 : éviter les curieux

Avec ce système les documents ajoutés peuvent être communs à tous les sites : qu’il s’agisse des documents installés dans IMG/ ou d’éventuelles pages ajoutées « à la main », le serveur enverra la même chose pour tous les appels http ne passant pas par SPIP, indépendamment du nom de domaine.

Autrement dit, le document chargé dans le site capetown sous l’URL
http://capetown.chose.tld/sites/capetown/IMG/pdf/document.pdf
est aussi accessible via
http://antananarivo.chose.tld/sites/capetown/IMG/pdf/document.pdf

Il est possible de contourner ce problème en bidouillant le .htaccess des répertoires sites/capetown/ pour bloquer les appels provenant d’un autre nom d’hôte. Cela pourrait être ajouté comme option de mutualiser_creer().

Réflexions sur les mises à jour

Mises à jour centralisées. Au fil du temps, on voudra sans doute procéder à des mises à jour, forcément centralisées, des fichiers de SPIP. Le schéma actuel des mises à jour est le suivant :

  1. mise à jour des fichiers
  2. lors d’un accès à l’espace privé, comparaison de la variable $spip_version avec la valeur mémorisée dans la base de données.
  3. si ces valeurs diffèrent, SPIP propose une mise à niveau de la base (ecrire/base/upgrade.php), laquelle se fait après une vérification FTP.

Clairement, ce processus ne peut pas fonctionner dans le cadre de la mutualisation : on ne va pas demander au responsable de chaque site d’aller créer un fichier ad hoc par FTP.

Remarque : avec dans le mes_options.php global la ligne suivante :

define('_ID_WEBMESTRES', '1');

on va permettre à celui qui crée le site d’être webmestre de celui-ci et de ne pas avoir besoin de l’authentification FTP et donc de réaliser les mises à jour sans accès FTP.

Il faut donc procéder autrement. Une piste (TODO) serait de faire un script spécialisé, qui ferait un « foreach » sur les sites, et les mettrait à jour chacun son tour en appelant la fonction spécifique d’upgrade. Sachant que, si une mise à jour se passe mal, le risque est de planter tous les sites d’un coup.

Offrir plusieurs versions. Autre problématique, la compatibilité des squelettes avec les versions de SPIP. En règle générale ça ne pose pas de problème, mais dans certains cas, on peut avoir envie de vérifier avant de basculer. On suppose alors que chaque site va vouloir upgrader à son rythme, après des vérifications (par exemple en local).

Dans ce cas, il faut prévoir quelque chose comme plusieurs installations mutualisées de SPIP, côte à côte, avec un lien symbolique identifiant les répertoires spip-version1/sites/ et spip-version2/sites/ (dans ce cas, on va créer les répertoire sites/ au même niveau que les répertoires spip-version1/ et spip-version2/).

La définition d’un site, du coup, repose dans la création d’un lien symbolique de la racine VHost du site vers la version souhaitée de SPIP. Pour changer de version, il suffit alors de modifier un lien symbolique, de vérifier si le site tourne, puis d’aller dans l’espace privé procéder à la « mise à niveau » (en général irréversible) de la base de données.

TODO : Récupérer son site

Pour être viable, le système doit proposer au webmestre de chaque site une méthode simple pour récupérer ses données et les réinstaller aillurs (en local pour tests, ou sur un site « dédié »). Pour récupérer ses données, il y a deux méthodes : la sauvegarde SPIP et le dump SQL classique. Il faut voir comment on détermine qui est le webmestre autorisé à récupérer cela (une piste avec autoriser(webmestre), cf. -Autorite-). Pour récupérer les images, un simple script avec wget suffit, mais est-ce suffisamment pratique ?

Connaître et visiter les sites mutualisés

ecrire/?exec=mutualisation permet si l’on est admin du site et que l’on a les droits suffisant (lire le code) d’afficher les sites mutualisés.

La liste ainsi produite est clicable et permet de visiter chacun des sites. Mais aussi, de procéder aux mises à jour de ces derniers.

Mettre en place un service d’hébergement mutualisé

Des notes sur la mise en place d’un hébergement mutualisé de sites spip avec gestion des utilisateurs et activation individuel des espaces : Service d’hébergement mutualisé

Retour à la version courante

Toutes les versions