Attention, cet article a plus d'une année d'ancienneté. Il est possible que les informations présentées ne soient plus à jour, spécialement dans le cadre d'un article technique.
Bonjour à tous,
Mise à jour de l’article pour monter son serveur Web avec un Debian 10.
Il m’a fallu un moment pour sortir cet article, car on va vraiment s’occuper de la partie serveur web, on ne verra plus la partie sécurisation du serveur directement.
Aussi, fini les sources externes, nous n’allons utiliser que les repository Debian.
Introduction
L’idée, c’est de partir sur un système simple et stable (Debian donc), pour y installer les briques d’un serveur web performant et sécurisé (HTTP2, TLS 1.2 et 1.3 avec les best practices).
Et vu qu’un serveur web ne sert à rien sans application, on va mettre un WordPress (qui reste utilisé par plus d’un tiers du web, donc on va mettre un truc qui intéressera le plus grand monde pour l’exemple).
Voici les briques logicielles que nous allons utiliser :
- Serveur Web : NGINX
- Serveur de base de données : MariaDB
- Moteur PHP : FastCGI Process Manager (FPM) avec gouverneur statique (on en parlera de l’optimisation de FPM, mais pas maintenant)
Ce n’est pas tout, pour accélérer tout cela on va également utiliser deux systèmes de cache :
- Redis pour MariaDB avec intégration PHP
- OPcache en interne dans PHP-FPM
Résultat souhaité
On se base sur deux sites ici, SSL Labs et Security Headers.
- SSL Labs : A+
- Security Headers : A
Installation
Dans cette première partie, on va voir l’installation des packages nécessaires. On installe Nginx, MariaDB, PHP 7.3 et Redis avec cette simple commande :
apt install curl git unzip imagemagick haveged mariadb-client mariadb-server nginx-extras php-common php-pear php-redis redis php-zip php7.3-cli php7.3-common php7.3-curl php7.3-dev php7.3-fpm php7.3-gd php7.3-imap php7.3-intl php7.3-json php7.3-mbstring php7.3-mysql php7.3-opcache php7.3-pspell php7.3-readline php7.3-recode php7.3-snmp php7.3-tidy php7.3-xml php7.3-zip
Ensuite, on récupère Let’s Encrypt pour générer les certificats SSL par la suite :
cd /etc git clone https://github.com/letsencrypt/letsencrypt cd letsencrypt ./letsencrypt-auto --help
Configuration
On va configurer un par un les logiciels du serveur maintenant.
NGINX
On va commencer par mettre une configuration qui va bien et qui utilise le module headers-more.
cd /etc/nginx/ rm nginx.conf && wget https://raw.githubusercontent.com/stylersnico/nginx-secure-config/master/nginx.conf-debian-extras && mv nginx.conf-debian-extras nginx.conf
Vous pouvez ouvrir la configuration et adapter les workers selon le nombre de coeurs sur votre serveur. Vous pouvez également faire le tour de toutes les best practices qui sont déjà intégrées.
On reviendra sur Nginx après, redémarrez le service en attendant :
systemctl restart nginx
MariaDB / MySQL
Rien de spécial ici, lancez la commande suivante pour sécuriser l’installation :
mysql_secure_installation
Ouvrez maintenant le fichier de configuration et ajoutez cela dans la partie [mysqld] :
nano /etc/mysql/mariadb.conf.d/50-server.cnf
# # * Fine Tuning # max_connections = 50 connect_timeout = 5 wait_timeout = 600 max_allowed_packet = 16M thread_cache_size = 128 sort_buffer_size = 4M bulk_insert_buffer_size = 16M tmp_table_size = 32M max_heap_table_size = 32M # # * Query Cache Configuration # # Cache only tiny result sets, so we can fit more in the query cache. query_cache_limit = 512K query_cache_size = 32M
On reviendra également sur MariaDB après pour faire la base de données, en attendant, redémarrez le service :
systemctl restart mysql
PHP
Créez le répertoire des sockets avec la commande suivante :
mkdir -p /var/lib/php7.3-fpm/
Ouvrez la configuration de PHP et ajoutez-y les paramètres de cache ainsi que la TimeZone :
nano /etc/php/7.3/fpm/php.ini
opcache.enable=1 opcache.enable_cli=1 opcache.interned_strings_buffer=8 opcache.max_accelerated_files=10000 opcache.memory_consumption=128 opcache.save_comments=1 opcache.revalidate_freq=1 date.timezone = Europe/Paris session.cookie_httponly = True max_execution_time = 300 max_input_vars = 1740 post_max_size=100M upload_max_filesize=100M
Redémarrez PHP avec la commande suivante :
systemctl restart php7.3-fpm
Redis
Ouvrez le fichier de configuration de Redis et modifier les variables suivantes (pour configurer la taille du cache et l’expiration du cache le plus ancien) :
nano /etc/redis/redis.conf
maxmemory 256mb maxmemory-policy allkeys-lru
Redémarrez ensuite redis :
systemctl restart redis
Installation d’un blog WordPress
Dans cette partie, on va voir comment mettre à profit la base de serveur web que l’on vient d’installer afin d’y installer un des systèmes de gestion de contenu les plus utilisés.
Supprimez déjà les fichiers de configuration par défaut :
rm /etc/nginx/sites-enabled/default rm /etc/php/7.3/fpm/pool.d/www.conf
Téléchargement de WordPress
Téléchargez et installez la dernière version de WordPress sur votre serveur :
cd /var/www/ wget https://wordpress.org/latest.zip && unzip latest.zip && rm latest.zip
Maintenant, créez l’utilisateur pour wordpress :
adduser wordpress
Et ajoutez-lui les droits sur le site :
chown -R wordpress:www-data /var/www/wordpress
Ajoutez ensuite cet utilisateur dans le groupe www-data :
adduser wordpress www-data
Création du fichier de configuration NGINX
Créez le vhost avec la commande suivante :
nano /etc/nginx/sites-enabled/wordpress.vhost
Et copiez-y ceci :
server { listen 80; server_name myblog.tap.ovh; root /var/www/wordpress/; location /.well-known/acme-challenge { alias /var/www/wordpress/.well-known/acme-challenge/; } index index.php; }
Création du fichier de configuration PHP
Créez le pool fpm avec la commande suivante :
nano /etc/php/7.3/fpm/pool.d/wordpress.conf
Et copiez-y ceci :
[wordpress] listen = /var/lib/php7.3-fpm/wordpress.sock listen.owner = wordpress listen.group = www-data listen.mode = 0660 user = wordpress group = www-data pm = static pm.max_children = 15 chdir = / env[HOSTNAME] = $HOSTNAME env[PATH] = /usr/local/sbin:/usr/local/bin:/usr/sbin:/usr/bin:/sbin:/bin
Redémarrez les services avec la commande suivante :
systemctl restart nginx && systemctl restart php7.3-fpm
Création de la base de données
Connectez-vous en root avec la commande suivante :
mysql -u root -p
Créez la base de données pour WordPress :
CREATE DATABASE wordpress;
Créez l’utilisateur :
CREATE USER 'wordpress'@'localhost' IDENTIFIED BY 'password';
Donnez les droits à l’utilisateur sur la base de données :
GRANT ALL PRIVILEGES ON wordpress.* TO 'wordpress'@'localhost';
Appliquez les droits et sortez :
FLUSH PRIVILEGES; exit
Mise en place du certificat Let’s Encrypt
Maintenant, on va installer un certificat ECDSA pour le blog WordPress.
Créez les dossiers nécessaires avec les commandes suivantes :
mkdir /etc/letsencrypt/live-ecdsa/ mkdir /etc/letsencrypt/live-ecdsa/myblog.tap.ovh cd /etc/letsencrypt/live-ecdsa/myblog.tap.ovh mkdir letmp
Maintenant, créez la clé privée pour votre certificat :
openssl ecparam -genkey -name secp384r1 > privkey-p384.pem
Maintenant, créez un CSR, indiquez votre domaine correctement :
openssl req -new -sha256 -key privkey-p384.pem -subj "/CN=myblog.tap.ovh" -reqexts SAN -config <(cat /etc/ssl/openssl.cnf <(printf "[SAN]\nsubjectAltName=DNS:myblog.tap.ovh")) -outform der -out csr-p384.der
Rendez-vous dans le dossier temporaire « letmp » et créez votre certificat avec Let’s Encrypt :
cd letmp /etc/letsencrypt/letsencrypt-auto certonly -a webroot --email mail@changeca.com --webroot-path /var/www/wordpress/ --csr /etc/letsencrypt/live-ecdsa/myblog.tap.ovh/csr-p384.der --renew-by-default --agree-tos cat 0001* > /etc/letsencrypt/live-ecdsa/myblog.tap.ovh/chain.pem
Si l’opération réussie, vous devrez juste configurer le certificat ECDSA dans votre vhost nginx :
ssl_certificate /etc/letsencrypt/live-ecdsa/myblog.tap.ovh/chain.pem; ssl_certificate_key /etc/letsencrypt/live-ecdsa/myblog.tap.ovh/privkey-p384.pem;
Éditez votre vhost nginx pour rajouter les informations nécessaires :
server { listen 80; listen 443 ssl http2; ssl_certificate /etc/letsencrypt/live-ecdsa/myblog.tap.ovh/chain.pem; ssl_certificate_key /etc/letsencrypt/live-ecdsa/myblog.tap.ovh/privkey-p384.pem; if ($scheme != "https") { rewrite ^ https://$http_host$request_uri? permanent; } server_name abyssproject.net; root /var/www/wordpress/; location /.well-known/acme-challenge { alias /var/www/wordpress/.well-known/acme-challenge/; } index index.php; location = /xmlrpc.php { deny all; } location = /favicon.ico { log_not_found off; access_log off; } location = /robots.txt { allow all; log_not_found off; access_log off; } location ~ \.php$ { try_files /e1d4ea2d073f20faebaf9539ddde872c.htm @php; } location @php { try_files $uri =404; include /etc/nginx/fastcgi_params; fastcgi_pass unix:/var/lib/php7.3-fpm/wordpress.sock; fastcgi_index index.php; fastcgi_param SCRIPT_FILENAME $document_root$fastcgi_script_name; fastcgi_intercept_errors on; } location ~ ^/(status|ping)$ { access_log off; deny all; } location ~* \.(?:jpg|jpeg|gif|png|ico|cur|gz|svg|svgz|mp4|ogg|ogv|webm|htc|css|js|woff|woff2|webp)$ { expires max; add_header Pragma public; add_header Cache-Control "public, must-revalidate, proxy-revalidate"; } location / { try_files $uri $uri/ /index.php?$args; } }
Redémarrez ensuite NGINX et accédez à l’URL du blog pour l’installer :
https://myblog.tap.ovh/
Configuration du cache Redis
Suivez l’installateur WordPress, la première chose à faire ensuite, c’est de configurer ces deux lignes dans votre fichier de configuration WordPress :
nano /var/www/wordpress/wp-config.php
define('WP_CACHE', true); define('WP_CACHE_KEY_SALT', 'myblog.tap.ovh');
Ensuite, installez et activez l’extension Redis Object Cache.
Une fois que c’est fait, vérifiez que Redis marche bien avec la commande suivante :
redis-cli monitor
Vous devriez voir le cache répondre en naviguant sur votre site :
Validation des résultats
Sur SSL Labs d’abord :
Et sur SecurityHeaders :
Et voilà, c’est déjà pas mal 🙂
Si vous souhaitez aller plus loin, vous pouvez regarder la mise en place des images au format WebP : https://www.abyssproject.net/2020/05/mettre-en-place-les-images-au-format-webp-sur-son-site-avec-nginx/
Bonjour,
Franchement, j’ai toujours été refroidi par l’installation de WordPress sur mon VPS :
-« Complexité » de la stack
-Maintenance
-Sécurité
Et partir sur un hébergement mutualisé cela me plait moyennement pour diverses raisons, mais avec ton article ça va me faire réfléchir !
Après il y a quand même toute la partie autour de la sécurité WordPress à gérer qui me semble un peu être un « enfer »…
Je suis preneur de ton retour d’expérience là dessus !
PS: Depuis tu es passé sous PHP8, si oui tu as noté des « breaking changes » ou autre ?
Bonjour,
Il n’y a aucune complexité dans wordpress ni dans la gestion de sa sécurité.
Mises à jour automatiques + bonne sécurisation du serveur + backup au cas où, je n’ai jamais eu un problème en 10 ans.
PHP 8 n’as rien cassé sous wordpress.
Bonjour je rejoins le sujet de marty car moi aussi j’ai des problème avec l’installation de letsencrypt quand je l’installe il me dit que certbot-auto n’ai pas supporter par mon système .du coup puis je quel distribution utilisez vous ? afin que ceux-lui ci soit compatible .
Cordialement
Bonjour Nicolas, merci pour ce tuto très très précis. Mais si je poste, c’est que j ‘ai un souci. Je vous mets dans l’environnement, je souhaite faire un site vitrine avec wordpress et autohebergé (via free et leur proposition de Vm). c’est un test car certains me diront que cela n’est pas bien….l’autohébergement! enfin j’ai une erreur dans le dossier temporaire « letmp » en créant le certificat avec Let’s Encrypt. l’argument cat 0001* n’est pas reconnu. donc pouvez-vous me préciser à quoi correspond cette syntax (j’aime bien comprendre quand je le peux). mais du coup je suis coincè à… Voir plus »
Bonjour,
Est-ce que tu es sûr que l’obtention du certificat via Let’s Encrypt est réussie ?
Merci pour ce tuto, il va m’être utile, en ce moment je déploie pas mal de wordpress pour des clients 🙂
Parfait, tu pourras me faire livrer des bières quand ils t’auront payé 😀
Haha aucun soucis, entre ancien élèves de collonges pas de soucis 😀