Serveur web Debian : Apache2 et FastCGI

Dans le cadre de l'installation d'un serveur web personnel avec un unique site, il n'est pas forcément nécessaire d'imaginer une configuration "poussée" d'apache avec une gestion des droits elle aussi "poussée".

Sur une Debian, apache s'exécute par défaut avec l'utilisateur www-data et le groupe www-data. Ainsi, si on héberge un site dont les fichiers ont un propriétaire différent, ils devront avoir un chmod type 755. Cependant, si on veut permettre à apache de modifier un fichier ou un repertoire, le chmod sera 777 et c'est le mal absolu !

Il faut donc installer les outils de telle sorte qu'un site puisse avoir des fichiers en 755 (par exemple) et qu'apache puisse tout de même écrire dedans. On admet donc facilement que apache doit devenir le propriétaire des fichiers.

On a donc deux solutions : utiliser www-data:www-data ou bien demander qu'apache s'exécute avec les droits des fichiers du site.

Dans le cas où on a un seul site, la première solution est envisageable...mais vient le problème d'un serveur multi-sites : peut-on prendre le risque de voir l'ensemble des sites supprimés car un d'eux aurait été piraté ? Ma réponse est non !

L'objectif de ce tutorial est le suivant :

  • Un site web admet un utilisateur unique
  • On aura un groupe commun pour tout les sites
  • Apache devra être capable, pour chaque site, de s’exécuter avec le bon utilisateur et le bon groupe

L'idée est d'utiliser pour les scripts PHP (ou perl, peu importe le langage finalement) un "Wrapper" qui permettra d'utiliser un binaire type php5-cli pour lancer les scripts php du site hébergé. C'est ce wrapper et l'utilisation de modules qui conditionnera l'exécutation d'apache avec des droits spécifiques.

Je rédige ce tutoriel avec une Debian Squeeze mais il est valable pour beaucoup d'autres système (pour peu qu'on adapte les commandes et les fichiers de conf).

Informations :

  • Sauf précision, toutes les commandes suivantes sont exécutées en root
  • Votre système doit être à jour et la liste des paquets du gestionnaire également

Si vous avez déjà un serveur en place, il y aura des perturbations quant à apache donc prévoyez des coupures relativement longues du service web. Aussi, si vous utilisez le mode php5 pour apache, il faut veiller à le désactiver.

prompt> a2dismod php5

Pour les personnes qui n'ont pas apache installé :

prompt> aptitude install apache2

Mon objectif est d'avoir des sites avec php. On va donc installer les paquets dont on a besoin :

prompt> aptitude install php5-cgi

Bien sûr, si vous souhaitez des modules comme par exemple GD, vous pouvez les installer sans problème.

Suite à cette installation, on a dans "/usr/bin/", un binaire php5-cgi qui quand on l'exécute retourne une entête HTTP et le résultat de l'exécution du code qu'on lui donne :

prompt> /usr/bin/php5-cgi 
<?php echo "Hello World\n"; ^D
X-Powered-By: PHP/5.3.3-7+squeeze1
Content-type: text/html

Hello World

C'est via ce cgi que nos scripts seront exécutés.

Nous allons installer deux modules apache2 : libapache2-mod-fcgid (pour utiliser des cgi) et apache2-suexec (pour changer les droits).

prompt> aptitude install libapache2-mod-php5 libapache2-mod-fcgid apache2-suexec

Sauf compilation par nos soins, il faudra absolument placer les sites web dans /var/www. Si comme moi, vous avez une partitions dédiée aux site web, non montée dans /var/www, vous devrez modifier la configuration de votre système. J'ai pour ma part, sur les serveurs que j'administre, un point de montage /services qui contient les données de mes services (web, git, svn, etc). Via /etc/fstab, j'ai simplement monté mon répertoire /services/web dans /var/www/service-web en faisant un bind :

prompt> mkdir /var/www/service-web
prompt> echo "/services/web /var/www/service-web none bind 0 0" >> /etc/fstab
prompt> mount -a

Nous allons créer le groupe commun de chaque site : webgroup.

prompt> addgroup webgroup

Dans mon tutoriel, j'ai décidé que mes sites seraient : site1.com, site2.com. Ainsi, j'ai choisi de nommé les utilisateurs website1 et website2. Nous allons créer les utilisateurs (unix) :

prompt> useradd -G webgroup -s /bin/false -M website1
prompt> useradd -G webgroup -s /bin/false -M website2

J'ai évoque tout à l'heure la notion de "wrapper". C'est un script shell qui va faire le lien entre apache et php5-cgi.

Je décide de placer mes wrappers, uniques pour chaque site, dans : /var/www/service-web/bin/webXXX :

prompt> mkdir -p /var/www/service-web/bin/website1 /var/www/service-web/bin/website2

Je vais maitenant placer mon script (wrapper) dans ces répertoires :

prompt> cd /var/www/service-web/bin
prompt> cat << EOF > /tmp/php5-fcgi
#!/bin/sh
exec /usr/bin/php5-cgi
EOF
prompt> cp /tmp/php5-fcgi website1
prompt> cp /tmp/php5-fcgi website2

On va maintenant donner les droits adéquates :

prompt> chmod -R 755 web*
prompt> chown -R website1:webgroup website1
prompt> chown -R website2:webgroup website2

Pour être certain que nos modules apache précédemment installés sont activés, ben nous allons les....activer :

prompt> a2enmod suexec fcgid

On ajoute une configuration chargée systématiquement par apache avec des options très bien documentées ici.

prompt> cat << EOF >  /etc/apache2/conf.d/php-fcgi
<IfModule mod_fcgid.c>
  AddHandler fcgid-script .fcgi .php
  FcgidIPCDir /var/lib/apache2/fcgid/sock
  FcgidConnectTimeout 10
  FcgidIOTimeout 120
  FcgidOutputBufferSize 0
  FcgidMaxRequestsPerProcess 500
  FcgidMaxRequestLen 131072
  FcgidMinProcessesPerClass 0
  FcgidIdleScanInterval 1
  FcgidProcessLifeTime 20	
</IfModule>
EOF

L'étape suivante est la création des répertoires pour les sites web. J'ai décidé de les placer dans un répertoire www de /var/www/service-web/ :

prompt> mkdir -p /var/www/service-web/www/site1.com /var/www/service-web/www/site2.com 
prompt> cd /var/www/service-web/www/
prompt> cat << EOF > /tmp/droits.php
<?php echo shell_exec("id"); ?>
EOF
prompt> cp /tmp/droits.php site1.com
prompt> cp /tmp/droits.php site2.com
prompt> chmod -R 755 site*
prompt> chown -R website1:webgroup site1.com
prompt> chown -R website2:webgroup site2.com

La configuration des VirtualHost se fait très simplement.

prompt> cat << EOF > /tmp/vhost
<VirtualHost *:80>
 ServerName DOMAIN
 DocumentRoot /var/www/service-web/www/DOMAIN
 SuexecUserGroup USER webgroup
 <Directory /var/www/service-web/www/DOMAIN>
  FCGIWrapper /var/www/service-web/bin/USER/php5-fcgi .php
  Options Indexes FollowSymLinks MultiViews
  Options +ExecCGI
 </Directory>
</VirtualHost>
EOF
prompt> sed 's/USER/website1/;s/DOMAIN/site1.com/' /tmp/vhost > /etc/apache2/sites-available/site1.com
prompt> sed 's/USER/website2/;s/DOMAIN/site2.com/' /tmp/vhost > /etc/apache2/sites-available/site2.com
prompt> a2ensite site1.com site2.com

L'ajout de VirtualHost cumulée à l'activation de modules, il faut redémarrer apache :

prompt> service apache2 restart

Pour terminer, on doit s'assurer que tout fonctionne correctement. Si vous allez sur http://site1.com/droits.php et http://site2.com/droits.php, vous devriez constater que les uid sont différents.

Simon Vieille

Détecter les vulnérabilités dans les dépendances de son projet

Détecter les vulnérabilités dans les dépendances de son projet

La gestion des dépendances dans un projet est quelque chose de complexe. Il y a autant de ge…

Un an d'utilisation de AdGuard comme DNS

Un an d'utilisation de AdGuard comme DNS

Au moment où j'ai commencé à utiliser Wireguard, je me suis aperçu que le principal usage qu…

Supprimer les mots de passe d'un fichier Excel

Supprimer les mots de passe d'un fichier Excel

Dans le cadre de mon travail, je vais devoir supprimer les mots de passe définis dans plusie…


  • Simon
  • Un des intérêts, à priori, à utiliser la config dont j'ai parlée, c'est la facilité à gérer des php.ini différents suivant le vhost en précisant tout ça dans le wrapper. On pourra également envisager de proposer différentes versions de php en modifiant le cgi indiqué dans ce même wrapper. J'ai eu cette dernière crontraite au boulot quand j'ai du reprendre un projet qui n'était pas compatible 5.3.3 mais 5.2.*.

    Maintenant, pourquoi pas, faudrait que je prenne du temps pour tester ça =)

Ajouter un commentaire

Votre commentaire - Vous pouvez utiliser du markdown

Renouveler