Formation Evolix

Services HTTP

Apache

Serveur HTTP le plus utilisé, depuis 1996

Installation


# apt install apache2-mpm-itk \
              libapache2-mod-evasive apachetop libwww-perl

# apachectl configtest
    

Fichiers de configuration

/etc/apache2/
├── apache2.conf
├── conf-available
│   └── *.conf
├── conf-enabled
│   └── *.conf -> ../conf-available/*.conf
├── envvars
├── magic
├── mods-available
│   ├── *.conf
│   └── *.load
├── mods-enabled
│   ├── *.conf -> ../mods-available/*.conf
│   └── *.load -> ../mods-available/*.load
├── ports.conf
├── sites-available
│   └── *.conf
└── sites-enabled
    └── *.conf -> ../sites-available/*.conf
    

Des modules à la carte


      # a2enmod rewrite expires headers rewrite cgi
    

Optimisations "Evolix"


      ServerTokens Prod
      Timeout 10
      KeepAliveTimeout 2
      MaxKeepAliveRequests 10
      ServerLimit 250
      #MaxClients 250
      MaxRequestWorkers 250
      StartServers 50
      MinSpareServers 20
      MaxSpareServers 30
      MaxRequestsPerChild 100
      <Directory /home/>
          AllowOverride None
          Require all granted
      </Directory>
      <IfModule mod_ssl.c>
      SSLProtocol all -SSLv2 -SSLv3
      SSLCipherSuite HIGH:MEDIUM:!aNULL:!MD5:!RC4
       </IfModule>
    

Forcer le umask

# grep umask /etc/apache2/envvars
umask 007

VirtualHost

  • Permet de séparer de plusieurs sites sur un même serveur HTTP
  • Séparation par nom de domaine ou par adresses IP

VirtualHost basé sur un nom de domaine


<VirtualHost *:80>
    ServerName www.example.com
    ServerAlias example.com

    DocumentRoot /home/example/www/
    <Directory /home/example/www/>
        Options SymLinksIfOwnerMatch
        AllowOverride AuthConfig Limit FileInfo Indexes
    </Directory>

    AssignUserID www-example example
    MaxClientsVHost 150

    CustomLog /var/log/apache2/access.log vhost_combined
    CustomLog /home/example/log/access.log combined
    ErrorLog  /home/example/log/error.log

    RewriteEngine On
    UseCanonicalName On
    RewriteCond %{HTTP_HOST} !^www.example.com$
    RewriteRule ^/(.*) http://%{SERVER_NAME}/$1 [L,R]
</VirtualHost>
    

Activation du site


# adduser example
# adduser --ingroup example www-example
# mkdir /home/example/{www,log,awstats}
# chown example: /home/example/{www,log,awstats}
# a2ensite example
    

Gestion des droits avec Apache-ITK

  • user/group distincts pour chaque VirtualHost
  • séparation stricte des droits
  • … y compris la lecture
  • … y compris avec PHP

# chmod 750 /home/example
      

Restriction en écriture pour Apache

  • Lecture seule pour Apache, sauf certains répertoires (uploads/, cache/)
  • utilisateur dédié pour l'écriture par Apache : www-example
  • … et pour FTP/SSH/SFTP/SCP/RSYNC : example
  • groupe commun pour tous et droits accordés au groupe
  • pas besoin de chmod, Apache a son umask à 007

# echo "umask 027" >> /etc/profile
# find /home/example -type f -user www-example -exec chmod 660 {} \;
# find /home/example -type d -user www-example -exec chmod 770 {} \;
      

Attention !

Ne jamais forcer les droits récursivement
sur toute l’arborescence.
#NEVER777

Si la restriction en écriture pour Apache est impossible :

  • plus d’utilisateur distinct
  • "AssignUserID example example" élimine 100% des soucis de droits
  • … mais réduction de la sécurité

HTTPS ‑ TLS/SSL

Activation du module SSL pour Apache


# a2enmod ssl
  

Création d'un certificat


# openssl req -newkey rsa:2048 -sha256 -nodes \
    -keyout private.key -out demande.csr
# openssl x509 -req -days 3650 -sha256 -in demande.csr \
    -signkey private.key -out certificate.crt
# mv private.key /etc/ssl/private/
# chown root:ssl-cert /etc/ssl/private/private.key
# chmod 640 /etc/ssl/private/private.key
# mv certificate.crt /etc/ssl/certs
# chown root:root /etc/ssl/certs/certificate.crt
# chmod 644 /etc/ssl/certs/certificate.crt
  

Modification du VirtualHost


<VirtualHost *:80 *:443>
    ServerName secure.example.com
    ServerAlias www.example.com example.com

    SSLEngine on
    SSLProtocol all -SSLv2 -SSLv3
    SSLCertificateKeyFile /etc/ssl/private/private.key
    SSLCertificateFile /etc/ssl/certs/certificate.crt
    # SSLCertificateChainFile /etc/ssl/certs/certificates_chain.pem

    RewriteEngine On
    RewriteCond %{HTTPS} !=on
    RewriteRule ^/(.*) https://%{SERVER_NAME}/$1 [L,R=permanent]
</VirtualHost>
    

logs

Apache propose plusieurs formats de logs

CustomLog log/global_access.log vhost_combined
CustomLog log/access.log combined

SetEnvIf User-Agent "Foo" dontlog
CustomLog log/access.log combined env=!dontlog

ErrorLog  log/error.log

Authentification "HTTP Basic"

Le module mod_auth_basic est disponible par défaut.

    AuthType Basic
    AuthName "Restricted"
    AuthUserFile /foo/.htpasswd
    AuthGroupFile /dev/null
    require valid-user
    

Règles de ré-écriture


RedirectPermanent / http://new.example.com

RedirectMatch ^/(.*)$ http://new.example.com/$1

# GET / --> /sub/
RedirectMatch ^/$ /sub/

RewriteRule ^/(.*) http://new.example.com/$1 [L,R=permanent]

RewriteCond %{REQUEST_URI} !^/foo.txt
RewriteRule ^/(.*) https://%{SERVER_NAME}/$1 [L,R]

# le drapeau NC pour ne pas tenir compte de la casse
RewriteRule ^/FoO.tXt /sub/ [L,R,NC]

# empêcher des requêtes POST sur une URL particulière
RewriteCond %{REQUEST_METHOD} POST
RewriteRule ^/foo.txt [L,F]

mod_evasive

Limite les accès, notamment les dénis de service


<IfModule mod_evasive20.c>
    DOSHashTableSize    3097
    DOSPageCount        5
    DOSSiteCount        30
    DOSPageInterval     3
    DOSSiteInterval     1
    DOSBlockingPeriod   60
    DOSEmailNotify      security@example.com
</IfModule>

Fail2ban

  • recherche de comportements anormaux dans les logs
  • blocage temporaire ou permanent, via firewall

Apachetop

Affiche en direct des stats sur le trafic, d'après les logs.

  $ apachetop -f access.log -T 3600 -q
  

mod_status

Génère une page web résumant l'état d'Apache.

<IfModule mod_status.c>
    ExtendedStatus On
    <Location /server-status-XXXX>
        SetHandler server-status
        Deny from all
        Include ipaddr_whitelist.conf
        Allow from 192.0.2.43
        Allow from 127.0.0.1
    </Location>
</IfModule>
    

Nginx

Serveur web, alternative à Apache

Installation


# apt install nginx

# nginx -t -c /etc/nginx/nginx.conf
  
  

Fichiers de configuration

/etc/nginx/
├── conf.d
├── fastcgi.conf
├── fastcgi_params
├── koi-utf
├── koi-win
├── mime.types
├── nginx.conf
├── proxy_params
├── scgi_params
├── sites-available
│   └── default
├── sites-enabled
│   └── default -> /etc/nginx/sites-available/default
├── snippets
│   ├── fastcgi-php.conf
│   └── snakeoil.conf
├── uwsgi_params
└── win-utf

Optimisations "Evolix"


user www-data;
worker_processes 8;
pid /var/run/nginx.pid;

events {
    use epoll;
    worker_connections 10240;
}

http {
    keepalive_timeout  15;
[…]

# disable Nginx version
server_tokens off;
    

VirtualHost


server {
    listen 80;
    server_name static.example.com assets.example.com;
    access_log  /var/log/nginx/access.log;
    root   /home/static/www;
    location /crossdomain.xml {
        alias   /home/static/www/crossdomain.xml;
    }
    error_page   500 502 503 504  /50x.html;
    location = /50x.html {
        root   /var/www/nginx-default;
    }
    location ~\.(jpeg|jpg|gif|png)$ {
        add_header Cache-Control "public";
        expires 2w;
    }
    location ~\.(js|pdf|css|swf)$ {
        add_header Cache-Control "public";
        expires 3w;
    }
}
    

server {
    listen 443;
    server_name static.example.com assets.example.com;

    ssl on;
    ssl_certificate /etc/ssl/certs/static.example.com.crt;
    ssl_certificate_key /etc/ssl/private/static.example.com.key;
    # add_header Strict-Transport-Security "max-age=31536000;";
}

HAProxy

Proxy et load-balancer TCP/HTTP/HTTPS

Installation


# apt install haproxy

# haproxy -c -f /etc/haproxy/haproxy.cfg
  
  

Configuration minimale


global
    log 127.0.0.1 local5 debug

defaults
    mode     http

listen www
    bind *:80
    balance roundrobin
    option httpchk OPTIONS * HTTP/1.1\r\nHost:\ www.example.com
    stats uri /haproxy-stats
    stats auth foo:bar
    server www00 192.0.2.1:80 maxconn 50 check inter 10s
    server www01 192.0.2.2:80 maxconn 50 check inter 10s
      

Configuration avancée

  • gestion fine des performances
  • multiples IP/domaines
  • différents algorithmes de load-balancing

TLS/SSL

  • terminaison SSL ou transmission transparente
  • multi certificats et SNI
  • agrafage OCSP facilitée

mode TCP


listen memcached 127.0.0.1:11211
    option tcp-check
    server nosql00 192.0.2.3:11211 check
    server nosql01 192.0.2.4:11211 check backup
    

Load-balancing MySQL (simple)


listen mysql 127.0.0.1:3306
    mode tcp
    option mysql-check user haproxy_check
    server sql00 192.0.2.1:3306 check
    

Load-balancing MySQL (avancé)

Si le test de connexion à MySQL ne suffit pas,
on indique un programme pour un test personnalisé
qui indiquera à HAProxy si le backend va bien.

Dashboard

Varnish

Accélérateur web : cache et reverse-proxy

Installation


# apt install varnish

Configuration minimale

Varnish relaie les requêtes vers le port 8080 local.


backend default {
    .host = "127.0.0.1";
    .port = "8080";
}

Logs

Par défaut les logs sont gardés en mémoire (taille fixe) pour les performances.

# varnishstat
# varnishtop -i ReqURL
# varnishlog
# varnishnsca
Filtres possibles

# varnishlog -q 'TxHeader eq MISS' -q "ReqHeader \
             ~ '^Host: example\.com$'" | grep RxURL
# varnishncsa -q "ReqHeader eq 'X-Cache: MISS'"

Syntaxe VCL


sub vcl_recv {
    if (req.http.host == "boutique.example.com") {

        if (req.url ~ "^/" || req.url  ~ "/newsletter" ) {
            unset req.http.cookie;
        }
    }
}

sub vcl_backend_response {
    if (bereq.http.host == "boutique.example.com") {

        if (bereq.url ~ "^/" || bereq.url  ~ "/newsletter" ) {
            unset beresp.http.Set-Cookie;
            set beresp.ttl = 1h;
            return (deliver);
        }
    }
}

PHP

Langage de programmation très adapté au web.

Versions de PHP

  • PHP 3 (1997)
  • PHP 4 (2000)
  • PHP 5 (2004)
  • PHP 5.4 (Debian 7)
  • PHP 5.6 (Debian 8)
  • PHP 7 (Debian 9)

Installation de PHP5


# apt install php5 libapache2-mod-php5 php5-gd php5-imap php5-ldap \
              php5-mcrypt php5-mhash php5-mysql php5-pgsql \
              php-gettext librsvg2-bin
$ php -v

PHP 5.6.30-0+deb8u1 (cli) (built: Feb  8 2017 08:50:21)
Copyright (c) 1997-2016 The PHP Group
Zend Engine v2.6.0, Copyright (c) 1998-2016 Zend Technologies
    with Zend OPcache v7.0.6-dev, Copyright (c) 1999-2016, by Zend Technologies

# apt install php5-fpm

php.ini


  short_open_tags = Off
  disable_functions = exec, shell-exec, system, passthru, putenv, popen
  expose_php = Off
  display_errors = Off
  log_errors = On
  allow_url_fopen = Off
  memory_limit = 128M
  max_execution_time = 10
  open_basedir = /home
  

Délégation dans VirtualHost Apache


#php_admin_flag engine off
#AddType text/html .html
#php_admin_flag safe_mode off
#php_admin_value safe_mode_exec_dir /usr/bin
#php_admin_flag display_errors on
#php_flag short_open_tag on
#php_flag register_globals on
#php_admin_value upload_tmp_dir "/home/bloginfo/tmp/
php_admin_value sendmail_path "/usr/sbin/sendmail -t -i -f www-bloginfo"
php_admin_value error_log "/home/bloginfo/log/php.log"
php_admin_value memory_limit "64M"

fpm/php-fpm.conf


[global]
pid = /run/php5-fpm.pid
error_log = /var/log/php5-fpm.log

fpm/pool.d/www.conf


[www]
listen = /var/run/php5-fpm.sock
;listen = 127.0.0.1:9000
user = www-data
group = www-data
pm = dynamic

php_admin_value[sendmail_path] = /usr/sbin/sendmail -t -i -f return-path@example.com
php_flag[display_errors] = off
php_admin_value[error_log] = /var/log/fpm-php.www.log
php_admin_flag[log_errors] = on
php_admin_value[memory_limit] = 32M

fpm/pool.d/www.conf


pm = dynamic
pm.max_children = 100
pm.start_servers = 50
pm.min_spare_servers = 20
pm.max_spare_servers = 30
pm.max_requests = 100
OU

pm = ondemand
pm.max_children = 100
pm.process_idle_timeout = 10s

fpm/pool.d/www.conf


slowlog = log/$pool.log.slow
request_slowlog_timeout = 5s

pm.status_path = /fpm-status
request_terminate_timeout = 60s
chroot = /home/foo
access.log = log/$pool.access.log

Avec Apache :


# a2enmod proxy_fcgi
  

DocumentRoot /home/foo/www/
# ProxyPassMatch "^/(.*\.php(/.*)?)$" "fcgi://127.0.0.1:9000//home/foo/www/$1"
ProxyPassMatch "^/(.*\.php(/.*)?)$" "unix:/var/run/php5-fpm.sock|fcgi://localhost/home/foo/www/"
  

Avec Nginx


server {
    listen 80;
    server_name www.example.com example.com;
    root /home/foo/www;
    index index.php;

    location ~ \.php$ {
        try_files $uri =404;
        #fastcgi_pass   127.0.0.1:9000;
        fastcgi_pass   unix:/var/run/php5-fpm.sock;
        fastcgi_param SCRIPT_FILENAME /home/foo/www$fastcgi_script_name;
        include fastcgi_params;
    }
}
  

$ echo "" > /var/www/info.php

Let's Encrypt

  • Autorité de certification
  • propose des certificats X-509
  • DV – Domain Validation

Principes de base

  • gratuit
  • automatique
  • sécurisé
  • transparent
  • ouvert
  • cooperatif

Composants

  • Protocole ACME (standard IETF en janvier 2018)
  • Boulder : serveur ACME
  • Certbot : client ACME pour gérer des certificats
  • des dizaines d'autres clients tiers

Installation de certbot


  # apt install certbot
  
  • création du compte Let's Encrypt
  • création de certificats
  • auto-configuration du serveur web
  • renouvellement/révocation de certificats

3 Challenges pour la validation

  • HTTP – ressource signée
  • DNS – enregistrement DNS signé
  • TLS-SNI – certificat TLS contenant une signature

Particularités

  • Durée de vie de 90 jours
  • Entièrement automatisé
  • … donc seulement DV et pas OV ou EV