lindev.fr

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

31 oct. 2013

Déployer votre app Python automatiquement avec fabric .

Petite mise en place

Lorsque vous développez en Python, contrairement à PHP, ce dernier compile le code à la première "interprétation", puis génère des fichiers "bytecode", avec l’extension .pyc.
Une fois cette génération faite, le fichier source .py du même nom sera ignoré, et ce jusqu'au redémarrage du process.
Le redémarrage du process, vérifiera les modifications apportées aux sources ( .py ) afin de les recompiler et exécuter le code mis à jour.

Tout ça pour en venir au fait, que lorsque vous développez en python ( par exemple une app. web avec Django ), lorsque vous envoyez vos maj sur le serveur de production, vos modifications n'auront aucun effet tant que vous n'avez pas redémarré les process ( uwsgi, ou autre .. ) .

Ce qui peut vous surprendre au début, si vous venez du monde PHP ou les modifications sont prises en compte instantanément.
Bien que vous pouvez avoir quelque chose de similaire si vous utilisez PHP avec le cache APC ... mais ce n'est pas le sujet ici.

Étapes manuelles

Donc si je prends mon projet Django, voici les étapes manuelles à appliquer :

Sur mon poste de développement :

git add xx ; s'il y a des fichiers sources à ajouter au dépôt
git commit -a -m "Commentaire de mon commit"
git push

Sur mon serveur de prod :

cd /mon/depot
git pull 
# vim settings.py pour des update de version de cache etc .. 
workon monenvironnementvirtuel
python manage.py collectstatic
supervisorctl MonApp reload

Étapes avec fabric

Sur mon poste de développement :
fab backup
Sur le serveur
fab deploy

Bon ... voyons maintenant comment mettre en place fabric .

Installation et fabfile.py

Commençons par installer la librairie ( sur le serveur et le poste de dev. )

workon monenvironnement
pip install fabric

Puis nous allons créer notre fichier qui va se charger d'automatiser les différentes étapes manuelles: fabfile.py

#! -*- coding:utf-8 -*-
from fabric.api import local,prefix
from fabric.colors import green

import re

PROJECT_NAME = "MonApp" # Nom de l'app
SUPERVISOR_APP_NAME = "MonApp" # Nom de l'app supervisor à redémarrer
VIRTUALENV_NAME = "MonApp"  #Nom de l'environnement virtuel à utiliser

def backup():
    #Sauvegarde les librairies utilisées par le projet ( pour les installer si besoin sur le serveur .. sans réfléchir )
    local('pip freeze > requirements.txt')

    #Ajoute les éventuels fichiers non "trackés" 
    local('git add .')

    git_status = local( 'git status', capture=True )
    print git_status

    regx = re.compile(r"(nothing to commit)")
    if not regx.search( git_status ):

        print(green("Il y a des choses à commiter !"))

        print("Entrez votre commentaire de commit : ")
        comment = raw_input()

        #Renseignement du commentaire du commit
        local('git commit -m "%s"' % comment)
        local('git push')
    else:
        print(green("Rien à commiter !"))


def deploy():
    """
    Déploie l'app sur le "serveur" courant 
    """

    #Récupère la dernière version du dépôt
    local('git pull')

    #Permet de changer la version des fichiers statiques à servir 
    print(green("Version du cache à appliquer []:"))
    vcache = raw_input()
    xs = vcache.strip()
    if xs[0:1] in '+-': xs = xs[1:]
    if xs.isdigit():
        init_cache(int(xs))


    # Active ou désactive le mode DEBUG
    print(green("Désactiver le mode DEBUG ( y/n ) ? [y]"))
    disable_debug = raw_input()
    print disable_debug
    if disable_debug == 'y' or disable_debug=='':
        print(green("Passage du mode DEBUG à FALSE"))
        switch_debug(False)
    else:
        print(green("Passage du mode DEBUG à TRUE"))
        switch_debug(True)

    #Récupère les éventuels nouveaux fichiers statiques 
    local(django_manage( 'collectstatic --link', VIRTUALENV_NAME ),capture=False,shell='/bin/bash')

    #Redémarre le processus supervisord
    local('supervisorctl restart '+SUPERVISOR_APP_NAME)



def init_cache(change_to):

    local( 'cp '+ PROJECT_NAME +'/settings.py '+ PROJECT_NAME +'/settings.bak' )
    sed = "sed 's/^VERSION_JS_CSS = [0-9]*$/VERSION_JS_CSS = %s/' "+ PROJECT_NAME+"/settings.bak > "+PROJECT_NAME+"/settings.py"
    local(sed % (change_to))

    local('rm '+PROJECT_NAME+'/settings.bak')

def switch_debug(change_to):

    local( 'cp '+ PROJECT_NAME +'/settings.py '+ PROJECT_NAME +'/settings.bak' )
    sed = "sed 's/^DEBUG = [a-zA-Z]*$/DEBUG = %s/' "+ PROJECT_NAME+"/settings.bak > "+PROJECT_NAME+"/settings.py"
    local(sed % (change_to))

    local('rm '+PROJECT_NAME+'/settings.bak')

Et voilà en deux commandes, vous avez mis à jour votre application sur le serveur de production, chargé les éventuels fichier statiques dans le répertoire prévu à cet effet, modifié le fichier settings.py pour y indiquer s'il faut invalider les fichiers statiques ( css, js .. ) afin de forcer les navigateurs à charger les nouvelles versions, activé ou non le mode DEBUG de Django, et pour finir relancé les process uwsgi grâce à supervisor ( commande supervisorctl ).

Il est possible de tout faire depuis son poste de développement, Fabric peu se connecter sur les serveurs distants pour déployer l'application, ce qui peu s'avérer très utile lorsque vous avez plusieurs frontaux à mettre à jour .

Backup

Fabric_backup.png

Deploy

Fabric_deploy.png

Source:

Fabric : http://docs.fabfile.org/en/1.8/

10 juil. 2010

La "crackabilité" de vos mots de passe

que vaut votre mot de passe

password2.jpg

J'ai découvert ce site par hasard , et j'ai été pour le moins surpris du résultat sur les mots de passe que j'utilise , qui selon moi sont plutôt sécurisés ..

Testez les vôtres ... et si le résultat est inférieur à 1 jour ( et encore ) , alors je vous conseille de complexifier votre mot de passe .

Bon test :

howsecureismypassword

07 avr. 2010

Nginx - Vhost - php - perl - ssl

banniere-nginx.png
Bon , le billet qui sert de pont de départ ... pas toujours évident sur un blog de s'y retrouver .. sans sommaire ...
Voici donc le sommaire concernant les billets de Nginx

Installation , et utilisation de base

Installer Nginx manuellement , options de compilation , découvrez les emplacements des différents fichiers de configuration , démarrage automatique , options de base ect ...

Gérer les pages PHP et PERL

Nginx seul c'est bien , mais pouvoir l'utiliser avec php perl et .. tant d'autres , c'est mieux , dans ce billet , est éxpliqué la mise en place de php et perl en fast-cgi , et la liaison avec nginx .

SSL , vhost , et autres petites options

Mise en place de pages sécurisées par ssl , création de certificats , redirection automatique , mod_rewrite , compatibilité avec certains framework qui ont besoin du mod rewrite commezend framework , symphony , etc ...

02 avr. 2010

Nginx Premiers pas

nginx-logo.png''Alors voilà , je vais essayer de présenter au mieux nginx , ou tout du moins , expliquer sont installation et utilisation .
On trouve de plus en plus de documentations sur le net , et je vais donc ici essayer de regrouper les choses , pour au final avoir un serveur HTTP digne de se nom , qui pourra sans problème remplacer son homologue Apache .
Je conseillerai même Nginx sur des machine de faible capacités en mémoire et/ou processeur .''

Présentation

Bon là je ne vais pas m'éterniser , le site NginxFr vous l'expliquera certainement mieux que moi .
En gros , c'est un serveur web ( entre autre ! ) open sources , d'origine Russe , développez pour répondre à une forte charge , grâce à une gestion des requêtes asynchrone , via des process innovants .
Ses points forts sont donc , une stabilité accrue , une faible consommation de mémoire , une simplicité de configuration , qui le rend ( je trouve ) agréable à administrer .

Notez qu'il vous est possible de tester ce serveur sans casser l'existant .. il vous suffira de le faire tourner sur un autre port , exemple , le 82 !
Aller , n'hésitez plus lancez vous dans l'aventure ...

L'installation

Comme à mon habitude , je n'utiliserai pas la version des paquet de ma distribution .
Il est pour moi important de savoir ce que j'ai sous le capot , et d'en maitriser ( ou au moins essayer ) toutes les facettes .

Récupération des sources et décompactage

cd /usr/local/src
wget http://sysoev.ru/nginx/nginx-0.7.65.tar.gz
tar xzf nginx-0.7.65.tar.gz
cd nginx-0.7.65

Nous voilà prêt à lancer la compilation de la bête ...
Commençons par éditer un fichier de configuration à la compilation , ( façon débian like comme le précise le site ) , j'ai juste ajouté l'option --with-http_stub_status_module qui permet d'avoir l'équivalent du server-status d'apache .
Pour les autres options , je vous laisse voir la description de chacun d'eux qui sont tres bien documenté à cette adresse

Fichier my_configure

vim my_configure

Et voici le contenu :

#!/bin/sh

./configure \
  --conf-path=/etc/nginx/nginx.conf \
  --error-log-path=/var/log/nginx/error.log \
  --pid-path=/var/run/nginx.pid \
  --lock-path=/var/lock/nginx.lock \
  --http-log-path=/var/log/nginx/access.log \
  --http-client-body-temp-path=/var/lib/nginx/body \
  --with-http_ssl_module \
  --http-proxy-temp-path=/var/lib/nginx/proxy \
  --with-http_stub_status_module \
  --http-fastcgi-temp-path=/var/lib/nginx/fastcgi \
  --with-debug \
  --with-http_flv_module \
  --with-http_stub_status_module

Rendons le exécutable et go ! :

chmod 777 my_configure
./my_configure
make
make install
mkdir -p /var/lib/nginx/body

warning.png Il vous faudra certainement installer des librairies manquantes ... les messages d'erreurs vous indiquerons lesquels .

Configuration

Nous allons maintenant nous attaquer à la configuration de la bête ... pour commencer .. ou ce trouve quoi !

Emplacements des éléments

Petit tour d'horizon , comme spécifié à la configuration , les principaux fichiers de conf se trouvent dans :

/etc/nginx/

Les fichiers de logs :

/var/log/nginx/

L'exécutable :

/usr/local/nginx/sbin/

Rotation des logs

Si vous ne voulez pas que vos fichiers de logs remplissent le disque en quelques mois , alors , il est préférable de faire une rotation journalière .
Nous allons dédier cette tâche à logrotate .

cd /etc/logrotate.d/
vim nginx

Et voici le contenu :

/var/log/nginx/*.log {
        daily
	missingok
	rotate 5
	compress
	delaycompress
	notifempty
	create 640 root adm
	sharedscripts
	postrotate
    	if [ -f /var/run/nginx.pid ]; then
    		/usr/local/nginx/sbin/nginx -s reload > /dev/null
    	fi
   	endscript

}

download.pngOu si vous préférez en format à dl : nginx_logrotatenginx

Configuration principale

Le fichier de configuration principale se trouve donc là : /etc/nginx/nginx.conf
Nous allons sauvegarder la version originale , et démarrer de 0 , enfin presque ..

cd /etc/nginx/
mv nginx.conf nginx.conf.old
vim nginx.conf

warning.png Si vous souhaitez faire tourner votre serveur nginx sur un autre port , n'oubliez pas de le modifier ( directive listen ) . De même que l'utilisateur que j'utilise www-data n'est pas forcément le même pour vous .. adaptez à votre conf.

download.pngJe vous met le fichier de conf à dispo , ici : nginx.confnginx.conf

Pour ce qui est des explications sur chaque option , les utilisateurs d'apache trouverons tres vite leurs marques , de plus la documentation est compléte ici.

les Vhosts

Vous l'avez certainement remarqué , dans nginx.conf , il y a la ligne

include /etc/nginx/site-enabled/*;

Qui permet de gérer les vhosts de façons structuré , tous les fichiers de conf présents dans ce répertoire seront analysé par nginx à sont lancement .

Préparons le terrain avant de creer notre premier vhost .

mkdir site-available
mkdir site-enabled

Voici maintenant la création d'un vhost type , le plus simple du monde .

cd /etc/nginx/site-available
vim monsite.com

Et voilà le contenu type :

server {
        listen       80;
        
        server_name  monsite.com  www.onsite.com;

        location / {
            root   html;
            index  index.html index.htm;
        }
    }

Vous pouvez donc spécifier un ou plusieurs ports par vhost , ensuite définir des options propre à chaque location .
Nous verrons par la suite comment par exemple ajouter des régles de cache pour les données statics , ou rediriger en fonction de l'ip ect ... mais ne brulons pas les étapes .
Activons notre vhost !

ln -s /etc/nginx/site-available/monsite.com /etc/nginx/site-enabled/

Start Nginx

Pour la première fois nous allons donc lancer nginx afin de tester la conf de base , pour celà il faut vous rendre dans le répertoire contenant l'exécutable .

info.pngl'executable nginx s'utilise de cette façon :

nginx -s [ stop | quit | reopen | reload ] 

Pour démarrer :

cd /usr/local/nginx/sbin/

Et go

./nginx


Il ne doit y avoir aucun message au lancement , vous pouvez vérifier au niveau des logs si tout se passe bien ,

tail -f /var/log/nginx/error.log

Si tout est ok , alors vous voilà prêt à servir des page statiques .. testez avec votre navigateur !

http://localhost:80

Démarrage automatique

Vous avec votre serveur dans sa configuration de base prêt à l'emploi , mais au prochain redémarrage , celui-ci ne sera pas automatiquement lancé , nous allons donc créer de quoi automatiser tout ça ( debian like ).

Rendez-vous dans /etc/init.d/ et éditer le fichier nginx

cd /etc/nginx
vim nginx

Je vous met donc à disposition le script de démarrage ici : nginxnginx

warning.pngLe fichier que je vous donne est adapté à la configuration donné dans ce tuto , si vous avez modifié des choses à la compilation , n'oubliez pas d'adapter ce script au besoin .

Nous allons maintenant le rendre exécutable , puis le déclarer dans les RC

chmod 777 nginx
update-rc.d nginx defaults

Fin de la première partie ..

Et oui , bilan , vous avez un serveur web http , qui peut dés à présent servir du contenu statique , vous savez créer des hôtes virtuels , et votre serveur démarre automatiquement à démarrage de votre machine .
Ouf ... et bien il nous reste plus qu'à prendre en charge les scripts php , et - ou perl , qui sera le sujet de la deuxième partie .. ( rédaction en cours )

19 fév. 2010

Halte là !

Sécurisez vos formulaires contre les spams

police.png

Vous avez un banal site vitrine , un livre d'or ou autres formulaires de contact / commentaires , sans protection , même minime , vous allez rapidement voir apparaître des messages non sollicités , qui peuvent même parfois se révéler dangereux .
Cet article vise à donner une solution ( parmi beaucoup d'autres ) pour éviter ce genre de désagrément , et sans le moindre captcha .
Nous allons prendre un simple formulaire de contact pour l'exemple

Le code de base , sans aucune protection

Le formulaire

<form name="contact" method="POST" action="send.php" >
    
    <table>
        <tr>
            <td>
                Pseudo :
            </td>
            <td>
                <input type="text" name="pseudo" >
            </td>
        </tr>
        
        <tr>
            <td>
                Mail :
            </td>
            <td>
                <input type="text" name="email" >
            </td>
        </tr>
        
        <tr>
            <td>
                Message :
            </td>
            <td>
                <textarea name="message" ></textarea>
            </td>
        </tr>
        
        <tr>
            <td>
                <input type="submit" name="envoyer" value="envoyer" />
            </td>
        </tr>
    </table>
    
</form>

Envoi du mail

<?php
/*
 * send.php
 * 
 */

//récupération et filtrage des données
$tData = filter_form( $_POST, "utf-8" );

//envoie du mail 
sendMail( $tdata );

?>

Voilà , quoi de plus simple .. mais quoi de plus vulnérable par le spam !!!!
Note: je ne traiterais pas ici des fonctions filter_form() et sendMail() , n'étant que des fonctions fictives pour éclaircir au maximum le code .

Protection 1 : rendre le formulaire unique

Et oui ce n'est pas parce que le formulaire est là qu'une personne malveillante doit y passer pour envoyer le mail , ce qui permet aux "pirates" de forger des requêtes , envoyé soit par une de leurs victimes , un robots ou autres méthodes détournées .

Pour rendre le formulaire unique , nous allons lui ajouter un jeton , qui sera changeant constamment , ainsi avant l'expédition du mail , l'on vérifie que le jeton est là et valide
Voilà le formulaire modifié

<form name="contact" method="POST" action="send.php" >
    
    <table>
        <tr>
            <td>
                Pseudo :
            </td>
            <td>
                <input type="text" name="pseudo" >
            </td>
        </tr>
        
        <tr>
            <td>
                Mail :
            </td>
            <td>
                <input type="text" name="email" >
            </td>
        </tr>
        
        <tr>
            <td>
                Message :
            </td>
            <td>
                <textarea name="message" ></textarea>
            </td>
        </tr>
        
        <tr>
            <td>
                <input type="submit" name="envoyer" value="envoyer" />
                
                <input type="hidden" name="jeton" value="<?php echo  md5('graindesel'.date('Y-m-d h:i:00',time()));?>" />
                
            </td>
        </tr>
    </table>
    
</form>

Et au niveau de send.php , il nous suffit d'ajouter la vérification du jeton de la façon suivante :

<?php
/*
 * send.php
 *
 */

//récupération et filtrage des données
$tData = filter_form($_POST,"utf-8");

//cree un tableau de 0 à 10
$validite = range(0, 10) ;
//initialise le resultat
$valide = false ;
//vérifie le jeton
foreach($validite as $v) {
        $valide |= ( $_POST['jeton'] == md5('graindesel'.date('Y-m-d h:i:00', time() - $v * 60)));
}

if( !$valide ){
	//redirection vers une page d'erreur
}else{
        //envoie du mail
        sendMail($tdata);
}

?>

Contrairement au formulaire initial cette fois le "pirate" est obligé de passer par le formulaire pour envoyer le mail , le jeton étant valide 11 minutes , un internaute devra remplir et envoyer ce formulaire en maximum 11 minutes , ce qui est largement faisable . :-)

Protection 2 : filtrage anti-spam

La protection du formulaire unique permet déjà de réduire de façon notable l'envoie de spam via cette page , maintenant certains réussirons toujours à passer outre , rien de bien compliqué à celà .
La derniére solution avant expédition , est d'utiliser un service enti-spam tel que akismet

Akismet est un Web-service à qui nous allons envoyer les données du formulaire , en réponse nous arons un simple booléen qui nous indiquera si oui ou non le message semble être un spam .

Enregistrement Akismet

Il vous faut une clef ( gratuite ) , pour celà allez vous enregistrer sur le site d'akismet

Utilisation akismet

Le site vous propose de nombreux plugins déjà prêts pour des applications comme Dotclear , Wordpress , punBB ect ... Mais aussi des "class" php pour des scripts perso comme le notre .

Nous allons donc télécharger la classe proposé par le site achingbrain.net

L'utilisation est trés simple, dézipez l'archive afin de rendre la classe accessible par votre serveur web ... ( je vais la mettre au même endroit que send.php pour l'exemple )

et voilà la modification de send.php pour utiliser ce service :

<?php
/*
 * send.php
 *
 */

//récupération et filtrage des données
$tData = filter_form($_POST,"utf-8");

//cree un tableau de 0 à 10
$validite = range(0, 10) ;
//initialise le resultat
$valide = false ;
//vérifie le jeton
foreach($validite as $v) {
        $valide |= ( $_POST['jeton'] == md5('graindesel'.date('Y-m-d h:i:00', mktime() + $v * 60)));
}

if( !$valide ){
	//redirection vers une page d'erreur
}else{
    
    //Test AKISMET
    $APIKey = 'aoeu1aoue';
    $MyURL = 'http://www.lindev.fr/contact/';

    $akismet = new Akismet($MyURL ,$APIKey);
    $akismet->setCommentAuthor( $tdata['pseudo'] );
    $akismet->setCommentAuthorEmail( $tdata['email'] );
    $akismet->setCommentContent( $tdata['message'] );
    $akismet->setPermalink( $MyURL );

    if($akismet->isCommentSpam()){
        //redirection vers une page d'erreur
    }else{
        //envoie du mail
        sendMail($tdata);
    }
}

?>

Cette fois non seulement l'utilisateur doit passer par le formulaire , mais en plus le message sera vérifié par un service anti-spam , ce qui vous permet d'éliminer plus de 90% des mails/messages non sollicités qui peuvent provenir de ce genre de formulaire .
Et ce sans captcha :-)

Autre barrière:

Il existe encore une autre barrière , si vous êtes encore embêté , l'interrogation de listes rbls , qui vous indique si l'adresse ip du client qui remplis votre formulaire est listé comme spammeur ou non ..
Juste pour information , en voici une pour exemple :

http://bsb.spamlookup.net/

A bientot , Ch.

- page 1 de 3