Service backend down

Quand le serveur web fonctionne mais pas le reste

PHP-FPM crashé, MySQL saturé, Redis indisponible : rétablissez vos services.

Les symptômes révélateurs

Vous êtes face à un problème de backend si :

  • Les fichiers statiques chargent (images, CSS, JS) mais pas les pages PHP
  • Nginx/Apache répond mais avec une erreur 502 Bad Gateway ou 503
  • Les logs Nginx montrent des erreurs « upstream » ou « connect() failed »
  • La commande systemctl status php-fpm montre « inactive » ou « failed »
  • Le site fonctionnait et s’est arrêté brutalement (pas progressivement)

La différence avec une surcharge : ici, un service est complètement arrêté, pas simplement submergé. Le redémarrage résout souvent le problème immédiat.

Diagnostic rapide : État des services

Commande unique pour tout vérifier

$ systemctl status nginx php8.2-fpm mysql redis-server --no-pager

● nginx.service - A high performance web server
     Active: active (running) ✅

● php8.2-fpm.service - The PHP 8.2 FastCGI Process Manager
     Active: inactive (dead) ❌  ← PROBLÈME

● mysql.service - MySQL Community Server
     Active: active (running) ✅

● redis-server.service - Advanced key-value store
     Active: active (running) ✅

Vérifier chaque service individuellement

# PHP-FPM
$ systemctl status php8.2-fpm
$ ps aux | grep php-fpm

# MySQL / MariaDB
$ systemctl status mysql
$ mysqladmin -u root -p ping
# Réponse attendue : "mysqld is alive"

# Redis
$ systemctl status redis-server
$ redis-cli ping
# Réponse attendue : "PONG"

# Memcached
$ systemctl status memcached
$ echo "stats" | nc localhost 11211 | head

Problème 1 : PHP-FPM down

C’est la cause la plus fréquente de 502/503 quand Nginx fonctionne.

Diagnostic

# État du service
$ systemctl status php8.2-fpm
● php8.2-fpm.service - The PHP 8.2 FastCGI Process Manager
     Active: failed (Result: exit-code) ❌
     Process: 1234 ExecStart=... (code=exited, status=78)

# Logs détaillés
$ journalctl -u php8.2-fpm -n 50 --no-pager

# Logs PHP-FPM
$ tail -50 /var/log/php8.2-fpm.log

Erreurs courantes et solutions

Erreur : « unable to bind listening socket »

$ journalctl -u php8.2-fpm | grep "bind"
unable to bind listening socket for address '/run/php/php8.2-fpm.sock'

Cause : Le socket existe déjà (crash précédent) ou permissions incorrectes.

Solution :

$ rm -f /run/php/php8.2-fpm.sock
$ systemctl start php8.2-fpm

Erreur : « pm.max_children reached »

$ grep "max_children" /var/log/php8.2-fpm.log
WARNING: [pool www] server reached pm.max_children setting (5)

Cause : Tous les workers PHP sont occupés, les nouvelles requêtes sont refusées.

Solution : Augmenter pm.max_children dans la config du pool :

/etc/php/8.2/fpm/pool.d/www.conf

pm = dynamic
pm.max_children = 50      ; Augmenter selon RAM disponible
pm.start_servers = 10
pm.min_spare_servers = 5
pm.max_spare_servers = 20

Erreur : « OOM killer » (Out Of Memory)

$ dmesg | grep -i "killed process"
[12345.678] Out of memory: Killed process 9876 (php-fpm)

Cause : Le serveur manque de RAM, le kernel tue PHP-FPM pour survivre.

Solution :

  • Réduire pm.max_children
  • Ajouter de la RAM
  • Optimiser la consommation mémoire des scripts

Redémarrage et vérification

# Redémarrer PHP-FPM
$ systemctl restart php8.2-fpm

# Vérifier qu'il tourne
$ systemctl status php8.2-fpm
● php8.2-fpm.service
     Active: active (running) ✅
     
# Vérifier que le socket existe
$ ls -la /run/php/php8.2-fpm.sock
srw-rw---- 1 www-data www-data 0 Dec 26 14:30 /run/php/php8.2-fpm.sock

# Tester une page PHP
$ curl -I https://monsite.com
HTTP/1.1 200 OK ✅

Problème 2 : MySQL / MariaDB down ou saturé

Diagnostic

# État du service
$ systemctl status mysql

# Tester la connexion
$ mysql -u root -p -e "SELECT 1"
ERROR 2002 (HY000): Can't connect to local MySQL server through socket '/var/run/mysqld/mysqld.sock'
# ❌ MySQL est down

# Ou
$ mysql -u root -p -e "SELECT 1"
ERROR 1040 (HY000): Too many connections
# ❌ MySQL saturé

MySQL down : Causes et solutions

Vérifier les logs :

$ tail -100 /var/log/mysql/error.log

Erreurs fréquentes :

ErreurCauseSolution
« InnoDB: Unable to lock ./ibdata1 »Crash précédent, fichier verrouillérm /var/lib/mysql/ib_logfile* puis restart
« disk full »Plus d’espace disqueLibérer de l’espace, purger les logs
« Out of memory »RAM insuffisanteRéduire innodb_buffer_pool_size
« Too many open files »Limite systèmeAugmenter ulimit

Redémarrer MySQL :

$ systemctl restart mysql

# Si ça ne démarre pas, mode recovery
$ mysqld_safe --skip-grant-tables &
# Puis investiguer et réparer

MySQL saturé : « Too many connections »

# Voir les connexions actives
$ mysql -u root -p -e "SHOW PROCESSLIST;"
+----+------+-----------+------+---------+------+-------+------------------+
| Id | User | Host      | db   | Command | Time | State | Info             |
+----+------+-----------+------+---------+------+-------+------------------+
| 1  | root | localhost | NULL | Query   |    0 | init  | SHOW PROCESSLIST |
| 2  | web  | localhost | shop | Sleep   |  300 | NULL  | NULL             |
| 3  | web  | localhost | shop | Sleep   |  298 | NULL  | NULL             |
# ... des dizaines de connexions "Sleep"

Solution immédiate : Killer les connexions dormantes

$ mysql -u root -p -e "
SELECT CONCAT('KILL ', id, ';') 
FROM information_schema.processlist 
WHERE command = 'Sleep' AND time > 300;" | mysql -u root -p

Solution durable : Ajuster la configuration

/etc/mysql/mysql.conf.d/mysqld.cnf

[mysqld]
# Augmenter si nécessaire (attention à la RAM)
max_connections = 200

# Fermer les connexions inactives plus vite
wait_timeout = 60
interactive_timeout = 60

# Optimiser InnoDB
innodb_buffer_pool_size = 1G  # 50-70% de la RAM disponible

Problème 3 : Problème de socket / communication

Nginx et PHP-FPM communiquent via un socket Unix ou un port TCP. Si la configuration ne correspond pas, 502/503.

Vérifier la configuration Nginx

$ grep -r "fastcgi_pass" /etc/nginx/
/etc/nginx/sites-available/monsite.conf:    fastcgi_pass unix:/run/php/php8.2-fpm.sock;

Vérifier la configuration PHP-FPM

$ grep "listen" /etc/php/8.2/fpm/pool.d/www.conf
listen = /run/php/php8.2-fpm.sock

Les deux doivent correspondre !

Vérifier que le socket existe et est accessible

$ ls -la /run/php/php8.2-fpm.sock
srw-rw---- 1 www-data www-data 0 Dec 26 14:30 /run/php/php8.2-fpm.sock

# L'utilisateur Nginx doit pouvoir y accéder
$ ps aux | grep nginx
www-data  1234  ... nginx: worker process
# ✅ Nginx tourne en www-data, qui est propriétaire du socket

Configuration correcte

/etc/php/8.2/fpm/pool.d/www.conf

[www]
user = www-data
group = www-data

listen = /run/php/php8.2-fpm.sock
listen.owner = www-data
listen.group = www-data
listen.mode = 0660

/etc/nginx/sites-available/monsite.conf

location ~ \\.php$ {
    fastcgi_pass unix:/run/php/php8.2-fpm.sock;
    fastcgi_param SCRIPT_FILENAME $document_root$fastcgi_script_name;
    include fastcgi_params;
    
    # Timeouts (évite les 504)
    fastcgi_read_timeout 300;
    fastcgi_send_timeout 300;
}

Problème 4 : Redis / Memcached down

Si votre application utilise Redis ou Memcached pour le cache ou les sessions, leur indisponibilité peut causer des erreurs.

Redis

# État du service
$ systemctl status redis-server

# Test de connexion
$ redis-cli ping
PONG  # ✅ OK

# Si erreur de connexion
$ redis-cli ping
Could not connect to Redis at 127.0.0.1:6379: Connection refused
# ❌ Redis down

# Redémarrer
$ systemctl restart redis-server

# Vérifier les logs
$ tail -50 /var/log/redis/redis-server.log

Erreur fréquente : « maxmemory reached »

$ redis-cli info memory | grep used_memory_human
used_memory_human:256.00M

# Si Redis est plein, il refuse les écritures
$ redis-cli set test "value"
(error) OOM command not allowed when used memory > 'maxmemory'

Solution :

/etc/redis/redis.conf

# Augmenter la limite
maxmemory 512mb

# Politique d'éviction (supprimer les clés les moins utilisées)
maxmemory-policy allkeys-lru

Memcached

# État du service
$ systemctl status memcached

# Test
$ echo "stats" | nc localhost 11211 | head
STAT pid 12345
STAT uptime 123456
# ✅ OK

# Redémarrer si down
$ systemctl restart memcached

Impact sur les sessions : Si vos sessions PHP sont stockées dans Redis/Memcached et que le service est down, tous vos utilisateurs seront déconnectés. Prévoyez un fallback vers les fichiers en cas de problème.

Script de diagnostic complet

/usr/local/bin/check-backend.sh

#!/bin/bash
# Script de diagnostic des services backend

echo "=== DIAGNOSTIC BACKEND ==="
echo ""

# Fonction de check
check_service() {
    local service=$1
    local name=$2
    
    if systemctl is-active --quiet $service; then
        echo "✅ $name : OK"
    else
        echo "❌ $name : DOWN"
        echo "   → systemctl start $service"
    fi
}

# Vérifier les services
check_service nginx "Nginx"
check_service php8.2-fpm "PHP-FPM"
check_service mysql "MySQL"
check_service redis-server "Redis"

echo ""
echo "=== RESSOURCES ==="

# RAM
free -h | awk 'NR==2{printf "RAM: %s / %s (%.1f%% utilisé)\
", $3, $2, $3/$2*100}'

# Disque
df -h / | awk 'NR==2{printf "Disque: %s / %s (%s utilisé)\
", $3, $2, $5}'

# Load
echo "Load: $(uptime | awk -F'load average:' '{print $2}')"

echo ""
echo "=== CONNEXIONS ==="

# Connexions MySQL
mysql -u root -pPASSWORD -e "SELECT COUNT(*) as 'MySQL connexions' FROM information_schema.processlist;" 2>/dev/null || echo "MySQL: impossible de se connecter"

# Workers PHP
echo "PHP-FPM workers: $(ps aux | grep 'php-fpm: pool' | wc -l)"

echo ""
echo "=== ERREURS RECENTES ==="
echo "-- PHP-FPM --"
tail -5 /var/log/php8.2-fpm.log 2>/dev/null | grep -i error || echo "Aucune erreur récente"

echo "-- MySQL --"
tail -5 /var/log/mysql/error.log 2>/dev/null | grep -i error || echo "Aucune erreur récente"

echo ""
echo "=== FIN DIAGNOSTIC ==="
$ chmod +x /usr/local/bin/check-backend.sh
$ check-backend.sh

Automatiser le redémarrage des services

Avec systemd (service auto-restart)

/etc/systemd/system/php8.2-fpm.service.d/restart.conf

[Service]
Restart=on-failure
RestartSec=5s
$ systemctl daemon-reload
$ systemctl restart php8.2-fpm

Avec un script cron de surveillance

/usr/local/bin/watch-backend.sh

#!/bin/bash
# Redémarre automatiquement les services down

restart_if_dead() {
    local service=$1
    if ! systemctl is-active --quiet $service; then
        echo "$(date): $service down, redémarrage..." >> /var/log/backend-watch.log
        systemctl restart $service
    fi
}

restart_if_dead php8.2-fpm
restart_if_dead mysql
restart_if_dead redis-server
# Cron toutes les minutes
$ crontab -e
* * * * * /usr/local/bin/watch-backend.sh

Cette surveillance automatique est un pansement, pas une solution. Si un service crash régulièrement, il faut trouver et corriger la cause racine.

Infrastructure fiable et résiliente

Monitoring proactif, haute disponibilité, intervention 24/7.

Questions fréquentes

Pourquoi PHP-FPM crash-t-il régulièrement ?

Les causes les plus fréquentes sont : mémoire insuffisante (OOM), erreurs fatales PHP répétées (bug applicatif), configuration pm.max_children inadaptée, ou fuite mémoire dans un script. Analysez les logs et le dmesg pour identifier la cause exacte.

Comment savoir si c’est MySQL ou PHP le problème ?

Testez MySQL directement : mysql -u root -p -e "SELECT 1". Si ça fonctionne, MySQL est OK et le problème vient de PHP ou de la connexion PHP→MySQL. Vérifiez aussi les logs PHP pour des erreurs de connexion PDO.

Puis-je utiliser plusieurs versions de PHP-FPM ?

Oui, c’est courant. Installez plusieurs versions (php7.4-fpm, php8.2-fpm), configurez chacune avec son propre socket, et pointez chaque site vers le bon socket dans Nginx. Utile pour les migrations progressives.

Le site marche en HTTP mais pas en HTTPS, pourquoi ?

Ce n’est généralement pas un problème de backend mais de certificat SSL ou de configuration Nginx. Vérifiez que le bloc server pour le port 443 a bien la même configuration PHP que celui du port 80.