Aller au contenu

Installer son Serveur Web : NGINX, PHP-FPM et MariaDB

On va voir comment installer et configurer correctement NGINX, PHP-FPM et MariaDB en ajoutant des sources pour obtenir des versions à jour. Pour les sources de nginx, remplacer codename par sa distribution.

Sites officiels Liens utiles
NGINX Doc NGINX
PHP Manuel PHP
MariaDB Documentation MariaDB

Installer et configurer NGINX

Tout d'abord, avant de vouloir installer le serveur web NGINX, il faut déjà ajouter une source.

└─# apt-cache policy nginx
nginx:
  Installé : 1.14.2-2+deb10u4
  Candidat : 1.14.2-2+deb10u4
 Table de version :
     1.14.2-2+deb10u4 500
        500 http://deb.debian.org/debian buster/main amd64 Packages
        500 http://security.debian.org/debian-security buster/updates/main amd64 Packages

Si on utilise les repositories de base de Debian Buster, ceux-ci installent la version 1.14.2 de NGINX. Actuellement on en est à la 1.21.2. C'est pour ça qu'on ajoute les repositories du site officiel pour obtenir une version à jour.

Tout d'abord, on commence par ajouter le depot NGINX à Debian

$ echo "deb [signed-by=/usr/share/keyrings/nginx-archive-keyring.gpg] '
http://nginx.org/packages/mainline/debian `lsb_release -cs` nginx" '
    | sudo tee /etc/apt/sources.list.d/nginx.list

Il faut également ajouter la GPG Key à son Debian, sans quoi il nous affichera que la source n'est pas certifiée

$ curl https://nginx.org/keys/nginx_signing.key | gpg --dearmor '
    | sudo tee /usr/share/keyrings/nginx-archive-keyring.gpg >/dev/null

Afin d'être sûr qu'on va utiliser les repository Debian, on ajoute un Pinning :

echo -e "Package: *\nPin: origin nginx.org\nPin: release o=nginx\nPin-Priority: 900\n" | sudo tee /etc/apt/preferences.d/99nginx

Et enfin, on effectue un apt-get update pour mettre à jour nos packets disponibles.

Si tout marche bien, voici ce qu'on devrait obtenir avec apt-cache policy nginx :

    └─# apt-cache policy nginx
    nginx:
      Installé : (aucun)
      Candidat : 1.21.1-1~buster

Si tout se passe comme il faut, on peut lancer l'installation

└─# apt-get -y install nginx nginx-extras nginx-doc

Voici les options de compilations du paquet nginx

NGINX Default Compilation Options
--prefix=/etc/nginx
--sbin-path=/usr/sbin/nginx
--conf-path=/etc/nginx/nginx.conf
--error-log-path=/var/log/nginx/error.log
--http-log-path=/var/log/nginx/access.log
--pid-path=/var/run/nginx.pid
--lock-path=/var/run/nginx.lock
--http-client-body-temp-path=/var/cache/nginx/client_temp
--http-proxy-temp-path=/var/cache/nginx/proxy_temp
--http-fastcgi-temp-path=/var/cache/nginx/fastcgi_temp
--http-uwsgi-temp-path=/var/cache/nginx/uwsgi_temp
--http-scgi-temp-path=/var/cache/nginx/scgi_temp
--user=nginx
--group=nginx
--with-http_ssl_module --with-http_realip_module --with-http_addition_module --with-http_sub_module
--with-http_dav_module --with-http_flv_module --with-http_mp4_module --with-http_gunzip_module
--with-http_gzip_static_module --with-http_random_index_module --with-http_secure_link_module --with-http_stub_status_module
--with-http_auth_request_module
--with-mail
--with-mail_ssl_module
--with-file-aio
--with-http_v2_module
--with-ipv6

L'option --with-ipv6 est nécessaire pour supporter IPv6. Voir Configurer nginx pour utiliser IPv6 pour la configuration détaillée.

Désormais, nginx est quasiment prêt à être utilisé, il reste à le configurer.

Voici une configuration personnelle :

File: /etc/nginx/nginx.conf
user www-data;
worker_processes auto;
worker_rlimit_nofile 65536;
#worker_cpu_affinity 00000010 00000100 00001000 00010000;
pid /run/nginx.pid;

include /etc/nginx/modules-enabled/*.conf;

events {
    worker_connections 16384;
    # multi_accept on;
}

http {

    ##
    # Basic Settings
    ##

    sendfile on;
    tcp_nopush on;
    tcp_nodelay on;

    resolver 127.0.0.1 1.1.1.1;
    ignore_invalid_headers on;

    keepalive_timeout 65;
    types_hash_max_size 2048;

    server_tokens off;
    more_set_headers Server: Jeremy Server;
    more_set_headers Contact: wiki[at]jdelgado[dot]fr;

    # server_names_hash_bucket_size 64;
    # server_name_in_redirect off;

    include /etc/nginx/mime.types;
    default_type application/octet-stream;

    ##
    # SSL Settings
    ##

    ssl_protocols TLSv1 TLSv1.1 TLSv1.2 TLSv1.3; # Dropping SSLv3, ref: POODLE
    ssl_prefer_server_ciphers on;

    ##
    # Logging Settings
    ##

    access_log /var/log/nginx/access.log;
    error_log /var/log/nginx/error.log;

    ##
    # Gzip Settings
    ##

    gzip on;

    gzip_vary on;
    gzip_proxied any;
    gzip_comp_level 4;
    # gzip_buffers 16 8k;
    # gzip_http_version 1.1;
    # gzip_types text/plain text/css application/json application/javascript text/xml application/xml application/xml+rss text/javascript;
    gzip_types text/plain text/css application/json application/ld+json application/x-javascript text/xml application/xml application/xml+rss text/javascript application/xml+xhtml application/javascript application/vnd.ms-fontobject font/ttf font/opentype image/svg+xml image/x-icon;

    ##
    # Virtual Host Configs
    ##

    include /etc/nginx/conf.d/*.conf;
    include /etc/nginx/sites-enabled/*;
}

Évidemment, ce fichier n'est pas à recopier tel quel, mais il y a tout de même certains points importants à conserver :

  • user qui sera l'utilisateur qui exécutera les instances nginx
  • worker_processes qui définira combien d'instances seront exécutées en simultanées (ce nombre doit correspondre au nombre de coeurs logiques du CPU). La commande nproc donne cette info. La valeur auto est censée définir le bon nombre de workers automatiquement
  • include qui permet d'inclure différents éléments de configuration à nginx.conf pour le rendre plus clair. Les sites se trouvent dans sites-enabled et certains éléments de configuration dans conf.d/static/
  • server_tokens une valeur très importante, celle-ci doit être mise à off. Cette valeur évite à nginx de montrer des éléments importants tel que son numéro de version. Ces éléments peuvent être utilisés pour exploiter des failles sur nginx. Voir Être encore plus safe en customisant son header Server NGINX pour plus de détails.
  • ignore_invalid_headers est également une directive assez intéréssante. Si des bots tentent de se connecter avec un header incorrect, nginx leur retourne une erreur 404.
  • resolver permet de spécifier les DNS utilisés dans les logs pour résoudre les noms de domaines

La directive more_set_headers permet de ne pas dévoiler son serveur web, et n'est disponible que via le package nginx-extras. Voir Être encore plus safe en customisant son header Server NGINX.

On inclut également différents fichiers :

File: /etc/nginx/conf.d/filecache.conf
##
# File Cache
##
open_file_cache          max=10000 inactive=20s;
open_file_cache_valid    60s;
open_file_cache_min_uses 2;
open_file_cache_errors   on;
File: /etc/nginx/conf.d/gzip.conf
###
# GZip Settings
###
gzip on;
gzip_buffers 16 8k;
gzip_comp_level 9;
gzip_disable "msie6";
gzip_min_length 20;
gzip_proxied any;
gzip_types text/plain
           text/css
           text/xml
           text/javascript
           application/json
           application/x-javascript
           application/javascript
           application/xml
           application/xml+rss
gzip_vary on;

Ce fichier est assez important, il permet d'activer la compression gzip, ce qui signifie concrètement un gain de vitesse sur votre site internet.

  • gzip permet d'activer la compression gzip
  • gzip_buffers permet de spécifier le nombre de buffers qui vont être utilisés, ainsi que leur taille
  • gzip_comp_level spécifie l'agressivité de la compression gzip. Plus la valeur est forte (max 9), plus le CPU est sollicité — 4 est un bon compromis.
  • gzip_disable permet de désactiver la compression GZip selon l'User-Agent (par exemple, ici on désactive la compression gzip pour IE4 à IE6)
  • gzip_min_length spécifie la longueur minimale d'un élément qui doit être gzippé. Il dépend du header Content-Length
  • gzip_proxied spécifie les éléments qui doivent être gzippés lorsque nginx agit comme reverse-proxy
  • gzip_types est également une autre ligne importante. C'est ici qu'on spécifie les MIME-Types des différents éléments qui vont être gzippés
  • gzip_vary indique si un ajout va être effectué dans le header si le fichier a été gzippé
File: /etc/nginx/snippets/ssl.conf
###
# SSL Settings
###

# Ciphers for OpenSSL 1.1.1d (Bullseye)
ssl_ciphers ECDHE-ECDSA-CHACHA20-POLY1305:ECDHE-RSA-CHACHA20-POLY1305:ECDH+AESGCM:DH+AESGCM:ECDH+AES256:DH+AES256:ECDH+AES128:DHE-RSA-CHACHA20-POLY1305:DH+AES:RSA+AESGCM:RSA+AES:!aNULL:!MD5:!DSS;

ssl_prefer_server_ciphers off;
ssl_dhparam /etc/nginx/ssl/dhparam.pem;

ssl_prefer_server_ciphers  on;
ssl_session_cache    shared:SSL:64m; # a 1mb cache can hold about 4000 sessions, so we can hold 40000 sessions
ssl_session_timeout  12h;
ssl_session_tickets  off;

add_header Strict-Transport-Security "max-age=15768000;";
add_header X-Frame-Options SAMEORIGIN;
add_header X-Content-Type-Options nosniff;
add_header X-XSS-Protection "1; mode=block";
add_header Referrer-Policy "no-referrer";

ssl_certificate /etc/nginx/ssl/server.crt;
ssl_certificate_key /etc/nginx/ssl/server.key;

Le fichier ssl.conf est à inclure seulement si l'on souhaite du SSL sur ses sites web. Voir Forcer le SSL sous NGINX pour les directives de redirection.

Certaines lignes sont importantes tels que ssl_ciphers qui permet de sélectionner quels ciphers seront utilisés pour coder l'échange entre son serveur web, et son client. Cette ligne est extrêmement importante car il y a actuellement de nombreux ciphers utilisés mais qui sont totalement dépassés. ssl_protocols permet lui également de ne pas passés par des protocoles complètement troués. Cependant, il faut faire attention avec ces 2 lignes, car en effet, elles peuvent provoquer des erreurs de sécurité côté navigateur, voir carrément entrainer un refus du navigateur. Nous activons également le protocole HSTS (Plus d'informations ici)

Pour avoir une bonne cipher list et de bons paramètres SSL, voir le Wiki Mozilla.

La configuration CSP (Content Security Policy) n'est pas couverte ici — c'est un protocole délicat à mettre en place, voir content-security-policy.com.

Voici désormais des snippets utiles pour ses différents blocks nginx :

File: /etc/nginx/snippets/protect.conf
###
# Basic File Protect
###

# Disallow download of hidden files
location ~* (?:^|/)'. {
    deny all;
}

# Disallow download of these extensions
location ~* (?:'.(?:bak|conf.*|sql|fla|psd|ini|log|sh|inc|swp|dist)|~)$ {
    deny all;
}

Ce fichier nous permet d'éviter que des fichiers de configuration ou autres soient accessible par tout le monde. Il s'agit d'un fichier générique qui s'adapte au plus grand nombre de services, évidemment, il se peut que certains fichiers/dossiers ne soient pas protégés, dans ces cas-là, il faut les ajouter manuellement.

Snippets

Snippets utiles pour les vhosts (snippets/letsencrypt.conf) :

File: /etc/nginx/snippets/letsencrypt.conf
location ^~ /.well-known/acme-challenge/ {
    satisfy any;
    allow all;

    access_log /var/log/nginx/certbot.log;

    root /var/www/letsencrypt;
}

Installer et configurer PHP7-FPM

Commande à adapter selon les modules souhaités. Généralement suffisant pour 99% des installations. Pour installer une version spécifique de PHP, voir Installer une version custom de PHP:

apt-get -y install php-common php8.2 php8.2-bz2 php8.2-cli php8.2-common php8.2-curl php8.2-fpm php8.2-gd php8.2-geoip php8.2-gmp php8.2-igbinary php8.2-imagick php8.2-intl php8.2-json php8.2-mbstring php8.2-mcrypt php8.2-memcached php8.2-msgpack php8.2-mysql php8.2-opcache php8.2-readline php8.2-sqlite3 php8.2-xml php8.2-xmlrpc php8.2-zip

La configuration de base de PHP-FPM se situe dans /etc/php/8.2/fpm/ et ses sous-répertoires (adapter 8.2 à la version installée).

Éditer le fichier php.ini :

  • expose_php : Désactivation afin de ne pas exposer la version de PH
  • upload_max_filesize : Modification de la taille maximale des fichiers qu'on peut upload avec PHP
  • post_max_size : Va avec la directive upload_max_filesize et doit être supérieur à cette dernière
  • max_file_uploads : Nombre de fichiers qu'on peut upload en parallèle. Par défaut à 20, peut suffir dans une majorité des cas

Petit customisation de la. configuration afin d'optimiser les performances. Il faut pour la plupart des CMS/Framework adapter les valeurs de l'OPcache. Pour WordPress, voici des valeurs adéquates :

opcache.memory_consumption = 128M
opcache.interned_strings_buffer=16
opcache.max_accelerated_files=100000
opcache.fast_shutdown=1

Symfony fournit ses propres recommandations pour la configuration de l'OPcache. La variable opcache.max_accelerated_files peut être facilement calculée :

└─# find . -name "*.php" |wc -l
5165

Pour cet exemple, 10000 fichiers sont largement suffisants. Aucune astuce n'existe pour calculer opcache.memory_consumption — il faut surveiller le monitoring.

Installer et configurer MariaDB

On met à jour les paquets disponibles :

apt-get update

Et enfin, on vérifie que la Candidate Version est la bonne :

apt-cache policy mariadb-server

Voilà le résultat attendu :

$ apt-cache policy mariadb-server
mariadb-server:
  Installé : (aucun)
  Candidat : 1:10.3.29-0+deb10u1
 Table de version :
 *** 1:10.3.29-0+deb10u1 500
        500 http://apt.daevel.fr/debian buster/main amd64 Packages
        100 /var/lib/dpkg/status

Si tout se passe comme il faut, on lance l'installation du serveur SQL

apt-get install mariadb-server

Pendant l'installation de mariadb-server, une fenêtre demande de spécifier un password.

Danger

Cette fenêtre définit le root password MariaDB. Utiliser un mot de passe solide — tous les sites hébergés sont exposés si ce mot de passe est faible ou vide.

Et on finit par le script made in MariaDB pour sécuriser le tout

mysql_secure_installation

Voir aussi