Schplurtzeries
Le wiki de schplurtz
Dokuwiki

5. October 2012 crééeztrulphcs

Ceci est une ancienne révision du document !


Passage de lighttp à nginx

Bon, ben voilà. Quand on POSTe des fomulaires un peu gros (des fichiers par exemple) vers le slug via curl, et que le serveur est lighttpd < 1.5, alors on a ce genre de réponse de la part de lighttpd :

HTTP/1.1 417 Expectation Failed
Connection: close
Content-Length: 0
Date: Wed, 01 Aug 2012 20:42:03 GMT
Server: lighttpd/1.4.18

C'est un vieux bug connu de lighttpd qui est corrigé en version 1.5. Mais toutes les versions 1.4 souffrent de cette infirmité. CF le bug 1017 de lighttpd.

On peut corriger ça en utilisant un hack de curl. Comme indiqué sur cette page de stackoverflow, il suffit de rajouter l'option «-H Expect:» pour que tout rentre dans l'ordre, mais ça m'a quand même donné envie de changer de serveur web.

D'abord, on vérifie les versions disponibles, tant dans les feeds officiels avec opkg que dans les feeds non officiels avec ipkg.

root@nslu2:/etc/init.d# opkg list '*lightt*'
lighttpd - 1.4.18-r3 - Web server
lighttpd-dbg - 1.4.18-r3 - Web server
.....
lighttpd-module-webdav - 1.4.18-r3 - Lighttpd module for webdav
root@nslu2:/etc/init.d# ipkg list '*lightt*'
lighttpd - 1.4.31-1 - A fast webserver with minimal memory footprint.
Successfully terminated.
root@nslu2:/etc/init.d# 

Bon la meilleure version disponible est 1.4.31, pas suffisant. Faut passer à autre chose. essayons nginx :

root@nslu2:/etc/init.d# opkg list nginx
root@nslu2:/etc/init.d# ipkg list '*nginx*' 
nginx - 1.0.14-1 - A high perfomance http and reverse proxy server, and IMAP/POP3 proxy server.
Successfully terminated.
root@nslu2:/etc/init.d# 

nginx est disponible dans les feeds non officiel, mais seulement en version 1.0.14-1 alors que la dernière version stable est 1.2.3. La différence est grande et justifie pleinement qu'on essaye d'installer cette dernière version en la compilant sur le slug…

Préparer la compilation de nginx

Avant tout, installer un environnement minimal de développement, comme indiqué sue cette page. Ensuite, rajouter quelques bibliothèques de développement. La configuration de nginx exige pcre, mais les paquets disponibles dans les feeds n'ont pas l'option unicode-properties1), donc je compile d'abord pcre 8.31. Pour obtenir également du HTTPS, et pas seulement du HTTP, il faut aussi openssl-dev

ipkg install openssl-dev

Éventuellement, ne pas installer openssl-dev si on prévoit de ne pas utiliser HTTPS.

On pourra enlever les paquets -dev après la compilation.

Comme certaines bibliothèques (libcrypt notamment) sont installées dans /opt/lib et d'autres dans /opt/schplurtz/lib (pcre), il faut aussi trouver le moyen de passer à l'éditeur de liens l'option «indique que ce binaire doit aussi rechercher ses bibliothèques dynamiques dans /opt/lib et dans /opt/schplurtz/lib». Heureusement, le script ./configure de nginx permet d'utiliser les options de son choix passées au compilateur lors de l'édition de liens. On va donc rajouter ces trois options pour l'édition de liens :

-L/opt/schplurtz/lib -L/opt/lib -Wl,-rpath,/opt/schplurtz/lib,-rpath,/opt/lib

et ces deux options pour la compilation :

-I/opt/schplurtz/include -I/opt/include

Les deux premières indiquent de rechercher les bibliothèques dynamiques dans /opt/schplurtz/lib et /opt/lib, la seconde indique d'inscrire ces chemins dans le binaire généré.

Dernier mais non des moindres, il faut encore les sources de nginx. à prendre ici : http://nginx.org/en/download.html

Compilation de nginx 1.2.3 sur nslu2

Et bien, la machine est préparée, on a tout sous la main pour y aller. Il faut juste choisir avant de se lancer le répertoire d'installation et les modules qui seront activés.

J'installerai tout dans /opt/schplurtz/nginx-1.2.3, puis je derais un lien symbolique de nginx vers nginx-1.2.3.

J'installe tout ça dans /opt/schplurtz/nginx-1.2.3 au lieu de /opt/schplurtz/nginx. Puis je ferai un lien symbolique de nginx vers nginx-1.2.3. À la prochaine version, je changerai le lien symbolique.

ce que j'enlève et ce que j'ajoute

En fait, la compilation n'est pas très longue, ni très difficile. On peut donc enlever autant de modules qui paraissent inutiles, et si besoin, recompiler pour rajouter les modules qu'on a un peu trop vite écartés.

Les retraits d'abord :

  • ssi_module :
    Je ne fais pas de Serveur Side Include
  • proxy_module :
    Bien que ce soit l'une des fonctionnalités principales de nginx. Je n'utilise pas mon slug comme proxy, mais comme serveur web. Donc : «pas de ça, Ginette !»
  • uwsgi_module :
    Protocole de Gateway Interface vers un produit que je n'utiliserai jamais sur le slug.
  • scgi_module :
    Protocole de Gateway Interface vers des produits que je n'utiliserai jamais sur le slug. Dans les feeds, il n'y a que du PHP fcgi, pas scgi
  • limit_conn_module :
    Un slug derrière une BOX ADSL me semble déjà bien assez limité, pas la peine de rajouter un module de ralentissement (Sauf pour limiter les attaques,…. mouaip. Le jour où un pirate s'en prendra à cette pauvre chose qu'est le slug… et ben, je le mettrai hors ligne et j'aviserai. Pas près de m'arriver cette chose là)
  • limit_req_module :
    Un slug derrière une BOX ADSL me semble déjà bien assez limité, pas la peine de rajouter un module de ralentissement.

Et les ajouts maintenants

  • file-aio : Entrées/Sorties asynchrones.
    Du pour et du contre. Le contre, je ne sers pas beaucoup de données qui ne soient générées par PHP. Le pour : quand on a peu de mémoire, comme c'est le cas du slug, le cache disque sert pas à grand chose et les entrées sorties asynchrones peuvent améliorer la situation.
  • ssl_module :
    De temps en temps un peu de HTTPS quand il y a des mots de passe ou des données, ça ne fait pas de mal…
  • dav_module :
    DAV permet de voir l'arborescence de fichiers vue par le serveur web à travers le protocole WEB. En gros : un protocole de disque distant sur HTTP/HTTPS. Je suis gros fan de cette chose car elle passe en général les routeurs et autres pare-feu.
nslu2 09:11 ~/SOFT/NGINX$ time ./configure \
    --prefix=/opt/schplurtz/nginx-1.2.3 \
    --user=www-data \
    --group=www-data \
    --with-cc-opt='-I/opt/schplurtz/include -I/opt/include' \
    --with-ld-opt='-L/opt/schplurtz/lib -L/opt/lib -Wl,-rpath,/opt/schplurtz/lib,-rpath,/opt/lib' \
    --with-file-aio \
    --with-http_ssl_module \
    --with-http_dav_module \
    --without-http_ssi_module \
    --without-http_proxy_module \
    --without-http_uwsgi_module \
    --without-http_scgi_module \
    --without-http_limit_conn_module \
    --without-http_limit_req_module

En substance, voilà le reste des commandes pour installer nginx :

nslu2 $ make
nslu2 $ su
nslu2 # make install
nslu2 # strip /opt/schplurtz/nginx-1.2.3/sbin/nginx
nslu2 # mkdir -p /opt/schplurtz/nginx-1.2.3/man/man8
nslu2 # cp objs/nginx.8 /opt/schplurtz/nginx-1.2.3/man/man8

Journal complet de l'installation

pour ceux que ça intéresse…

Journal complet de l'installation

Re-compilation avec nginx-dav-ext-module

En fait, le module DAV de nginx est incomplet. Arutyunyan Roman a écrit un module complémentaire pour nginx qui implémente les méthodes PROPFIND et OPTIONS, qui manquent au module DAV de base. Il s'agit donc d'un module qui complète le module DAV existant. Au cas où ce soit nécessaire d'avoir toutes les méthodes, et tant qu'à être plongé dedans…

Pour ajouter ce module à nginx, il faut cloner le dépôt git quelque part, puis utiliser l'option –add-module=/chemin/du/dossier/du/module.

J'en profite pour installer dans un autre répertoire.

nslu2 $ rm -rf nginx-1.2.3
nslu2 $ tar xf nginx-1.2.3.tar.gz
nslu2 $ cd nginx-1.2.3
nslu2 $ prefix=/opt/schplurtz/nginx-1.2.3-dav-ext
nslu2 $ time ./configure \
--prefix=/opt/schplurtz/nginx-1.2.3-dav-ext \
--user=www-data \
--group=www-data \
--with-cc-opt="-I/opt/schplurtz/include -I/opt/include" \
--with-ld-opt="-L/opt/schplurtz/lib -L/opt/lib -Wl,-rpath,/opt/schplurtz/lib,-rpath,/opt/lib" \
--with-file-aio \
--with-http_ssl_module \
--with-http_dav_module \
--without-http_ssi_module \
--without-http_proxy_module \
--without-http_uwsgi_module \
--without-http_scgi_module \
--without-http_limit_conn_module \
--without-http_limit_req_module \
--add-module=/home/schplurtz/SOFT/NGINX/Additionnal-WEBDAV-COMMAND/nginx-dav-ext-module
nslu2 $ time make
nslu2 $ time make install
nslu2 $ test -r objs/nginx.8 && {
  mkdir -p "$prefix/man/man8"
  cp objs/nginx.8 "$prefix/man/man8"
}

Le détail ici

configuration

Avoir un serveur web est cool, encore faut-il qu'il soit configuré. Voici la config initiale que j'ai faite. Elle comprend l'utilisation de php en mode fast-cgi, une section pour un dokuwiki installé dans /latestdw/, une section pour un dokuwiki installé à la racine du site (J'ai deux versions, une stable et l'autre copie du doku de développement). Comme nginx doit discuter avec php-fastcgi, il faut aussi configurer php-fastcgi, au moins pour que les deux utilisent le même point de communication. On ne crée pas de fichier de configuration pour php-fastcgi, on passe plutôt les bonnes options au serveur php-fastcgi dans son script de démarrage.

points de configuration

  • le compte web est www-data
  • les journaux vont dans /var/log/ et pas dans /opt/schplurtz/nginx-…/logs. car /var/log est en tmpfs.
    • le journal d'accès est complètemen est désactivé
    • seul le journal d'erreur est conservé
  • php est activé en fastcgi sur socket unix
  • le document root est /www/mainsite (lighttpd utilisait /www/pages)
  • un seul process de travail sur cette petite machine
  • encodage par défaut est utf-8
  • un gros morceau de config pour dokuwiki.
/opt/schplurtz/nginx-1.2.2/conf/nginx.conf
# 
# any file or directory that is not absolute is relative to
# /opt/schplurtz/nginx-1.2.3
# 
# Please refer to nginx.conf.default for more examples and possibilities
# 
 
user  www-data;
 
# This is a small machine, and the website will be **very** low traffic.
# One worker is enough
worker_processes  1;
 
# /var/log is on tmpfs. So log there instead in /opt/schplurtz/nginx-...
error_log  /var/log/nginx-error.log;
 
# Use standard place for pid file
pid        /var/run/nginx.pid;
 
events {
    worker_connections  1024;
}
 
 
http {
    root /www/mainsite;
 
    # no need to keep logs on such a small machine
    access_log off;
 
    include       mime.types;
    default_type  application/octet-stream;
 
    sendfile        on;
    #tcp_nopush     on;
 
    #keepalive_timeout  0;
    keepalive_timeout  65;
 
    #gzip  on;
 
    server {
        listen       80;
        server_name  bloink.homelinux.net;
 
        #charset koi8-r;
	charset utf-8;
 
	# in case access_log is needed (debug ?), use this settings, because
	# /var/log is on tmpfs. So log there instead in /opt/schplurtz/nginx-...
	# access_log  /var/log/nginx-http__access.log;
 
	# Block access to .htaccess files
	location ~ /\.ht {
		deny  all;
	}
 
	#OFF cos in doku config#location / {
	#OFF cos in doku config#	index index.html;
	#OFF cos in doku config#}
 
	# 
	# INCLUDE THE VARIOUS DOKUS
	# 
	include doku/stabledoku.conf;
	include doku/latestdw.conf;
 
 
	# 
	# PHP CONFIG START
	# 
	location ~ \.php$ {
		# Workaround PHP vulnerability:
		# http://forum.nginx.org/read.php?2,88845,page=3
		try_files $uri =404;
 
		fastcgi_split_path_info ^(.+\.php)(/.+)$;
		include fastcgi_params;
		keepalive_timeout 0;
		fastcgi_param     SCRIPT_FILENAME $document_root$fastcgi_script_name;
		# Ceci doit être en accord avec les options de démarrage de php-fastcgi
		fastcgi_pass      unix:/opt/schplurtz/nginx/fastcgi_temp/php-fcgi.sock;
	}
	# 
	# PHP CONFIG END
	# 
 
 
        #error_page  404              /404.html;
 
        # redirect server error pages to the static page /50x.html
        #
        error_page   500 502 503 504  /50x.html;
        location = /50x.html {
            root   html;
        }
    }
}
/opt/schplurtz/nginx-1.2.2/conf/doku/stabledoku.conf
# 
# DOKUWIKI CONFIG START
# 
 
# 
# This stable dokuwiki is in /
# 
 
# Block access to data, conf etc... folders
location ~ /(data|conf|bin|inc)/ {
	deny all;
}
 
location / {
	index index.php;
	try_files $uri $uri/ @stabledoku;
}
 
location @stabledoku {
    rewrite ^/_media/(.*)          /lib/exe/fetch.php?media=$1 last;
    rewrite ^/_detail/(.*)         /lib/exe/detail.php?media=$1 last;
    rewrite ^/_export/([^/]+)/(.*) /doku.php?do=export_$1&id=$2 last;
    rewrite ^/(.*)                 /doku.php?id=$1 last;
}
# 
# DOKUWIKI CONFIG END
#
/opt/schplurtz/nginx-1.2.2/conf/doku/latestdw.conf
# 
# DOKUWIKI CONFIG START
# 
 
# 
# this test dokuwiki is in /latestdw/
# 
 
# Block access to data, conf etc... folders
location ~ /latestdw/(data|conf|bin|inc)/ {
	deny all;
}
 
location /latestdw/ {
	index index.php;
	try_files $uri $uri/ @latestdw;
}
 
location @latestdw {
    rewrite ^/latestdw/_media/(.*)          /latestdw/lib/exe/fetch.php?media=$1 last;
    rewrite ^/latestdw/_detail/(.*)         /latestdw/lib/exe/detail.php?media=$1 last;
    rewrite ^/latestdw/_export/([^/]+)/(.*) /latestdw/doku.php?do=export_$1&id=$2 last;
    rewrite ^/latestdw/(.*)                 /latestdw/doku.php?id=$1 last;
}
# 
# DOKUWIKI CONFIG END
#

démarrage et arrêt

Maintenant que tout est configuré, encore faut-il s'assurer que tout va démarrer comme il faut, lors du boot de la machine. Il faut écrire deux script de démarrage un pour nginx, un pour php-fastcgi. En effet, contrairement à lighttpd, nginx ne lance pas le serveur php-fastcgi, c'est à nous de le faire.

start/stop php-fastcgi

Placer le fichier php-fcgi ci dessous dans /etc/init.d et passer ces commandes :

chmod 755 /etc/init.d/php-fcgi
/usr/sbin/update-rc.d php-fcgi defaults

Le script est inspiré du script de [http://wiki.nginx.org/PHPFcgiExample|cette page]] du wiki de nginx.org.

/etc/init.d/php-fcgi
#!/bin/sh
### BEGIN INIT INFO
# Provides:          php-fcgi
# Required-Start:    $local_fs $remote_fs $network $syslog $named
# Required-Stop:     $local_fs $remote_fs $network $syslog $named
# Default-Start:     2 3 4 5
# Default-Stop:      0 1 6
# Short-Description: starts/stops php over fcgi
# Description:       starts/stops php over fcgi
### END INIT INFO
 
 
# Required-Start:    $nginx
# Required-Stop:     $nginx
 
PATH=/bin:/usr/bin:/usr/sbin:/sbin
 
test  0 = $( id -u ) || { echo "You need to have root priviliges." ; exit 1 ; }
# This parameter **MUST** be consistent with that defined in nginx.conf
SOCKET_DIR=/opt/schplurtz/nginx/fastcgi_temp # This directory must exists and be properly protected
BIND=$SOCKET_DIR/php-fcgi.sock
USER=www-data
PHP_FCGI_CHILDREN=2
PHP_FCGI_MAX_REQUESTS=1000
 
PHP_CGI=/opt/bin/php-fcgi
PHP_CGI_NAME=${PHP_CGI##*/}
PHP_CGI_ARGS="- USER=$USER PATH=/usr/bin PHP_FCGI_CHILDREN=$PHP_FCGI_CHILDREN PHP_FCGI_MAX_REQUESTS=$PHP_FCGI_MAX_REQUESTS $PHP_CGI -b $BIND"
RETVAL=0
 
fatal() {
	warn "$@"
	exit 1
}
warn() {
	printf %s\\n "$@" >&2
}
start() {
	echo -n "Starting PHP FastCGI: "
	su -c "test -O '$SOCKET_DIR'" $USER || fatal \
		"socket dir >>$SOCKET_DIR<< does not exists" \
		"or it does not belong to $USER"
	start-stop-daemon --quiet --start --background --chuid "$USER" --exec /usr/bin/env -- $PHP_CGI_ARGS
	RETVAL=$?
	echo "$PHP_CGI_NAME."
}
stop() {
	echo -n "Stopping PHP FastCGI: "
	#busybox can t handle these options : # killall -q -w -u $USER $PHP_CGI
	pkill -f $PHP_CGI
	RETVAL=$?
	echo "$PHP_CGI_NAME."
}
 
case "$1" in
	(start)
		start
	;;
	(stop)
		stop
	;;
	(restart)
		stop
		start
	;;
	(*)
		echo "Usage: php-fastcgi {start|stop|restart}"
		exit 1
	;;
esac
exit $RETVAL

start/stop nginx

Placer le fichier nginx ci dessous dans /etc/init.d et passer ces commandes :

chmod 755 /etc/init.d/nginx
/usr/sbin/update-rc.d nginx defaults
/etc/init.d/nginx
#!/bin/sh
 
### BEGIN INIT INFO
# Provides:          web-server
# Required-Start:    php-fcgi
# Required-Stop:     php-fcgi
# Default-Start:     2 3 4 5
# Default-Stop:      0 1 6
# X-Interactive:     false
# Short-Description: Start/stop nginx web server
### END INIT INFO
 
PATH=/bin:/usr/bin:/usr/sbin:/sbin
DAEMON=/opt/schplurtz/nginx/sbin/nginx
NAME=nginx
DESC="Nginx Web Server"
OPTS=
 
start() {
	echo -n "Starting $DESC: "
	start-stop-daemon --start -x "$DAEMON" -- $OPTS
	echo "$NAME."
}
stop() {
	echo -n "Stopping $DESC: "
	"$DAEMON" -s quit
	echo "$NAME."
}
reload() {
	echo -n "Reloading $DESC: "
	"$DAEMON" -s reload
	echo "$NAME."
}
test -x "$DAEMON" || { echo "$DAEMON" not present. exiting ; exit 0 ; }
case "$1" in
	(start)
		start
	;;
	(stop)
		stop
	;;
	(reload)
		reload
	;;
	(restart|force-reload)
		stop
		sleep 1
		start
	;;
	(*)
		N=/etc/init.d/$NAME
		echo "Usage: $N {start|stop|reload|restart|force-reload}" >&2
		exit 1
	;;
esac
 
exit 0

Lancement et vérifications

Maintenant, tout est prèt, le démarrage du bazar ne doit pas être plus compliqué que ça :

/etc/init.d/php-fcgi start
/etc/init.d/nginx start

En pointant mon navigateur sur la page du slug, je vois apparaître les mots

It works

Parfait.

retrait de lighttpd

Il est temps de se séparer de lighttpd qui fait double emplois.

En premier lieu, le listing de ce qui est installé :

nslu2 09:59 # opkg list_installed '*ligh*'
lighttpd - 1.4.18-r3 - 
lighttpd-module-access - 1.4.18-r3 - 
lighttpd-module-accesslog - 1.4.18-r3 - 
lighttpd-module-dirlisting - 1.4.18-r3 - 
lighttpd-module-fastcgi - 1.4.18-r3 - 
lighttpd-module-indexfile - 1.4.18-r3 - 
lighttpd-module-rewrite - 1.4.18-r3 - 
lighttpd-module-staticfile - 1.4.18-r3 - 

Ensuite la purge des paquets inutiles :

nslu2 09:59 # opkg purge $( opkg list_installed 'lighttpd*' | awk '{ print $1 }' )
Removing package lighttpd from root...
Stopping Lighttpd Web Server: stopped /usr/sbin/lighttpd (pid 1213)
lighttpd.
 Removing any system startup links for lighttpd ...
  /etc/rc0.d/K70lighttpd
  /etc/rc1.d/K70lighttpd
  /etc/rc2.d/S70lighttpd
  /etc/rc3.d/S70lighttpd
  /etc/rc4.d/S70lighttpd
  /etc/rc5.d/S70lighttpd
  /etc/rc6.d/K70lighttpd
Removing package lighttpd-module-access from root...
Removing package lighttpd-module-accesslog from root...
Removing package lighttpd-module-dirlisting from root...
Removing package lighttpd-module-fastcgi from root...
Removing package lighttpd-module-indexfile from root...
Removing package lighttpd-module-rewrite from root...
Removing package lighttpd-module-staticfile from root...
1) quoi que soit cette chose, elle est nécessaire à une option de PHP. J'aurai donc besoin de recompiler cette bibliothèque. autant le faire maintenant