Aujourd’hui, petit tutoriel pour déployer une instance WordPress sur un serveur Nginx / PHP 7.4 FPM, en activant le SSL (Let’s Encrypt) et quelques plugins de base, très utiles : le tout en utilisant WP CLI, les outils en ligne de commande pour la gestion du CMS.

creation-web-bretagne-wpcli-wordpress-nginx

Prérequis

Pour procéder à cette installation, il vous faudra au préalable :

  • Un serveur dédié Online.net ou une petite instance Scaleway.
  • Un nom de domaine pointant sur l’IP de votre instance

Préparation du serveur

Nous allons préparer le serveur, fraichement installé avec la distribution de votre choix. Nous utiliserons dans cet article une instance Scaleway Baremetal C1 dont vous retrouverez les tarifs ici.

instance-scaleway-baremetal-wordpress-creation-web-bretagne-dedicated-vps

Nous allons mettre à jour la distribution :

apt update && apt upgrade -y

Installation de Nginx

apt install nginx-extras

Installation des paquets PHP

Nous utiliserons ici les repos Ondrej pour récupérer les paquets PHP :

apt install software-properties-common
add-apt-repository ppa:ondrej/php
apt update

A ce stade, notre VPS est équipé des repos Ondrej pour l’installation des dernières version de PHP. Procédons désormais à l’installation de PHP 7.4 FPM ainsi que toutes les extensions nécessaires :

apt install php7.4 php7.4-bcmath php7.4-cli php7.4-common php7.4-curl php7.4-fpm php7.4-gd php7.4-intl php7.4-json php7.4-mbstring php7.4-mysql php7.4-opcache php7.4-readline php7.4-soap php7.4-sqlite3 php7.4-xml php7.4-xmlrpc php7.4-xsl php7.4-zip redis php-redis php-geoip libnginx-mod-http-geoip php-mysql php-imap php-common

Installation de Mariadb

Pour la base de données, nous utiliserons MariaDB :

apt install mariadb-client mariadb-common mariadb-server

Optimisation et sécurité

MYSQL Secure Installation

Nous passons désormais sur l’étape d’optimisation et sécurisation du serveur. Pour démarrer, nous allons configurer mariadb pour refuser les connexion distantes, refuser le login via root. Dans l’invite de commande, tapez :

mysql_secure_installation

Ensuite, répondez aux différentes question afin de sécuriser l’installation du mariaDB :

  • Saisir le mot de passe Root
  • Supprimer les utilisateurs anonymes
  • Désactiver la connexion à distance en tant que root
  • Supprimer les bases de test
  • Recharger les privilges
mysql-secure-installation-mariadb-securiser-serveur-web-wordpress

Optimisations et configuration PHP

Mise à jour du fuseau horaire : ouvrez le fichier /etc/php/7.4/fpm/php.ini recherchez la ligne :

;date.timezone =

Remplacez-la par :

date.timezone = Europe/Paris

Recherchez ensuite la bloc [opcache] et ajoutez dessous les lignes suivants :

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

Optimisation Nginx

Ouvrez le fichier /etc/nginx/nginx.conf et ajoutez-y les lignes suivantes dans le blog http des basics settings :

        ##
        # Basic Settings
        ##

        sendfile on;
        tcp_nopush on;
        tcp_nodelay on;
        keepalive_timeout 65;
        types_hash_max_size 2048;
        keepalive_requests 100000;
        server_tokens off;

        variables_hash_max_size 2048;
        variables_hash_bucket_size 256;
        server_names_hash_bucket_size 64;
        server_name_in_redirect off;
        server_names_hash_max_size 4096;

        client_max_body_size 50M;
        client_body_timeout 30;
        client_header_timeout 10;
        client_body_buffer_size 128K;
        client_header_buffer_size 3m;
        large_client_header_buffers 4 256k;

        proxy_max_temp_file_size 0;

Création de la clé DHParam :

cd /etc/ssl/certs
openssl dhparam -out dhparam.pem 4096

Préparation à la mise en place de WordPress

Utilisateur système

Nous allons créer un utilisateur système pour permettre l’isolation des sites sur le serveur, les process PHP fonctionneront sous cet utilisateur et le PHP ne pourra ainsi n’être exécuté que par cet utilisateur, sous son dossier.

useradd -md /var/www/html/demo.creation-web-bretagne.fr democreationwebbretagne
usermod -aG www-data democreationwebbretagne

Vhost Nginx

Voici un exemple de fichier de configuration Nginx sous /etc/nginx/sites-available/demo.creation-web-bretagne.fr.conf :

# Bloc de configuration pour prise en charge du WebP
map $http_accept $webp_ext {
        default "";
        "~*webp" ".webp";
}
# Upstream d'accès au socket PHP
upstream demo.creation-web-bretagne.fr {
	server            unix:/var/run/php/demo.creation-web-bretagne.fr.sock;
}
# Vhost HTTP -> HTTPS
server {
	listen 80;
	server_name demo.creation-web-bretagne.fr;
	return 301 https://demo.creation-web-bretagne.fr$request_uri;

	access_log /var/log/nginx/demo.creation-web-bretagne.fr.access.log combined;
	error_log /var/log/nginx/demo.creation-web-bretagne.fr.error.log notice;
}
server {
	listen            443 ssl http2;
	server_name       demo.creation-web-bretagne.fr;

	set $root "/var/www/html/demo.creation-web-bretagne.fr";
	root              $root;

	index		  index.php index.html;

	client_max_body_size 256M;
	proxy_buffer_size   128k;
	proxy_buffers   4 256k;
	proxy_busy_buffers_size   256k;

	ssl_certificate /etc/letsencrypt/live/demo.creation-web-bretagne.fr/fullchain.pem;
	ssl_certificate_key /etc/letsencrypt/live/demo.creation-web-bretagne.fr/privkey.pem;

    ssl_prefer_server_ciphers on;
    ssl_session_cache shared:le_nginx_SSL:1m;
    ssl_session_timeout 1d;
    ssl_protocols TLSv1.2 TLSv1.3;
    ssl_ciphers ECDHE-RSA-AES256-GCM-SHA512:DHE-RSA-AES256-GCM-SHA512:ECDHE-RSA-AES256-GCM-SHA384:DHE-RSA-AES256-GCM-SHA384:ECDHE-RSA-AES256-SHA384;

    ssl_dhparam /etc/ssl/certs/dhparam.pem;
    ssl_ecdh_curve secp384r1;

    ssl_stapling on;
    ssl_stapling_verify on;

    add_header Strict-Transport-Security "max-age=63072000; includeSubDomains; preload" always;
    add_header X-UA-Compatible "IE=Edge" always;
    add_header X-XSS-Protection "1; mode=block" always;
    add_header X-Frame-Options "SAMEORIGIN" always;
    add_header X-Content-Type-Options "nosniff" always;
    add_header Cache-Control "public, max-age=3600" always;
    add_header Referrer-Policy "same-origin" always;

	location / {
		try_files     $uri $uri/ /index.php?$args;
		add_header 'Access-Control-Allow-Origin' '*';
		add_header 'Accept-Encoding' 'gzip';
	}

	location ~ \.php$ {
		try_files $uri =404;
		fastcgi_split_path_info ^(.+\.php)(/.+)$;
		if (!-f $document_root$fastcgi_script_name) {
			return 404;
		}
		fastcgi_buffers 8 16k;
		fastcgi_buffer_size 32k;
		fastcgi_index index.php;
		fastcgi_param  SCRIPT_FILENAME $document_root$fastcgi_script_name;
		fastcgi_read_timeout 600;
		include       fastcgi.conf;
		fastcgi_pass  demo.creation-web-bretagne.fr;
	}

    # Restrictions d'accès divers
    location /.git { deny all; }
    location /.htaccess { deny all; }
    location /.htpasswd { deny all; }
    location /.user.ini { deny all; }
    location ~ ^/\. { deny all; }
    location ~* /uploads/.*\.php$ { deny all; }
    location ~* /files/.*\.php$ { deny all; }
    location ~* /akismet/.*\.php$ { deny all; }
    location /wp-content/cache/ { deny all; }
    location ~ ~$ { deny all; }
    location ~* /(?:uploads|files)/.*\.php$ { deny all; }

    location ~* /skins/.*.php$ {
        deny all;
        access_log off;
        log_not_found off;
    }
    location ~* /modules/.*.php$ {
        deny all;
        access_log off;
        log_not_found off;
    }
    location ~* /wp-includes/.*.php$ {
        deny all;
        access_log off;
        log_not_found off;
    }

    # Mise en cache des statiques
    set $skip_cache 0;
    # POST requests and urls with a query string should always go to PHP
    if ($request_method = POST) {
            set $no_cache 1;
    }
    if ($query_string != "") {
        set $skip_cache 1;
    }

    # Don't cache uris containing the following segments
    if ($request_uri ~* "(/wp-admin/|/wp-(app|cron|login|register|mail).php|wp-.*.php|/feed/|index.php|wp-comments-popup.php|wp-links-opml.php|wp-locations.php|sitemap(_index)?.xml|[a-z0-9_-]+-sitemap([0-9]+)?.xml)") {
        set $skip_cache 1;
    }

    # Don't use the cache for logged in users or recent commenters
    if ($http_cookie ~* "comment_author|wordpress_[a-f0-9]+|wp-postpass|wordpress_no_cache|wordpress_logged_in") {
        set $skip_cache 1;
    }
    #end Caching

    location ~* \.(?:manifest|appcache|html?|xml)$ {
        expires 30d;
    }
    location ~* \.(?:rss|atom)$ {
        expires 600s;
        add_header Cache-Control "public";
    }
    location ~* \.json {
        expires 1h;
        add_header Cache-Control "public";
    }
    location ~* \.(?:|cur|gz|svg|svgz|mp4|ogg|ogv|webm|htc)$ {
        expires 365d;
        add_header Cache-Control "public";
        log_not_found off;
        access_log off;
    }
    location ~ \.(?:gif|ico|webp)$ {
        expires 365d;
        log_not_found off;
        add_header Cache-Control "public";
        access_log off;
    }
    location ~ /\. {
            access_log off;
            log_not_found off;
            deny all;
    }
    location ~* \.(?:jpg|jpeg|png|cur|gz|svg|svgz|mp4|ogg|ogv|webm|htc)$ {
        expires 365d;
        add_header Cache-Control "public";
        log_not_found off;
        access_log off;
    }
    location ~ \.(?:ttf|ttc|eot|woff|woff2|otf|svg)$ {
        expires 365d;
        add_header Cache-Control "public";
        log_not_found off;
        access_log off;
    }
    location ~ \.(?:css|js)$ {
        expires 365d;
        log_not_found off;
        access_log off;
        add_header X-Content-Type-Options "nosniff";
        add_header Cache-Control "public";
    }
    location ~* \?sccss {
        expires 30d;
        add_header Cache-Control "public";
        access_log off;
    }
    location = /robots.txt {
        log_not_found off;
        access_log off;
    }
    location = /favicon.ico {
        log_not_found off;
        access_log    off;
    }

    # Restrictions d'accès à la page de Status PHP FPM
	location /status_phpfpm {
		fastcgi_pass demo.creation-web-bretagne.fr;
		include fastcgi_params;
		fastcgi_param SCRIPT_FILENAME $document_root$fastcgi_script_name;
		allow 127.0.0.1;
		deny all;
		access_log off;
    }

    # Restrictions d'accès sur le XMLRPC
	location = /xmlrpc.php {
		allow 127.0.0.1;
		fastcgi_pass demo.creation-web-bretagne.fr;
		include fastcgi_params;
		fastcgi_param SCRIPT_FILENAME $document_root$fastcgi_script_name;
 	}

	access_log /var/log/nginx/demo.creation-web-bretagne.fr.access.log combined;
	error_log /var/log/nginx/demo.creation-web-bretagne.fr.error.log notice;
}

Pool PHP FPM

Voici désormais un exemple de fichier de configuration FPM, sous /etc/php/7.4/fpm/pool.d/demo.creation-web-bretagne.fr.conf :

[demo.creation-web-bretagne.fr]

;prefix = /path/to/pools/$pool

user = democreationwebbretagne
group = www-data

listen = /var/run/php/demo.creation-web-bretagne.fr.sock
listen.owner = www-data
listen.group = www-data
listen.mode = 0660

pm = ondemand
pm.max_children = 40
pm.process_idle_timeout = 10s
pm.max_requests = 500

pm.status_path = /status_phpfpm
ping.path = /ping
ping.response = pong

access.log = /var/log/php/demo.creation-web-bretagne.fr.access.log
access.format = "%R - %u %t \"%m %r%Q%q\" %s %f %{mili}d %{kilo}M %C%%"
slowlog = /var/log/php/demo.creation-web-bretagne.fr.slow.log

request_slowlog_timeout = 5s
request_terminate_timeout = 120s

chdir = /

catch_workers_output = yes

env[HOSTNAME] = demo.creation-web-bretagne.fr
env[PATH] = /usr/local/bin:/usr/bin:/bin
env[TMP] = /tmp
env[TMPDIR] = /tmp
env[TEMP] = /tmp

php_admin_value[sendmail_path] = "/usr/sbin/sendmail -t -i -f webmaster@demo.creation-web-bretagne.fr"
php_flag[display_errors] = off
php_admin_value[error_log] = /var/log/php/demo.creation-web-bretagne.fr.error.log
php_admin_flag[log_errors] = on
php_admin_flag[allow_url_fopen] = off
php_admin_value[memory_limit] = 1024M
php_admin_value[open_basedir] = /var/www/html/demo.creation-web-bretagne.fr:/tmp
php_admin_value[upload_max_filesize] = 40M
php_admin_value[post_max_size] = 40M
php_admin_value[max_execution_time] = 700
php_admin_value[max_input_vars] = 2500

Base de données

Nous allons maintenant créer la base de données et l’utilisateur associé :

CREATE DATABASE db_democreationwebbretagne;
GRANT ALL PRIVILEGES ON db_democreationwebbretagne.* TO 'usr_democreationwebbretagne'@'127.0.0.1' IDENTIFIED BY 'monSuperPassword';
FLUSH PRIVILEGES;

Génération du certificat SSL Let’s Encrypt

Notre domaine étant géré chez Cloudflare, nous allons ici utiliser le challenge DNS pour procéder à la génération du certificat Let’s Encrypt :

apt install python3-certbot-nginx python3-certbot-dns-cloudflare certbot python3-certbot

Ensuite, il faudra récupérer vos identifiants et clé d’API sur Cloudflare pour renseigner un fichier en local, sur lequel vous appliquerez des permissions en lecture uniquement (400), puis, lancez la génération sur certificat :

certbot certonly --dns-cloudflare --dns-cloudflare-credentials /root/.cloudflare -d demo.creation-web-bretagne.fr

Répondez aux quelques questions posées :

  • Une adresse email pour l’envoi des remind d’expiration
  • Acceptez les termes du contrat d’utilisation
  • Acceptez ou non de partager vos données avec LE
certbot-cloudflare-dns-challenge-python-letsencrypt-creation-web-bretagne-wordpress

Installation de WordPress

Nous allons maintenant procéder à l’installation de WordPress via WP Cli, un utilitaire en ligne de commandes permettant de tout gérer sur WordPress. Récupérons le binaire :

curl -O https://raw.githubusercontent.com/wp-cli/builds/gh-pages/phar/wp-cli.phar
php wp-cli.phar --info
chmod +x wp-cli.phar
sudo mv wp-cli.phar /usr/local/bin/wp
wp --info

Si tout se passe bien, vous devriez voir apparaitre les informations relatives au binaire wp-cli :

creation-web-bretagne-wordpress-nginx-php-ssl-letsencrypt-wp-cli

Placez-vous désormais dans la docroot du site et suivez le guide pour :

  • Télécharger les sources de WordPress en FR :
sudo -u democreationwebbretagne wp core download --locale=fr_FR
  • Procéder à la génération du wp-config.php avec toutes les informations de connexion à la base de données :
sudo -u democreationwebbretagne wp core config --dbname=db_democreationwebbretagne --dbuser=usr_democreationwebbretagne --dbpass=monSuperPassword --dbhost=127.0.0.1 
  • EN OPTION : procéder à l’installation du site avec son URL, le nom du site et les données de l’administrateur :
sudo -u democreationwebbretagne wp core install --url="https://demo.creation-web-bretagne.--title="Creation Web Bretagne" --admin_email="votre@email.fr" --admin_user="votreadmin" --admin_password=monSuperPassword

Nous allons maintenant procéder à la validation de la configuration et le redémarrage des services :

systemctl restart nginx.service && systemctl restart php7.4-fpm.service

Tout devrait désormais être en place et le site joignable :

creation-web-bretagne-wordpress-wp-cli-nginx-php-ssl-letsencrypt

Si vous avez la moindre question, ou que vous souhaitez laisser cette partie à notre agence, nous serions ravis de vous accompagner dans l’installation de votre site WordPress, n’hésitez pas, contactez-nous.