lindev.fr

Aller au contenu | Aller au menu | Aller à la recherche

05 avr. 2010

Nginx + php fastcgi + perl

nginx-logo2.pngCa y est , voici la deuxième partie certainement attendu .. non !! ha .. bon .. spa grave ..
Je disais donc , nginx est maintenant en place , mais il faudrait peut être penser à le rendre compatible avec les 90% des sites sur le net aujourd'hui , c'est à dire php .. et pourquoi pas python tant que l'on y est .
Pour mettre en place cette liaison , nous allons utiliser php en fast-cgi .
Nginx ne possédant pas de mod_php comme apache , les requêtes php seronts donc transmises aux process php que nous aurons lancés en tâche de fond .
Je ne vais pas débattre des avantages et des inconvénients d'utiliser php en fastcgi , ce n'est pas le but de ce topic , mais sachez juste qu'aujourd'hui php en fastcgi est très apprécié , pour sa stabilité et sa sécurité , c'est pourquoi l'on retrouve souvent ce mode de fonctionnement chez les hébergeurs aujourd'hui ...
Vous n'étiez pas au courant ? ..

Note du 24/08/10 : Depuis php 5.3.3 il est bien plus simple et performant d'utiliser php-fpm , voir le tuto à ce sujet

PHP compilation

Et oui encore , il nous faut compiler php spécialement pour le mod fast-cgi ( ne vous inquiétez pas , il est maintenant impossible de repasser en mode cgi simple , vous aurez forcement du Fastcgi ).
Comme d'hab voici les étapes ,

  1. Récupération des source
  2. décompactage
  3. création du fichier de config à la compilation
  4. trio : ./configure make / make / install

Récupération de php

Voilà les lignes de commande correspondantes ( PHP 5.3.2 )

wget http://fr2.php.net/get/php-5.3.2.tar.gz/from/this/mirror
tar xzf php-5.3.2.tar.gz
cd /usr/local/src/php-5.3.2/
vim my_configure

Config de compilation

Voici un exemple , de config de php ( celui de ma machine de dev ) je vous laisse ajuster selon vos besoins ..

#!/bin/sh

export OPTIM=-02
./configure --prefix=/usr/local \
        --with-xsl \
        --enable-soap \
        --with-gettext \
        --enable-mbstring --with-mbstring=all \
        --disable-debug \
        --enable-memory-limit \
        --enable-ftp \
        --with-mcrypt \
        --enable-zip \
        --enable-calendar \
        --enable-exif \
        --enable-pdo \
        --with-pdo-mysql \
        --with-mysql \
        --with-pdo-sqlite \
        --with-sqlite \
        --with-zlib \
        --with-jpeg-dir \
        --with-gd \
        --enable-bcmath \
        --with-curl \

Compilation , go go go

make 
make install 

Vérification

Nous voilà avec normalement un exécutable nommé php-cgi dans /usr/local/bin_

Process FastCgi

Nous allons donc maintenant créer un script qui sera chargé de lancer X process , qui ont pour mission de répondre aux requêtes php envoyées par nginx.

Création

cd /etc/init.d/
vim php-fastcgi

Le script peut exister sous des formes plus ou moins différentes , voici celui que j'utilise :

download.pngphp-fastcgiwrapper php-fastcgi

warning.pngLà encore les script est adapté , si vous avez suivi à la lettre mon tutoriel , si vous avez effectué des modification vérifiez les paramètres , notamment:

  • USER
  • PHP_CGI

Ajout au RC

Il faut lui aussi le rendre exécutable , et le mettre dans le RC , afin que les process soient lancés au démarrage de la machine .

chmod 777 php-fastcgi
update-rc.d php-fastcgi defaults

warning.pngConcernant le nombre de process fils lancés , il faudra adapter selon la charge de votre site ... en production , la commande

netstat -atup

Vous donnera des indications sur l'état de vos process , n'en ajoutez pas trop ! travaillez de façon logique .

Vous pouvez démarrer les process :

/etc/init.d/php-fastcgi start

Liaison avec Nginx

Et bien voilà , il ne nous reste plus qu'à lui indiquer de transmettre les requêtes php aux process que nous avons lancés .

fastcgi_params

Dans un premier temps il faudra éditer le fichier de configuration fastcgi_params de nginx .

cd /etc/nginx/
vim fastcgi_params

A la fin de ce fichier , ajouter les lignes suivantes :

fastcgi_split_path_info ^(.+\.php)(.*)$;
fastcgi_param PATH_INFO $fastcgi_path_info;
fastcgi_param PATH_TRANSLATED $document_root$fastcgi_path_info;
fastcgi_param SCRIPT_FILENAME $document_root$fastcgi_script_name;

Ces lignes permettent entre autre d'indiquer aux process quel script executer , ainsi que son chemin .

Vhost ou Nginx.conf

Selon l'utilisation ou non de vhost , il vous faut ajouter ( en fait elles y sont déjà dans le conf principale si vous avez utilisé mon fichier de config nginx.conf ) les lignes suivantes dans les accolades de server .

location ~ \.php$ {

          include /etc/nginx/fastcgi_params; #or whatever you named it
          fastcgi_pass  127.0.0.1:9000;
	  index index.php;
        }


Exemple d'un vhost:

server{

        listen 8282;

        server_name lindev.fr;

        root /home/apache2/lindev.fr;

        
        location /  {

                index index.php;

        }

        location ~ \.php$ {

          include /etc/nginx/fastcgi_params; #or whatever you named it
          fastcgi_pass  127.0.0.1:9000;
	  index index.php;
        }

}

Et voilà votre serveur peut maintenant gérer les fichiers .php

Restart Nginx

Pour que les modifications prennent effet, il vous faut demander à Nginx de relire sont/ses fichiers de conf .

/usr/local/nginx/sbin -s reload

Et bien voilà pour php .. On fait la même chose avec perl ? aller .. go !

Perl CPAN

Certains sites demandent la gestion de perl , principalement pour des site de graph , tel qu'eluna , je vais donc faire en sorte que notre serveur puisse gérer ce genre de site .. même pas peur !

FCGI

Il nous faut dans un premier temps installer le paquet FCGI par cpan :

perl -MCPAN -e 'install FCGI'

Wrapper perl fastcgi

Il faut ensuite , créer le script qui ( comme pour php ) lance des process en fastcgi en attente de script à traiter .

vim /usr/bin/fastcgi-wrapper.pl

download.pngVoilà le contenu de ce script : fastcgi-wrapper.zip

Il faut maintenant le rendre exécutable

chmod 755 /usr/bin/fastcgi-wrapper.pl



Ok maintenant , nous allons créer le script qui se situe dans le RC , pour lancer les process :

vim /etc/init.d/perl-fastcgi

download.pngVoici le fichier perl-fastcgiperl-fastcgi

On le rend exécutable , et on l'ajoute au RC

chmod 755 /etc/init.d/perl-fastcgi
update-rc.d perl-fastcgi defaults
/etc/init.d/perl-fastcgi start

Liaison perl - Nginx

Nous y voilà , les process perl sont lancés , il écoutent sur le port 8999 , il ne nous reste plus qu'à ajouter dans les Vhost qui en ont besoin , les lignes suivantes :

location ~ \.pl$ {
        gzip off;
        include /etc/nginx/fastcgi_params;
        fastcgi_pass  127.0.0.1:8999;
        fastcgi_index index.pl;
    }

warning.pngCette fois , pas besoin de modifier les fichier fcgi_params car les modifications à apporter sont les même que précédemment avec php .

Nginx restart

Et bien oui comme pour php , on relance la lecture des fichiers de conf de nginx , afin de prendre en compte les modifications .

/usr/local/nginx/sbin/nginx -s reload

Good job

Ca y est , Nginx est maintenant capable de gérer les script php et perl en plus des fichiers statiques ...

Il reste encore quelques petites choses utiles à voir , comme la gestion du SSL , les redirections automatique , les réécritures d'url, pour du 301 ou l'utilisation de framework tel que symphony , Zend ou autre basé sur la réécriture d'url et un peut de sécurité en plus ...

Voilà le programme de la troisième partie sur nginx ..

23 mar. 2010

PHP et Clamav

PHP + Clamav = PHP ClamAV Lib

php-clamav_logo.png Passer les fichiers uploadés par un anti-virus , n'est plus marginal de nos jours . Même sur des systèmes linux , il faut se protéger ...

Etat des lieux

Nous allons donc utiliser un serveur web , avec apache et php5.x d'installé , évidemment clamav sera lui aussi installé et fonctionnel , si ce n'est pas le cas, vous pouvez vous reporter à ce tuto pour son installation .

Dans mon cas , je souhaitai vérifier les fichiers uploadés via un serveur FTP , comme j'ai mis en place un script PHP qui épluche les logs et averti les utilisateurs finaux de l'arrivée d'un nouveau fichier à traiter .

N'ayant finalement pas envi de mettre en place un serveur mandataire FTP transparent pour intégrer l'antivirus , j'ai décider d'utiliser le script de surveillance pour en plus d'avertir les personnes concernés , vérifier les fichiers et les supprimer en cas de détection positive .

PHP ClamAV Lib

Nous allons donc récupérer et décompresser l'archive , sur le site de ClamAV

wget http://sourceforge.net/projects/php-clamav/files/0.15/php-clamav_0.15.2.tar.gz/download
tar xzf php-clamav_0.15.2.tar.gz
rm php-clamav_0.15.2.tar.gz
cd php-clamav_0.15.2/

Compilation

phpize
./configure --with-clamav
make 
make install

PHP.ini

Nous allons donc changer un ou deux petits paramètres dans le php.ini
A commencer par le paramètre extension_dir si ce n'est pas encore fait .
A la fin de la compilation , le chemin à définir vous est indiqué , pour moi , ce sera :

extension_dir = "/usr/lib/php5/20060613/"

Ensuite , il nous faut lier l'extension clamav à php , pour celà nous allons ajouter à la fin du fichier php.ini ces quelques lignes :

extension=clamav.so
[clamav]
clamav.dbpath=/var/lib/clamav
clamav.maxreclevel=0
clamav.maxfiles=0
clamav.archivememlim=0
clamav.maxfilesize=0
clamav.maxratio=0

Enregistrez les fichier et redémarrez apache pour prendre en compte les derniers changements .
Pour vérifier que le module soit bien activé , vous pouvez entrer cette ligne de commande :

php -m | grep clamav

Qui doit normalement vous retourner clamav



Ou alors faire le grand standard echo phpinfo();

Utilisation

Ca y est vous avez fait le plus dur ... avouez que c'était simple !
Bon , ne nous reste plus qu'à utiliser ce module fraichement installé .

Dans les sources , vous avez peut être remarqué la présence d'un fichier php nommé phpclamav_test.php
N'hésitez pas à le tester , et l'ouvrir pour voir les fonctionnalités du module .

Voici son résultat :

test-clamav.jpeg

La fonction la plus utile est bien évidemment cl_scanfile qui prend deux arguments ,

  1. Le chemin vers le fichier à analyser
  2. La variable qui se verra attribué le nom du virus en cas de détection d'infection

La valeur de retour a deux valeur possibles :

  • 1 : détection de virus
  • 0 : pas de détection de virus

Ce qui vous donne donc un script du style , ( à adapter à votre utilisation )

$file = "/var/www/monfichier.zip";

$retcode = cl_scanfile($file, $virusname);
    if ($retcode == CL_VIRUS) {
        echo "<b>File path : </b>".$file."<b>Return code : </b> Virus found name : ".$virusname; 
    } else {
        echo "<b>File path : </b>".$file."<b>Return code : </b> Le fichier est sain"; 
    }

Faites vos test

Il ne vous reste plus qu'à tester vos scripts avec eicar , disponible sur son site.

Ch.

22 mar. 2010

Un antiVirus sous linux

Mon but est d'installer une solution anti-virus efficace sur mon serveur FTP.
virus.gif La solution retenu sera ClamAv qui je pense est largement assez puissante pour mon objectif .
Voilà la situation , serveur Linux sous débian lenny , avec VsfTP comme serveur FTP

L'installation

Commençons par le commencement ...

Prérequis

Voici les paquets qui doivent être installé avant la mise en place de ClamAv

#apt-get install zlib1g zlib1g-dev gcc bzip2 libbz2-dev build-essential ncurses-dev

Il nous faut ensuite créer l'utilisateur qui sera utilisé par ClamAv

groupadd clamav
useradd -g clamav -s /bin/false -c "Clam AntiVirus" clamav

Récupération des sources et décompression

A vous de vérifier qu'il n'y a pas de nouvelle version depuis l'écriture de ce billet , ici nous allons installer la version 0.95.3

wget http://downloads.sourceforge.net/project/clamav/clamav/0.95.3/clamav-0.95.3.tar.gz?use_mirror=heanet

Ne reste plus qu'à décompresser ...

zcat clamav-0.95.3.tar.gz | tar xvf -
cd clamav-0.95.3

Compilation

Pour la compilation , vous avec de nombreuses option , pour les lister , voici la commande

$./configure --help | less

Pour une utilisation standard , voilà les commandes à utiliser

$./configure --sysconfdir=/etc --with-user=clamav --with-group=clamav --with-dbdir=/var/lib/clamav
$make
#make install

N'oubliez pas la mise à jour des liens des libs

#ldconfig

Les Chemins

Pour une bonne utilisation , il nous faut maintenant créer les répertoires suivants :

mkdir /var/lib/clamav /var/run/clamav /var/log/clamav
chown -R clamav:clamav /var/lib/clamav /var/log/clamav /var/run/clamav

Les fichiers de configuration

Ils se trouvent dans /etc et sont :

  • freshclam.conf
  • clamd.conf

Comparez et commentez/dé-commentez ce qu'il faut ( n'oubliez pas de commenter la ligne "exemple" au début de chacun de ces fichiers )

Voici les fichiers tel que vous devriez les avoir avec la configuration

clamd.conf
freshclam.conf

Mises à jours automatique

Pour mettre en place la mise à jour automatique des signatures de virus , nous allons créer une tâche CRON

#vim /etc/cron.d/freshclam

Voici le contenu de ce fichier

PATH=/usr/local/sbin:/usr/local/bin:/sbin:/bin:/usr/sbin:/usr/bin
MAILTO=root

0 0,6,12,18 * * * clamav /usr/local/bin/freshclam --log-verbose
@reboot amavis /usr/local/bin/freshclam

MAILTO permet de définir l'utilisateur qui recevra les resultats/erreurs par courrier
Pour la périodicité , nous avons mis ici l'exécution du script chaque jour à 6h00 12h00 et 18h00 .Ainsi qu'au reboot éventuel de la machine .

Démarrer le démon au démarrage

Et oui dans la configuration actuelle , le mode daemon est activé , ce qui a pour avantage de charger une fois pour toute les signatures en mémoire à son démarrage , plutot qu'à chaque scan

Nous allons ajouter le petit script de start dans init.d

#vim /etc/init.d/clamd

voici le contenu

#!/bin/sh
# clamd

case "$1" in
'start')
	/usr/local/sbin/clamd
	;;
'stop')
/usr/bin/killall clamd > /dev/null 2>&1 && echo -n 'Clamd stopped'
	;;
*)
	echo "Usage: $0 { start | stop }"
	;;
esac
exit 0

Ajoutons ce script aux runlevels

chmod 777 /etc/init.d/clamd
update-rc.d clamd defaults

Il ne nous reste plus qu'à faire la première mise à jours des signatures

#freshclam -v

Une fois le téléchargement terminé , l'on peu démarrer le démon

/etc/init.d/clamd start

Mais .. la suite

Ne reste plus qu'à créer un serveur mandataire transparent , pour filtrer les flux FTP .. je travail actuellement sur FROX .. la suite bientot .

09 fév. 2009

Transformer un script PHP en Daemon ...

standing_daemon.jpg Nous allons voir ici comment faire pour qu'un script PHP puisse devenir un "Daemon" indépendant du navigateur web , personnellement je l'utilise par exemple dans un de mes projets en tant que partie serveur , le script est lancé au démarrage du serveur , puis écoute sur un port donné , pour effectuer une tache précise à la connexion d'un client ... A vous de trouver l'utilisation adéquate d'un tel système ..

Pré-requis :

Pour créer un daemon , nous allons devoir contrôler les processus via la bibliothèque PCNTL de php , pour l'installation , il faut juste compiler PHP avec l'option --enable-pcntl , et surtout , ne pas mettre --disable-cli ni --disable-cgi , car le script qui utilise les fonctions PCNTL , doivent être lancé en CGI , ou CLI , comme expliqué dans la documentation , il vous sera donc impossible de lancer votre script à partir d'un navigateur , sauf si vous utiliser php en mode CGI/FastCGI et non , en module apache .

Le principe :

Le principe est le suivant , l'utilisateur avec pouvoir ( ici root ) lance le script principale , qui dans un premier temps "fork" le processus courant , ( il crée donc un fils identique à lui-même ) , puis le processus pére se tue "Kill" . Le fils passe en chef d'orchestre change son processus en chef de session Le fils va ensuite changer d'utilisateur afin de s'exécuter sur un utilisateur avec le minimum de droits possible ( ici ce sera nobody ) . Dans un troisième temps , le fils va déclarer ses propres méthodes à la réception d'un signal du système . Et enfin , le script peut se lancer sans problème .., indépendamment du processus pére ou du terminal qui à lancer le script ..

L'exemple :

Comme expliqué plus haut , nous allons reprendre chaque étape importante et voir le code "PHP" correspondant ... aller c'est parti ...

Forker le processus pére :

$pid = pcntl_fork();
	   
if ($pid == -1)
    {
	/* Échec du fork*/
	echo "Échec du fork!\n";
	exit();
    }elseif ($pid)
    {
	/* Termine le process père */
	exit();
    }else
    {
	/* Process Fils*/

        //Fait du processus courant un chef de session
	posix_setsid();

        //Changement du répertoire courant pour l'exécution du script
	chdir('/');

        //change le umask de PHP en 0777
	umask(0);

        //Retourne l'identifiant du processus fils
	return posix_getpid();
    }

Voilà comment creer un démon .. dans le script ci-dessus , c'est la fonction pcntl_fork() qui s'occupe de dupliquer les processus , ensuite , vous imaginez deux processus qui s'exécutent en parallèle .. l'un qui a un $pid ( le pére , car c'est la pére qui a lancé le fork ) et un autre qui n'en a pas ( le fils , car $pid n'est pas défini ) . En tue donc le pére avec la commande exit() . Le processus fils continue donc seul son chemin .. il fait du processus courant un chef de session ... via la fonction posix_setsid(); , pour ensuite changer le répertoire courant , et le mask de php , pour au finale ,retourner son identifiant .

Changer d'utilisateur

Pour des raison de sécurité , il faut changer d'utilisateur courant , car là nous somme toujours en root :

if( !posix_setgid( 65534 ) )
    {
        print "Erreur  setgid :" . $gid . "!\n";
        exit;
    }

    if( !posix_setuid( 65534 ) )
    {
        print "Erreur setuid :" . $uid . "!\n";
        exit;
    }

Voilà , pour le changement d'utilisateur , nous avons récupéré l'UID et le GID de l'utilisateur nobody pour l'attribuer au processus fils via les fonctions posix_setuid() et posix_setgid()

Les signaux :

Le script fils peut déclarer ses propres méthodes pour gérer comme il l'entend ( ou plutôt comme VOUS l'entendez ) , la réaction aux signaux systéme .

declare(ticks = 1);

/* handle signals */
pcntl_signal(SIGTERM, 'sig_handler');
pcntl_signal(SIGINT, 'sig_handler');
pcntl_signal(SIGCHLD, 'sig_handler');

/**
* Signal handler
*/
function sig_handler($sig)
{
    switch($sig)
    {
        case SIGTERM:
        case SIGINT:
            exit();
        break;

        case SIGCHLD:
            pcntl_waitpid(-1, $status);
        break;
    }
}

La gestion des signaux ci-dessus , utilise les ticks déprécié depuis php 5.3 ... il faudra donc trouver une autre alternative ... ici , la gestion des signaux n'est pas obligatoire !

Lancement :

Pour lancer votre daemon, plusieurs solutions , soit apache fonctionne avec php en mode CGI/FastCGI , alors , vous pouvez lancer le daemon via votre navigateur ( mais mauvaise idée , car de ce fait , votre navigateur doit se trouver sur la même machine que votre script et être lancer en root ), sinon, ce sera en ligne de commande , comme ceci :

En root:

php /dir/de/votre/script/serveur.php

Le script se lance puis s'arrête aussitôt .. car en faite , le script que vous lancez est le process pére .. qui dés qu'il a créé son fils , se tue !

Pour vérifier que votre daemon se trouve bien dans la liste des processus , il vous suffit de le rechercher dans les process courant , exemple pour serveur.php :

ps -xa | grep serveur.php

Qui retourne une ligne de ce style :

25951 ? Ss 0:00 php /dir/du/script/serveur.php

Voilà , en espérant avoir écrit un script intéressant , sans trop entrer dans les détails ..

Christophe.