Archives pour la catégorie ‘Hébergement’

Nginx : configuration pour site PHP Symfony

http://www.symfony-project.org/

server {
   listen        192.168.0.1:80;
   server_name   www.site.fr;
   root          /home/site.fr/web/;

   location / {
      index index.php;
      try_files $uri $uri/ /index.php?$args;
   }

   location ^~ /sf/ {
      alias /home/site.fr/lib/vendor/symfony/data/web/sf/;
   }

   location ~ "^(.+\.php)($|/)" {
      fastcgi_split_path_info   ^(.+\.php)(.*)$;
      fastcgi_param             SCRIPT_FILENAME $document_root$fastcgi_script_name;
      fastcgi_param             SCRIPT_NAME $fastcgi_script_name;
      include                   fastcgi_params;
      fastcgi_pass              unix:/var/run/php-site_fr.sock;
      fastcgi_index             index.php;
   }
}

Debian : utilisation des cgroups sur un serveur web PHP mutualisé

Les cgroupsgroupes de contrôle – ont pour but de contrôler les ressources systèmes utilisées par un ou plusieurs processus. Les processus sous contrôle sont affectés dans des groupes sur lequels agissent des contrôleurs de ressources. Chaque contrôleur gère un type de ressources :

  • cpuset : allocation CPU (numéro CPU/core CPU).
  • cpuacct :  consommation CPU (nombre de cycles).
  • memory : contrôle de la mémoire vive et de la mémoire swap.
  • devices : contrôle l’accès aux périphériques.
  • blkio : contrôle l’accès aux périphériques de type bloc (ex disque dur).
  • net_cls : contrôle l’accès aux périphériques réseau.

Par défaut, la configuration s’effectue manuellement, ce qui est fastidieux et à réserver en cas d’état de saturation des ressources. Deux démons peuvent ainsi prendre la main pour automatiser la gestion :

  • cgconfig : qui créée la hiérarchie des cgroups.
  • cgrulesengd : qui classe les processus dans les cgroups en fonction de régles spécifiques.

Dans le cadre d’un serveur web, les cgroups sont utiles pour prioritiser les processus du serveur web, de MySQL, PHP (ou tout autre interpréteur), afin de garantir une réactivité du serveur. Ils peuvent également restreindre les ressources CPU de chaque utilisateur afin de garantir un partage équitable des ressources CPU entre chaque processus utilisateur (php, cron, ssh) et éviter une consommation anormale des ressources mémoire et bande passante.

Mon article détaille ainsi la mise en place d’un serveur web mutualisé sous cgroups avec les objectifs suivants :

  • garantir la priorité de toutes les tâches système.
  • limiter les ressources CPU de toutes les tâches des utilisateurs.
  • limiter l’utilisation mémoire vive des tâches utilisateurs et réserver 4 Go pour le système.
  • interdire l’utilisation de la mémoire swap pour les tâches utilisateurs.

Au niveau logiciel, la configuration est la suivante :

  • distribution Debian 6 Squeeze.
  • serveur web Nginx.
  • PHP 5.3.9 en configuration FPM (packages fournis par dotdeb).
  • accès SSH chrooté pour chaque utilisateur.

Chaque utilisateur (client1, client2, etc …) possède son pool de processus PHP attribué, processus qui s’exécutent donc sous son identité. L’ensemble des utilisateurs appartient au groupe secondaire clients. Ainsi, les cgroups vont s’appliquer sur ce groupe secondaire clients. Quant à Nginx, il fait partie automatiquement du cgroup par défaut ; il sera traité et prioritisé comme toute autre tâche système.

Compilation du noyau avec support cgroups

Le noyau fourni avec squeeze n’étant pas configuré pour la gestion des cgroups, il convient d’en compiler un spécifiquement, en veillant à ce que les options suivantes soient identiques. Je précise bien ne pas compiler en module mais en statique :

root@skinner:~# grep -e CONNECTOR -e PROC_EVENTS -e CGROUP /boot/config-2.6.32-bhuisgen
CONFIG_CGROUPS=y
CONFIG_CGROUP_NS=y
CONFIG_CGROUP_FREEZER=y
CONFIG_CGROUP_DEVICE=y
CONFIG_CGROUP_CPUACCT=y
CONFIG_CGROUP_MEM_RES_CTLR=y
CONFIG_CGROUP_MEM_RES_CTLR_SWAP=y
CONFIG_CGROUP_SCHED=y
CONFIG_NET_CLS_CGROUP=y
CONFIG_CONNECTOR=y
CONFIG_PROC_EVENTS=y

Pour la procédure de compilation noyau sous Debian, je vous renvoie à mon article précédent. J’ai également mis en ligne le noyau utilisé pour ce serveur, vous pouvez le télécharger ici.

Une fois le serveur redémarré avec le nouveau kernel, vous pouvez vérifier les contrôleurs de ressources disponibles :

root@skinner:/etc# cat /proc/cgroups
#subsys_name    hierarchy    num_cgroups    enabled
cpuset  0    1    1
ns      0    1    1
cpu     1    3    1
cpuacct 2    2    1
memory  4    3    1
devices 3    2    1
freezer 0    1    1
net_cls 0    1    1

Il reste à installer les démons userland pour gérer les cgroups :

root@skinner:~# apt-get install libcgroup cgroup-bin

Configuration des cgroups

root@skinner:~# more /etc/cgconfig.conf

 

# cgconfig.conf

mount {
   cpu = /mnt/cgroups/cpu;
   cpuacct = /mnt/cgroups/cpuacct;
   devices = /mnt/cgroups/devices;
   memory = /mnt/cgroups/memory;
}

group clients {

   cpu {
      cpu.shares = 512;
   }

   memory {
      memory.memsw.limit_in_bytes = 8G;
      memory.limit_in_bytes = 8G;
   }
}

 

root@skinner:~# more /etc/cgrules.conf

 

# /etc/cgrules.conf

@clients    cpu,memory    clients

Création d’un compte utilisateur

root@skinner:~# groupadd -g 2000 clients
root@skinner:~# groupadd -g 2001 client1
root@skinner:~# useradd -m client1 -p pa$$word -u 2001 -g 2001 -G clients -s /bin/false

 

root@skinner:~# mkdir -p /home/client1/www/{html,lib,logs,tmp}
root@skinner:~# chmod 755 /home/client1
root@skinner:~# chown -R root:root /home/client1
root@skinner:~# chown client1:client1/home/client1/www/html
root@skinner:~# chown client1:client1 /home/client1/www/lib
root@skinner:~# chown client1:client1 /home/client1/www/tmp

 

root@skinner:~# id client1
uid=2001(client1) gid=2001(client1) groups=2001(client1),2000(clients)

Configuration Nginx / PHP

root@skinner:~# more /etc/nginx/sites-available/client1

 

server {
    listen        192.168.1.173:80;
    server_name   client1.my.domain *.client1.my.domain;
    root          /home/client1/www/html/;
    access_log    /home/client1/www/logs/access.log main;
    error_log     /home/client1/www/logs/error.log;
    index         index.html index.php;

    location ~ \.php$ {
        fastcgi_pass  unix:/var/run/php-client1.sock;
        fastcgi_index index.php;
        fastcgi_param SCRIPT_FILENAME /home/client1/www/html$fastcgi_script_name;
        include       fastcgi_params;
    }
}

 

root@skinner:~# more /etc/php5/fpm/pool.d/client1.conf

 

[client1]
listen = /var/run/php-$pool.sock
listen.backlog = -1
listen.owner = www-data
listen.group = www-data
listen.mode = 0600
user = $pool
group = $pool

pm = static
pm.max_children = 4
pm.max_requests = 500
access.log = /home/$pool/www/logs/php-$pool.access.log
access.format = %R - %u %t "%m %r%Q%q" %s %f %{mili}d %{kilo}M %C%%
request_terminate_timeout = 35
request_slowlog_timeout = 15
slowlog = /home/$pool/www/logs/php-$pool.log.slow

php_admin_value[disable_functions] = dl, exec, highlight_file, fsockopen, passthru, pcntl_exec, phpinfo, pclose, popen, system, shell_exec, set_time_limit, show_source
php_admin_value[memory_limit] = 64M
php_admin_value[open_basedir] = /home/$pool/www/html:/home/$pool/www/lib:/home/$pool/www/tmp:/home/$pool/www/awstats
php_admin_value[session.save_path] = /home/$pool/www/tmp
php_admin_value[upload_tmp_dir] = /home/$pool/www/tmp

Lancement des démons

root@skinner:~# /etc/init.d/cgconfig start
root@skinner:~# /etc/init.d/cgred start
root@skinner:~# /etc/init.d/php-fpm

On peut à présent vérifier que les processus PHP de client1 sont bien attribués à notre cgroup clients au niveau des contrôleurs de ressources CPU et mémoire (RAM+swap) :

root@skinner:~# ps -u client1
PID TTY          TIME CMD
19507 ?        00:00:00 php5-fpm
19508 ?        00:00:00 php5-fpm
19509 ?        00:00:00 php5-fpm
19510 ?        00:00:00 php5-fpm
root@skinner:~# cat /proc/19507/cgroup
8:memory:/clients
7:devices:/sysdefault
6:cpuacct:/sysdefault
5:cpu:/clients

Il est également possible de manipuler à chaud les cgroups en parcourant sa hiérarchie, montée sous Debian dans /mnt/cgroups :

root@skinner~# cd /mnt/cgroups
 root@skinner:/mnt/cgroups# ls -l
total 0
drwxr-xr-x 4 root root 0 Jan 16 11:45 cpu
drwxr-xr-x 3 root root 0 Jan 16 11:45 cpuacct
drwxr-xr-x 3 root root 0 Jan 16 11:45 devices
drwxr-xr-x 4 root root 0 Jan 16 11:45 memory
root@skinner:/mnt/cgroups# ls -l cpu
total 0
-r--r--r-- 1 root root 0 Jan 16 11:45 cgroup.procs
drwxrwxr-x 2 root root 0 Jan 16 11:45 clients
-rw-r--r-- 1 root root 0 Jan 16 11:45 cpu.shares
-rw-r--r-- 1 root root 0 Jan 16 11:45 notify_on_release
-rw-r--r-- 1 root root 0 Jan 16 11:45 release_agent
drwxrwxr-x 2 root root 0 Jan 16 11:45 sysdefault
-rw-r--r-- 1 root root 0 Jan 16 11:45 tasks

Il suffit ensuite de faire les commandes echo appropriées selon les besoins.

Les cgroups représentent donc la brique logicielle indispensable à tout serveur afin de partager et limiter les ressources.

Nginx : configuration reverse proxy pour serveur GlassFish

server {
   listen 80;
   server_name shorturl.my.domain;
   root /opt/local/www/;

   # proxy glassfish
   location / {
      # Proxy all requests to Glassfish
      proxy_pass http://127.0.0.1:8080/shorturl/;
      proxy_set_header X-Real-IP $remote_addr;
      proxy_set_header X-Forwarded-For $proxy_add_x_forwarded_for;
      proxy_set_header Host $http_host;

      proxy_cache one;
      proxy_cache_min_uses 1;
      proxy_cache_valid  200 302 1m;
      proxy_cache_valid  404 1m;
      proxy_cache_use_stale error timeout invalid_header http_500 http_502 http_503 http_504;
   }

   # serve static resources directly
   location ~ ^/resources/(components|css|images|javascript?)/(.*)$ {
      alias /opt/local/www/shorturl/$1/$2;
   }

   location ~ ^/favicon.ico$ {
      alias /opt/local/www/shorturl/favicon.ico;
   }
}

Nginx : rewrite rule avec paramètres

Redirection avec conservation des paramètres :

rewrite ^/toto$ http://www.site.fr/tata;

Redirection sans conservation des paramètres :

rewrite ^/toto$ http://www.site.fr/tata?;

Redirection sur paramètre spécifique et sans conservation des paramètres :

if ($args ~ navi=4) {
   rewrite ^/toto$ http://www.site.fr/tata?;
}

./GoAccess : analyseur de log Apache/Nginx temps réel

./GoAccess est un analyseur de log Apache/Nginx qui présente ses résultats à la volée, directement en console. Ce logiciel opensource est disponible sur les différents systèmes UNIX/Linux.

Site officiel : http://goaccess.prosoftcorp.com/

Apache : protection X-Frame-Options

# fix for clickjacking
Header always append X-Frame-Options SAMEORIGIN

Plus d’informations ici.

Apache : autoriser le partage cross-domain des ressources

   <IfModule mod_headers.c>
      Header set Access-Control-Allow-Origin *
   </IfModule>

Source : http://enable-cors.org/

Squid : gestion séparée des logs d’accès

Squid stocke par défaut les accès client dans un unique fichier journal. Ceci est problématique dans le cas d’un reverse-proxy mutualisé car il est nécessaire de générer des statistiques d’accès par site.

Comme toujours avec ce logiciel, la solution réside au niveau des ACL. Ici, il s’agit d’effectuer un test sur le domaine (dstdomain), voire l’URL (url_regex) s’il convient de distinguer au niveau protocole. L’ACL est ensuite à spécifier en dernier argument de l’option access_log afin de limiter les données stockées dans le log. Evidemment, il faut veiller à ce que toutes les options access_log utilisent une ACL sous peine d’avoir un beau catch-all qui va griller le disque et les temps d’accès inutilement.

Je colle ici un exemple de configuration permettant la séparation des logs d’accès de deux sites web (fichier squid.conf) :

acl LOG_SITE1 dstdomain "/etc/squid/log_site1.txt"
acl LOG_SITE2 dstdomain "/etc/squid/log_site2.txt"

logformat combined %>a %ui %un [%tl] "%rm %ru HTTP/%rv" %Hs %<st "%{Referer}>h" "%{User-Agent}>h" %Ss:%Shcache_store_log none

access_log /var/log/squid/site1-access.log combined LOG_SITE1
access_log /var/log/squid/site2-access.log combined LOG_SITE2

Reste ensuite à créer pour chaque site le fichier listant des alias utilisés :

# more /etc/squid/log_site1.txt
www.site1.fr
site1.fr
# more /etc/squid/log_site2.txt
.site2.fr

Bref, c’est simple et performant.

Apache : redirection HTTPS générique

RewriteCond %{HTTPS} off
RewriteRule (.*) https://%{HTTP_HOST}%{REQUEST_URI}

Nginx : redirection HTTPS avec header STS

Ce n’est pas nouveau, donc direction wikipédia si besoin est.

server {
 listen 80;
 server_name     mon.webmail.fr

 # Strict Transport Security
 add_header Strict-Transport-Security max-age=2592000;

 rewrite ^.*$  https://mon.webmail.fr permanent;
}
Haut de page