Ce guide couvre l'installation, la configuration et la maintenance d'Arcivéo Monitor. Les sections sont regroupées : présentation générale, déploiement du tableau de bord, connexion des outils de sécurité, modules intégrés et diagnostic. Les commandes se copient via le bouton à droite.
L'installation du panneau se fait sur des pages dédiées, étape par étape. Choisissez une méthode :
Arcivéo Monitor est un tableau de bord de sécurité serveur. Il collecte les données des outils installés (Fail2ban, UFW, Lynis, ModSecurity, AIDE, ClamAV, Auditd, CrowdSec, Suricata, Falco, etc.) et les affiche dans une interface unifiée avec tableau de bord, carte des attaques et pages détaillées par outil.
Le moniteur n'est pas un outil de protection active — il ne bloque pas les attaques lui-même. Son rôle est d'agréger les informations des outils déjà en place et de les présenter de façon claire.
Le moniteur fonctionne uniquement en local — il doit être installé sur le serveur qu'il surveille. Aucun SSH ni API distante.
Le tableau de bord exécute toutes les commandes (fail2ban-client, ufw status, ipset list, etc.) sous l'utilisateur du serveur web (généralement www-data, sur les panneaux d'hébergement — le compte du site) avec un jeu de droits restreint sudo — limité à des utilitaires précis, sans accès root global. Les résultats sont analysés et affichés dans le navigateur.
Le score part du maximum et diminue à chaque problème détecté :
PermitRootLogin yes) — −20Résultat : 80+ = Protégé, 60–79 = Attention, <60 = Menacé.
WebAuthn — standard d'authentification sans mot de passe via une clé matérielle. Compatible avec YubiKey, Touch ID, Face ID, Windows Hello, Passkey.
Après la connexion par mot de passe, le système demande une confirmation via la clé enregistrée. Même en cas de fuite du mot de passe, la connexion est impossible sans la clé physique ou la biométrie.
Pour la configuration, ouvrez Clés WebAuthn dans le menu latéral et cliquez sur « Enregistrer une clé ». Enregistrez deux clés d'emblée : si votre unique clé est perdue ou endommagée, la connexion au dashboard avec celle-ci sera impossible.
Le tableau de bord peut envoyer le rapport de sécurité vers Telegram et par e-mail (sur clic ou selon une planification). Cela se configure dans « Paramètres ».
Telegram. Il faut un jeton de bot et un chat id :
@BotFather → /newbot → obtenez un jeton du type 123456:ABC....@userinfobot, ou ouvrez https://api.telegram.org/bot<TOKEN>/getUpdates et repérez "chat":{"id":...}.Email. Deux méthodes au choix dans « Paramètres » → Email :
re_...) et un domaine d'expéditeur vérifié.Statut du rapport : « ATTENTION » ou « OK ». Le titre devient « ATTENTION » uniquement en cas de problème réel ou d'action en attente : menace détectée par ClamAV, modifications de fichiers dans AIDE, événements critiques Falco (Emergency/Alert/Critical sur les 24 dernières h), service tombé dans Monit, redémarrage requis, SSL qui expire (≤14 jours) ou mises à jour de sécurité en attente. Le bruit de fond — attaques SSH par force brute des bots, IP bannies par fail2ban, alertes Suricata, avertissements Lynis et requêtes déjà repoussées par ModSecurity — n'élève pas le statut ; ces chiffres dans le rapport ne signifient donc pas « ATTENTION » à eux seuls.
Les modules de surveillance détaillés (Lynis, UFW, ModSecurity, carte des attaques, AIDE, ClamAV, etc.) s'ouvrent avec une licence valide. Sans elle, le tableau de bord, les paramètres et le compte fonctionnent, mais les modules affichent la carte « Licence requise ».
Après l'achat, votre espace client contient un code d'activation de la forme ARCIVEO-XXXX-XXXX-XXXX-XXXX. Il faut l'« activer » sur le domaine de votre panneau — cela transforme le code en un fichier de licence signé (bloc [license]) que vous collez dans le panneau.
Comment activer (3 étapes) :
my.arciveo.com → section « Licences » / « Activation de licence » — copiez le code ARCIVEO-….monitor.example.com). Cliquez sur activer — le système génère un fichier de licence lié à ce domaine et l'affiche dans un champ avec le bouton « Copier ».Le panneau vérifie la clé de manière cryptographique : signature, liaison au domaine et durée de validité.
APP_URL de config.php et saisissez uniquement le nom d'hôte — sans https:// ni le préfixe www. L'activation est à usage unique : le code se transforme en licence pour le domaine saisi et ne peut pas être réactivé — en cas d'erreur dans le domaine, la clé ne conviendra pas à votre panneau et le code sera consommé. Saisissez donc le domaine avec attention.
Tous les paramètres principaux du tableau de bord sont définis dans un seul fichier config.php à la racine (à côté du dossier public/) sous forme de constantes define(). Le fichier est créé lors de l'installation ; il est rarement nécessaire de le modifier à la main — surtout lors d'un changement de domaine, d'une migration ou d'une connexion à une autre base. Après chaque modification, redémarrez PHP-FPM (sinon, à cause d'OPcache, les changements ne s'appliqueront pas).
Renseignez vos valeurs aux endroits surlignés ; laissez le reste tel quel :
Base de données. Paramètres de connexion à MySQL/MariaDB :
DB_HOST — hôte du SGBD, presque toujours localhost ;DB_NAME — nom de la base de données du tableau de bord ;DB_USER — utilisateur de la BD (accès uniquement à sa propre base) ;DB_PASS — mot de passe de cet utilisateur ;DB_CHARSET — encodage de la connexion, laissez utf8mb4.Application.
APP_URL — adresse complète du tableau de bord (p. ex. https://monitor.example.com). Elle doit correspondre au domaine sur lequel la licence est activée — sinon la clé sera rejetée (voir la section « Licence ») ;TIMEZONE — fuseau horaire PHP : n'affecte que la façon dont le tableau de bord affiche les dates et heures. Il n'a aucun effet sur l'heure de lancement des tâches cron — c'est le fuseau du système qui s'applique (voir « Toutes les tâches cron »).Durée de session. SESSION_LIFETIME — délai d'inactivité de la session en secondes (glissant : réinitialisé à chaque activité). Par défaut 28800 = 8 heures ; passé ce délai d'inactivité, le tableau de bord demandera de se reconnecter. Par exemple, 3600 = 1 heure, 86400 = un jour.
Journalisation des erreurs. Les erreurs ne sont jamais montrées aux visiteurs ; elles sont écrites dans logs/php_errors.log — visibles sur la page « Logs de l'application ». Ces lignes (display_errors=0, log_errors=1, chemin error_log) n'ont généralement pas besoin d'être modifiées — les réglages sont définis directement dans le fichier et ne dépendent pas de php.ini.
public/), et pour ce tableau de bord la racine web (DocumentRoot) est justement la racine du tableau de bord, pas public/. Le fichier ne « fuit » pas de lui-même : le .htaccess racine lui interdit explicitement l'accès (Require all denied) — le serveur renvoie une 403. Même sans cette règle, le code source ne fuirait pas : c'est du PHP — le serveur l'exécute au lieu de le renvoyer en texte. Par précaution : ne le publiez pas dans des dépôts publics et ne le transmettez pas au support avec le vrai mot de passe. Droits du fichier — 640.
UFW (Uncomplicated Firewall) est une interface simple pour nftables/iptables. Il ferme tous les ports entrants, sauf ceux explicitement autorisés. La page « Pare-feu UFW » affiche l'état et les règles.
ufw enable, autorisez impérativement SSH (ufw allow OpenSSH), sinon vous perdrez l'accès au serveur.
deny n'est pas considéré comme accessible depuis l'extérieur.
Skipping adding existing rule n'est pas une erreur. C'est ainsi qu'UFW signale qu'une règle identique existe déjà et qu'il ne l'ajoute pas de nouveau. Lors d'une nouvelle exécution de la configuration automatique (elle est idempotente), ce message est normal — aucune action n'est requise.
Bloque automatiquement une IP après un nombre excessif de tentatives de connexion échouées. Analyse les journaux SSH, nginx, Apache et d'autres services.
L'installation de base est décrite plus haut. Voici une configuration opérationnelle qui fournit des dizaines de jails actifs et des milliers de blocages : réglages généraux, jails essentiels et bannissement automatique des IP malveillantes issues de la liste ipsum.
Fichier /etc/fail2ban/jail.local — réglages généraux et jails essentiels :
ignoreip, veillez à inscrire votre propre IP et vos réseaux de confiance, sinon vous risquez de vous bannir vous-même. Après modification : sudo fail2ban-client reload.
Chargement automatique de la liste de blocage ipsum — dans le cron root (sudo crontab -e) : le level 1 (100 000+ IP) est chargé dans l'ensemble ipsum, filtré au niveau du pare-feu (voir la section « Liste de blocage IPset ») :
ipsum — c'est précisément celui que lit le tableau de bord (carte « IPset ipsum »). Niveaux : levels/1.txt — couverture maximale, levels/3.txt — plus précis (3+ sources).
Pourquoi le « Monitor de sécurité » est divisé en deux zones. La protection fonctionne sur deux niveaux, et le tableau de bord ne les mélange pas :
sshd, apache-*, nginx-*, etc.) et récidivistes acharnés (jail recidive — ceux déjà bannis plusieurs fois). Ce sont des IP qui ont réellement tenté de vous attaquer — elles figurent sur la carte des attaques et la « Chronologie ».ipset ipsum, filtrée au niveau du pare-feu par une règle DROP. Ces adresses n'ont, pour la plupart, jamais touché votre serveur — elles sont coupées à l'avance ; le compteur « IPset ipsum » indique combien ont été filtrées préventivement.La différence est simple : le réactif, c'est « ceux-ci ont attaqué et se sont fait bannir » ; le préventif, c'est « ceux-ci ont été bloqués avant même toute tentative ». Auparavant, la list-3 ipsum était artificiellement injectée dans recidive (d'où l'ancienne distinction « recidive de liste ») ; désormais, recidive ne contient que de vrais récidivistes, et le préventif est entièrement géré au pare-feu.
ipsum — liste publique d'IP malveillantes, mise à jour quotidiennement. Le Monitor affiche le nombre d'adresses chargées sur le tableau de bord et la carte des attaques, et le prend en compte dans le Score de sécurité (−10 si l'ensemble n'est pas chargé).
Variante minimale sans fail2ban — un ensemble ipsum dédié avec blocage via iptables :
@reboot. Par la même occasion, la commande create … -exist fixe la limite maxelem 300000 (par défaut 65536 — le level 1 ne rentre pas, on obtient « Hash is full ») :
ipsum et, si le pare-feu est géré par l'installateur (VPS neuf — profils « Complète »/« Allégée »), rattache l'ensemble à UFW via une règle DROP — le trafic de ces IP est réellement bloqué. La règle se place après ESTABLISHED,RELATED, si bien que les connexions en cours (dont votre SSH) ne sont pas coupées — seules les nouvelles connexions de la liste le sont. L'ensemble est restauré au démarrage du service ipsum-load.service avant le pare-feu (sinon UFW ne monterait pas) et mis à jour par cron à 04:00. Sur un serveur déjà configuré (panneau, pare-feu propre), l'installateur ne touche pas au pare-feu — ipsum y reste une liste pour le tableau de bord et la carte des attaques, et la règle DROP s'ajoute manuellement au besoin (variante minimale avec iptables … --match-set ipsum … -j DROP — ci-dessus). En installation automatique, rien n'est à faire manuellement.
Remplaçant moderne de Fail2ban avec threat intelligence collaboratif : blocages issus de la communauté et règles personnalisées. Nécessite un bouncer distinct pour appliquer les blocages au pare-feu.
systemctl is-active crowdsec). Pour le démarrer : sudo systemctl enable --now crowdsec ; en cas d'échec, consultez sudo journalctl -u crowdsec -n 30. Même règle pour tout service au statut « Non démarré » (Suricata, Falco, Monit, MySQL).
stream halted / les blocages ne s'appliquent pas. Il s'agit d'une clé api orpheline : le bouncer a été supprimé de cscli bouncers list, mais son ancienne clé est restée dans /etc/crowdsec/bouncers/*.yaml. Réenregistrez le bouncer et renseignez la nouvelle clé :
AIDE (Advanced Intrusion Detection Environment) prend un instantané du système de fichiers et signale à chaque vérification les modifications dans /etc, /bin, /usr. Après l'installation, l'initialisation de la base est obligatoire (aideinit).
aideinit, le terminal reste 5 à 15 minutes sur la ligne Running aide --init... — c'est normal (hachage de tout le système de fichiers, charge disque). N'interrompez pas avec Ctrl+C. Si le processus « se fige » sans rien écrire, il attend peut-être une réponse à une invite masquée Overwrite existing aide.db.new [Yn]? (appuyez sur Y). Pour vérifier l'activité depuis une autre session : pgrep -af aide.
aideinit : « 21_aide_spamassassin … printf: invalid number » (return code 20) — bug connu du snippet de configuration AIDE sous Ubuntu 22.04. La base n'est pas créée. Écartez le snippet défectueux et recommencez :
aideinit n'a pas été lancé, soit (Ubuntu 24.04) le répertoire /var/lib/aide a été créé en mode 700 et est inaccessible à www-data — se corrige avec sudo chmod 755 /var/lib/aide (voir le bloc ci-dessus). « Aucune vérification » = la base existe, mais aucune vérification n'a encore été effectuée — ce n'est pas une erreur. Le moniteur lit les résultats depuis /var/log/aide/aide.log.
/etc/cron.daily/aide standard sur les nouvelles versions d'Ubuntu/Debian peut ne pas écrire /var/log/aide/aide.log dans le format attendu (et aide.wrapper n'y est plus présent). Il est plus fiable d'ajouter votre propre cron avec un --config explicite — il écrit le log en tant que root en mode 644, et le moniteur le lit sans groupes supplémentaires :
chmod 755 /var/lib/aide et le cron de vérification à 02:00 — rien à faire manuellement.
sudo aideinit && sudo cp /var/lib/aide/aide.db.new /var/lib/aide/aide.db.
Antivirus pour Linux. Particulièrement utile pour analyser /var/www à la recherche de shells PHP et de code malveillant.
enable --now ? Trois causes fréquentes :
1. La ligne Example est restée dans la config — clamd refuse de démarrer tant qu'elle est présente :
2. La base de signatures n'est pas téléchargée — clamd ne démarre pas sans elle :
3. Il est simplement en cours de chargement — clamd charge ~8 M de signatures en mémoire en 30 à 60 s. Patientez et vérifiez : systemctl is-active clamav-daemon (statut activating → toujours en cours de chargement).
sudo journalctl -u clamav-daemon -n 30 --no-pager.
clamd ne fait que garder les signatures en mémoire, il n'analyse rien de lui-même de façon planifiée. Le tableau de bord affiche les résultats de l'analyse planifiée ; il faut donc un cron qui analyse et écrit un journal. L'installation automatique met en place le wrapper /usr/local/bin/clamav-scan.sh et un cron à 01:30 — après la première exécution, « Fichiers analysés » et « Dernière analyse » se rempliront. Pour lancer tout de suite sans attendre la planification : sudo /usr/local/bin/clamav-scan.sh.
Linux Malware Detect (LMD) — un scanner de logiciels malveillants ciblant les menaces web : shells PHP, backdoors web, téléchargeurs. Il s'appuie sur le moteur ClamAV et le complète avec ses propres signatures.
maldet --report.
update-rc.d: error: unable to read /etc/init.d/maldet peut apparaître — elle est sans danger. maldet n'utilise pas init.d ; la mise à jour des signatures et les scans sont lancés via /etc/cron.daily/maldet. Si installation completed s'affiche ensuite, tout est bien installé.
apt, mais dans /usr/local/maldetect, et lorsque open_basedir est activé, sa présence est vérifiée via le shell — voir la section « La page est vide alors que les données sont bien sur le serveur ».
Système de détection d'intrusion réseau : il analyse le trafic au niveau des paquets et connaît des milliers de signatures d'attaques. Il complète ModSecurity (qui agit au niveau HTTP, tandis que Suricata opère au niveau TCP/IP).
/var/log/suricata/eve.json sous root avec des permissions 750 sur le répertoire, et le serveur web (www-data) ne peut pas le lire. Ouvrez le répertoire en traversée — les fichiers à l'intérieur restent protégés :
Intercepte les appels système via eBPF/kernel module et détecte les anomalies en temps réel : shell depuis nginx, lecture de /etc/passwd par un processus web, écriture dans /bin, etc.
journalctl -u falco (sans sudo — via le groupe systemd-journal). Vérifiez que www-data fait partie de ce groupe — voir « Configuration de sudo » (point 2) sur la page d'installation manuelle.
/etc/passwd, écriture dans les répertoires système). Zéro événement critique par jour sur un serveur calme est un état sain.
journalctl nécessite des droits sur le journal ; pour que le tableau de bord voie les événements de façon stable, l'installation automatique active la file_output de Falco → /var/log/falco/falco.log et applique au service UMask=0022 (le log est lisible par le serveur web). Sur une nouvelle installation, il n'est pas nécessaire de le configurer manuellement.
ModSecurity — pare-feu applicatif (WAF) pour Apache ou Nginx. Il bloque les attaques au niveau applicatif : injections SQL, XSS, traversées de chemin, scanners.
IncludeOptional /etc/modsecurity/*.conf, mais le paquet ne pose que modsecurity.conf-recommended — qui ne correspond pas au masque *.conf. Sans le copier dans modsecurity.conf, SecRuleEngine reste sur Off : le module est chargé, les règles CRS sont chargées, mais le trafic n'est pas inspecté et aucun journal d'audit n'est créé. Le mode intermédiaire DetectionOnly se contente d'enregistrer les événements dans le journal sans bloquer les requêtes — le tableau de bord l'affiche en jaune.
Accès du tableau de bord au journal d'audit. Le journal /var/log/apache2/modsec_audit.log appartient à root (droits 640), l'utilisateur web ne peut pas le lire. Le tableau de bord récupère les données via un wrapper — créez-le :
SecRuleEngine sans indentation : les lignes indentées se trouvent à l'intérieur de blocs <LocationMatch>/<Directory> (par exemple la désactivation du WAF pour phpMyAdmin) et ne définissent pas le mode global.www-data, dans HestiaCP le pool du site tourne sous le propriétaire du site (par exemple admin) — vérifiez avec grep -E '^user' /etc/php/*/fpm/pool.d/monitor.example.com.conf.X-Forwarded-For. Seules les transactions ayant déclenché une règle entrent dans les statistiques : la directive SecAuditLogRelevantStatus enregistre dans le journal d'audit toute réponse 4xx/5xx, si bien que les 403/500 ordinaires y figurent aussi — le tableau de bord ne les compte pas comme des événements WAF.---RULES--- est nécessaire à la section « Toutes les règles actives » — le tableau de bord affiche non seulement les règles déclenchées, mais l'ensemble des règles CRS chargées + les règles personnalisées. Les trois chemins de la boucle for f in … sont les emplacements habituels des règles CRS et des ajouts locaux ; si votre disposition diffère (le paquet place les fichiers dans son propre répertoire, ou les règles personnalisées ne sont pas dans /etc/modsecurity/custom-rules.conf), trouvez les chemins réels avec sudo grep -rl 'IncludeOptional\|^Include ' /etc/apache2/mods-enabled/security2.conf /etc/apache2/conf-enabled/*.conf 2>/dev/null et ajoutez-les à la liste. Si le wrapper est ancien (sans cette section), la section affichera simplement l'avertissement « indisponible », le reste de la page fonctionne comme avant.
Auditd (Linux Audit Daemon) enregistre les appels système au niveau du noyau : connexions et déconnexions, commandes sudo, échecs d'authentification, modifications de fichiers. Le moniteur affiche les connexions, les tentatives échouées et les commandes sudo du jour.
ausearch (/usr/sbin/ausearch) et, si nécessaire, dans /var/log/audit/audit.log à l'aide de la commande tail. Les deux doivent figurer dans sudoers.
Surveille les services (nginx, php-fpm, mysql, etc.) et les redémarre en cas de panne. Peut envoyer des alertes par e-mail.
monit status. Dans /etc/monit/monitrc, l'interface HTTP doit être activée (bloc set httpd avec allow localhost), sinon monit status renverra une erreur.
monitrc, la ligne set httpd est commentée (par défaut sous la forme # set httpd port 2812 …). Décommentez le bloc et autorisez localhost. (2) Le httpd activé ne surveille rien en soi — Monit ne compte que ce qui est décrit par des stances check ; sans elles, la liste reste vide même si l'interface fonctionne. Configuration minimale opérationnelle :
conf.d prêt à l'emploi avec httpd sur 2812 et un jeu de vérifications — sur une nouvelle installation, aucune configuration manuelle n'est nécessaire.
PSAD analyse le journal iptables et détecte les scans de ports et les attaques réseau, en attribuant à chaque source un niveau de menace (1–5). Complète fail2ban et Suricata.
psad --Status (requis dans sudoers). Sans journalisation iptables, la page restera vide — c'est normal tant qu'aucun scan n'a eu lieu.
Mandatory Access Control limite les fichiers et ressources auxquels un programme peut accéder, même s'il est compromis. Sous Ubuntu/Debian, AppArmor est utilisé par défaut (généralement déjà installé et actif).
aa-status (requis dans sudoers). Il affiche le nombre de profils en mode enforce/complain et les processus sans profil.
« Profils chargés » supérieur à enforce + complain, c'est normal. AppArmor 4.x (Ubuntu 24.04 et plus récent) a introduit le mode unconfined : le profil est chargé dans le noyau, mais ne limite rien. Ubuntu marque ainsi des dizaines de profils pour les programmes utilisant les user namespaces (navigateurs, clients torrent et similaires). Lorsque de tels profils existent, la carte « Profils chargés » devient ambre et affiche leur nombre — par exemple unconfined: 90 pour 120 chargés et 26 en enforce. Seuls les profils en enforce protègent réellement ; sous Ubuntu 22.04 (AppArmor 3.x) ce mode n'existe pas et les chiffres concordent toujours.
unconfined qu'en toute connaissance de cause : ils ne sont pas désactivés par erreur, mais parce que cela casserait le fonctionnement des programmes eux-mêmes. Les profils en complain, c'est différent : les règles y sont déjà écrites, elles ne sont simplement pas appliquées.
debsums vérifie que les fichiers des paquets installés correspondent aux sommes de contrôle du dépôt — il détecte les binaires système altérés (en complément d'AIDE). Une analyse complète prend 1 à 2 minutes, elle est donc lancée par cron, et le tableau de bord lit le résultat depuis data/debsums/debsums.log et le classe lui-même par catégories (seuls les binaires et bibliothèques comptent).
La tâche va dans le cron root (sudo crontab -e). Le wrapper prêt à l'emploi debsums-scan.sh se place dans /usr/local/bin/ (chmod +x ; voir le récapitulatif des tâches cron) et écrit lui-même le rapport dans data/debsums/ du tableau de bord.
Le wrapper debsums-scan.sh trouve lui-même le dossier data/ du tableau de bord — inutile d'indiquer le chemin.
/etc/ (configs) et /usr/share/ (ressources) sont généralement normales sur un serveur — le tableau de bord les signale d'une couleur distincte. Les modifications de binaires et bibliothèques (/bin, /sbin, /usr/lib, etc.) sont préoccupantes — la carte « Binaires / bibliothèques » montre précisément celles-ci.
Lynis se lance manuellement ou via cron. Le rapport doit être enregistré dans le dossier data/lynis/ du projet — le moniteur lit le fichier lynis-report.dat.
lynis-scan.sh en arrière-plan directement depuis le panneau (sans attendre cron) : il affiche « Analyse… » et met à jour le rapport à la fin. Pour cela, l'utilisateur web a besoin d'une ligne sudoers pour lancer le script — l'installateur l'ajoute automatiquement dans /etc/sudoers.d/monitor. Si le panneau a été installé manuellement/plus tôt, ajoutez-la avec le même utilisateur que celui déjà indiqué dans le fichier :
Logwatch doit enregistrer les rapports quotidiens dans le dossier data/logwatch/ du projet au format .txt. Le moniteur affiche le dernier rapport et les archives.
Le moniteur réseau ne nécessite aucune installation — c'est une page intégrée au tableau de bord. Elle affiche l'état réseau du serveur à partir de sources locales :
/proc/net/dev ;ip ;ss ;journalctl -k.Les trois premières sources fonctionnent sans sudo, les interfaces, le trafic, les connexions et les ports sont donc visibles immédiatement. Le bloc « Événements du noyau » utilise journalctl -k — sa lecture passe par le groupe systemd-journal (« Configuration de sudo », pt.2), sudo n'est pas requis. Vérifier que tout est accessible à l'utilisateur web :
UFW BLOCK n'y figurent pas — elles sont sur les pages « Pare-feu UFW » et « Carte des attaques ». Un bloc vide avec une coche verte = aucun incident réseau sur la journée.
La page intégrée affiche trois éléments :
df) ; la barre passe au rouge à ≥90 % ;lsblk), réels uniquement (loop/snap masqués) ;smartctl).L'espace et la liste des périphériques fonctionnent immédiatement, sans configuration. SMART nécessite le paquet smartmontools. Le processus web n'a pas d'accès direct aux périphériques de disque ; SMART est donc relevé via cron dans le fichier data/disk/smart.txt, que le tableau de bord lit ensuite.
La tâche va dans le cron root (sudo crontab -e). Le script prêt à l'emploi smart-scan.sh se place dans /usr/local/bin/ (chmod +x ; voir le récapitulatif des tâches cron) et écrit lui-même dans data/disk/ du tableau de bord.
Le script smart-scan.sh trouve lui-même le dossier data/ du tableau de bord — pas besoin d'indiquer le chemin. En interne, lsblk -e7,11 exclut loop/cdrom.
La page affiche l'historique de la charge du serveur sur les dernières 24 heures — Load Average, occupation CPU et attente I/O, RAM/Swap, trafic réseau (réception/émission), I/O disque (lecture/écriture), remplissage du disque et des inodes, descripteurs de fichiers ouverts et connexions MySQL, plus le nombre actuel de connexions TCP et de processus.
Les données sont collectées par cron/collect_metrics.php — toutes les 5 minutes, il écrit un instantané « brut » des compteurs (/proc/loadavg, /proc/meminfo, /proc/stat, /proc/net/dev, /proc/diskstats, df/df -i, /proc/sys/fs/file-nr, SHOW GLOBAL STATUS LIKE 'Threads_connected') dans la table de base de données system_metrics ; les pourcentages et débits sont calculés par la page elle-même à partir de la différence entre deux instantanés voisins (remplissage du disque/inodes/descripteurs/connexions MySQL — valeurs instantanées, sans recalcul). Sudo n'est pas requis — les sources sont lues sans droits root. Les points de plus de 24 heures sont supprimés automatiquement à chaque écriture.
Le wrapper collect-metrics-all.sh (voir le récapitulatif des tâches cron) détecte lui-même toutes les instances du panneau installées sur le serveur et lance le cron/collect_metrics.php de chacune au nom du propriétaire du site.
Alertes de charge (section « Paramètres » → « Alertes de charge ») — en cas de dépassement du seuil CPU/RAM/disque/inodes, le panneau envoie une notification sur Telegram/Email (les mêmes canaux que le rapport quotidien — pas besoin de les activer séparément pour les alertes), et une autre — lorsque la métrique revient à la normale. Il ne spamme pas pendant le maintien du seuil : la notification suivante n'arrive qu'après un cycle « revenu à la normale → de nouveau dépassé ».
collect_metrics.php à chaque exécution (toutes les 5 minutes) — pas besoin d'un cron séparé. L'état « déjà notifié / pas encore » est stocké dans data/alerts_state.json, les seuils — dans les paramètres du panneau.
La page « Carte des attaques » détermine le pays d'après l'IP grâce à la commande geoiplookup. Sans le paquet GeoIP, les pays ne sont pas identifiés et aucun point n'apparaît sur la carte :
/usr/share/GeoIP/GeoIP.dat est lisible par tous, les résultats sont mis en cache dans tmp/geoip_cache.json. La carte elle-même (Leaflet + tuiles OpenStreetMap) se charge dans le navigateur : une connexion internet est nécessaire sur l'ordinateur où le tableau de bord est ouvert.
Deux cartes intégrées au tableau de bord qui n'affichent pas l'état « activé/désactivé » d'un outil, mais le niveau réel de protection du serveur. Aucune installation requise, lecture locale sans sudo.
Exposition externe — nombre de services à l'écoute sur toutes les interfaces (0.0.0.0/[::]) et accessibles de l'extérieur. Passe au rouge si une base de données ou un cache est exposé vers l'extérieur (MySQL, PostgreSQL, Redis, MongoDB, Memcached, Elasticsearch) — c'est une faille directe (−10 au Score de sécurité). Source : ss -tuln.
127.0.0.1 (bind-address dans la config MySQL/PostgreSQL, bind 127.0.0.1 dans Redis) ou fermez le port dans UFW.
127.0.0.1 (loopback) n'est visible que du serveur lui-même — impossible de l'atteindre de l'extérieur, même si le port est « ouvert ». C'est pourquoi Postfix sur le port 25, lié au loopback, est sûr : la configuration automatique définit inet_interfaces = loopback-only (plus un smtpd_banner neutre — ce qui lève la remarque Lynis MAIL-8818 sur la divulgation de version). La carte « Exposition externe » ne compte comme exposé que ce qui écoute sur 0.0.0.0/[::] ; les services loopback n'y figurent pas.
/etc/postfix/main.cf définissez smtpd_banner = $myhostname ESMTP (sans version ni OS) et inet_interfaces = loopback-only, puis sudo systemctl restart postfix.
Mises à jour de sécurité — nombre de correctifs de sécurité en attente d'installation et nécessité de redémarrer après une mise à jour du noyau (−5 au Score de sécurité en présence de correctifs). Source : /usr/lib/update-notifier/apt-check, fichier /var/run/reboot-required. Liste détaillée — sur la page « Mises à jour de sécurité ».
update-notifier-common). Si apt-check est absent — le moniteur compte les correctifs via apt-get -s upgrade.
Mises à jour de sécurité automatiques (unattended-upgrades) — sur la page « Mises à jour de sécurité », une carte dédiée indique si l'installation automatique des correctifs de sécurité est activée et quand elle s'est exécutée pour la dernière fois. Sudo n'est pas nécessaire — l'état est lu via apt-config dump.
La sauvegarde est votre principale assurance : perdre ses données est pire que n'importe quel piratage. Il faut deux choses — une sauvegarde du serveur/des sites et, séparément, une sauvegarde de la BDD du panneau (elle contient les utilisateurs, les clés WebAuthn, les paramètres, la licence).
Option A — HestiaCP : onglet Backup de l'utilisateur → bouton de création de sauvegarde (ou selon planification dans les paramètres du serveur). La sauvegarde inclut les sites et leurs BDD.
Option B — manuellement (cron) : dump de la BDD + archive du dossier data/ du panneau :
Mise à jour vers une nouvelle version. Faites d'abord une sauvegarde. Réimportez ensuite les fichiers de code en conservant vos données :
public/, includes/, assets/, cron/, database/, ainsi que les .htaccess racine (contrôleur frontal — le routage ne doit pas rester celui de l'ancienne version), manifest.json, sw.js ;config.php (données BDD), data/ (rapports), logs/, tmp/ (sessions et cache).SSH_FX_PERMISSION_DENIED — Permission denied. Les fichiers du panneau appartiennent à www-data (c'est ainsi qu'ils ont été réglés lors de l'installation), alors que le client SFTP se connecte sous votre propre utilisateur, qui n'a pas le droit d'écriture. Donner toute le panneau à www-data «pour que ça marche», c'est justement ce qui provoque cette erreur ; ci-dessous trois méthodes, n'importe laquelle résout le problème.
data/ (rapports), tmp/ (sessions et cache), logs/ ; ils restent la propriété de www-data. Le reste, c'est du code, et le serveur web n'en a besoin qu'en lecture, ce que lui donne le groupe www-data avec les droits 644. Bénéfice annexe : en cas de faille PHP, les fichiers du panneau ne peuvent plus être réécrits. Sur les panneaux d'hébergement (HestiaCP et similaires), la variante A n'est pas nécessaire : les fichiers du site appartiennent déjà au compte sous lequel vous vous connectez en SFTP, et le serveur web les lit via le groupe.
chmod ultérieur sur les fichiers réinitialise le masque ACL, et l'accès disparaît silencieusement. Si après une «remise en ordre des droits» le transfert bute de nouveau sur Permission denied — relancez les deux commandes setfacl.
2 de la variante C, c'est setgid : les fichiers transférés par SFTP restent dans le groupe www-data, sinon le panneau ne pourra pas les réécrire. Après la variante C, reconnectez-vous dans FileZilla — le nouveau groupe ne prend effet qu'à une nouvelle connexion. Vérification : id deploy (le groupe www-data doit apparaître) et ls -ld /path/to/monitor (drwxrwsr-x — la lettre s signifie que setgid est activé).
Migration vers un autre serveur :
config.php, data/.mysqldump sur l'ancien → import sur le nouveau ; corrigez les données BDD dans config.php.adm, tâches cron.Si la connexion échoue, tout se répare directement dans la BDD depuis le serveur. Ouvrez la BDD (le nom se trouve dans config.php) :
Clé WebAuthn perdue (second facteur impossible) — désactivez la 2FA, connectez-vous par mot de passe, enregistrez une nouvelle clé :
Mot de passe oublié — définissez un nouveau hachage (générez-le sur le serveur, puis insérez-le) :
Vous vous êtes bloqué par le filtre IP — désactivez la restriction :
sudo mysql sur le serveur, ou phpMyAdmin / la section BDD du panneau d'hébergement. Après la récupération, réactivez WebAuthn et le filtre IP.
Le récapitulatif des tâches se trouve dans le cron root du serveur (ajoutées via sudo crontab -e). Ne gardez que les lignes des outils que vous utilisez ; ajustez les chemins à votre serveur.
sudo crontab -l et que le service cron est actif.
TIMEZONE de config.php. La constante TIMEZONE n'influe que sur PHP (affichage des dates par le tableau de bord), mais le démon cron lance les tâches selon l'heure système de l'OS. Si le fuseau du serveur ne correspond pas au vôtre, le rapport « 08:00 » arrivera à la mauvaise heure. Exemple : le serveur est dans un autre fuseau (Europe/London, UTC+1), et vous à Paris (UTC+2) → le rapport « 08:00 » arrivera à 09:00 chez vous. Vérifiez et, au besoin, alignez le fuseau du système sur le vôtre :
0 8 * * * se déclenchera à 08:00 heure locale. Sinon il faudrait décaler cron lui-même, mais au passage à l'heure d'hiver/été le décalage se briserait de nouveau — mieux vaut donc régler le fuseau du système.
crontab.txt) se trouvent dans le dossier system/ à côté du projet, hors de public_html. Ce n'est pas une partie du site — inutile de les téléverser dans la racine web ; placez-les sur le serveur aux chemins système (comme dans le crontab ci-dessus) :
lynis-scan.sh → /usr/local/bin/ (chmod +x) — lance lynis audit system, pose le drapeau /tmp/lynis-running pendant le scan et copie lynis-report.dat dans data/lynis/ du tableau de bord ;logwatch_daily.sh → /usr/local/bin/ (chmod +x) — génère le rapport quotidien Logwatch (sshd, fail2ban, sudo, postfix) dans data/logwatch/ ;smart-scan.sh → /usr/local/bin/ (chmod +x) — relève l'état des disques (smartctl) dans data/disk/ ;debsums-scan.sh → /usr/local/bin/ (chmod +x) — vérifie l'intégrité des paquets (debsums) dans data/debsums/ ;clamav-scan.sh → /usr/local/bin/ (chmod +x) — scan antivirus ClamAV sur les chemins à risque (web, home, temp) ; écrit le récapitulatif dans /var/log/clamav/scan.log, d'où la page ClamAV le lit (ligne 01:30 du crontab ci-dessus) ;load-ipsum.sh → /usr/local/bin/ (chmod +x) — met à jour l'ensemble ipset ipsum (level 1) sur place, sans casser les règles actives du pare-feu (ligne 04:00 dans le crontab ci-dessus);daily-report-all.sh → /usr/local/bin/ (chmod +x) — lance le rapport cron/daily_report.php du tableau de bord (ligne 08:00 du crontab ci-dessus) ;daily_report.php — déjà inclus dans le tableau de bord (cron/daily_report.php), lancé via daily-report-all.sh, inutile de l'installer séparément ;collect-metrics-all.sh → /usr/local/bin/ (chmod +x) — lance cron/collect_metrics.php du tableau de bord (page « Performances », ligne */5 du crontab ci-dessus) ; collect_metrics.php est déjà inclus dans le tableau de bord, inutile de l'installer séparément ;crontab.txt (system/cron/) — exemple de tâches ; saisissez les lignes voulues via sudo crontab -e./usr/local/bin/. Impossible d'y écrire directement depuis FileZilla — le répertoire appartient à root, et le client SFTP recevra SSH_FX_PERMISSION_DENIED. Voici la marche à suivre : d'abord téléverser le fichier dans /tmp (où tout le monde peut écrire), puis le déplacer à sa place en une seule commande :
/tmp à la racine du serveur — pas /var/tmp ni tmp/ à l'intérieur du tableau de bord lui-même (ce dernier appartient à www-data et est fermé à votre utilisateur). Dans l'arborescence FileZilla, /tmp est une branche de premier niveau, à côté de var, et non à l'intérieur de celle-ci.
/usr/local/bin/, log — /var/log/arciveo-cron.log) — rien à faire manuellement.
/home/*/web/*/public_html et /var/www/*, et déposent les rapports dans leur data/. Si le tableau de bord se trouve à un autre chemin — ajoutez-le à la ligne for app in … dans les scripts, sinon les rapports Lynis/SMART/debsums/Logwatch n'arriveront pas au tableau de bord.
logs/cron.log est créé en premier par le cron root — il appartiendra à root, et l'onglet « Journal cron » du tableau de bord ne pourra ni le lire ni le vider. Créez le fichier à l'avance au nom de l'utilisateur web (propriétaire du répertoire du site ; sous HestiaCP c'est le compte, p. ex. admin) — le cron root ne fera alors qu'y ajouter, sans changer le propriétaire :
stat -c %U /path/to/monitor.
sudo crontab -e), sinon elle s'exécutera deux fois.
sudo crontab (ce serait une escalade directe vers root pour quiconque accède à la session du tableau de bord), mais d'un script étroit à deux commandes (list/set) qui ne touche que son propre bloc entre les commentaires de service. Installez-le une fois :
www-data — vérifiez sous quel compte tourne le pool PHP-FPM du site (ps -o user= -C php-fpm), et indiquez-le dans la ligne sudoers.
public/crontab_monitor.php a été chargé par FTP/SFTP sous un autre utilisateur système (par exemple root) que le reste des fichiers du site, le serveur web ne pourra pas le lire. Comparez le propriétaire et les droits avec un fichier voisin et alignez-les :
Le moniteur détecte la présence des outils via dpkg-query — la base de paquets APT. Si un outil n'est pas installé via apt (manuellement, depuis snap ou depuis les sources), dpkg ne le voit pas.
Erreur 500 — vérifiez les journaux de PHP, nginx et du moniteur lui-même :
www-data, mais sous le compte de l'utilisateur (par exemple admin — propriétaire du répertoire du site). Toutes les règles sudo et l'appartenance aux groupes (adm, systemd-journal) doivent être définies pour cet utilisateur, sinon les modules afficheront « Inactif / 0 » alors que les services fonctionnent. Pour connaître l'utilisateur PHP réel : ps -o user= -C php-fpm | sort -u ou le propriétaire du répertoire du site stat -c '%U' /path/to/monitor. Ensuite, dans toutes les commandes ci-dessous, remplacez www-data par cet utilisateur. L'installation automatique détecte l'utilisateur web elle-même et configure sudoers pour lui.
Les données ne s'affichent pas — il s'agit presque toujours de droits sudo non définis. Vérifiez la commande précise en tant qu'utilisateur web (remplacez www-data par le vôtre). L'option -n = sans mot de passe, comme PHP — si un mot de passe est demandé, c'est qu'il n'y a pas de règle dans sudoers :
sudo aa-status affiche des profils dans le terminal, mais la page « AppArmor » indique « Inactif »). Cause : l'utilisateur web n'a pas de droit sudo sur la commande de ce module. Vérifiez-la dans la liste ci-dessus : si un mot de passe est demandé — ajoutez la ligne manquante dans /etc/sudoers.d/monitor (« Configuration de sudo »). Commandes « nouvelles » fréquentes : /usr/sbin/aa-status (MAC), /usr/sbin/psad --Status (PSAD).
apache2ctl, ausearch, aa-status ou ss ne soit pas autorisé, ou que l'utilisateur web ne soit pas dans les groupes adm/systemd-journal (c'est de là que sont lus les journaux fail2ban/auth/modsec et journalctl — Falco et les événements du noyau).
Symptôme : les données existent sur le serveur (visibles via shell), mais la page affiche « aucune donnée » ou un statut incorrect — par exemple AIDE indique « Non initialisée » alors que la base est créée.
La cause est open_basedir : de nombreux panneaux et hébergeurs restreignent le pool PHP-FPM au répertoire du domaine, si bien que les fonctions PHP file_exists(), file_get_contents(), filemtime() sont bloquées sur les chemins système (/var/lib/aide, /var/log, /proc…). Le moniteur contourne cela en lisant ces chemins avec les commandes système standard (cat, test, stat).
open_basedir. La bonne solution est la lecture par commandes système (déjà en place pour AIDE et le moniteur réseau). Étendre open_basedir à /var, /proc est inutile et moins sûr.
Le monitor vérifie les certificats en se connectant directement aux domaines via le port 443. Si le domaine est inaccessible depuis le serveur lui-même ou si le port est fermé par le pare-feu, la vérification échouera.
/etc/nginx/sites-enabled/, /etc/nginx/conf.d/) et Apache (/etc/apache2/sites-enabled/) ainsi que l'hôte actuel depuis HTTP_HOST.
Le moniteur se connecte à MySQL avec l'utilisateur défini dans config.php, qui n'a accès qu'à sa propre base. MySQL n'affiche dans information_schema que les bases sur lesquelles l'utilisateur a des privilèges — les autres restent donc invisibles.
Pour que le moniteur voie toutes les BDD, accordez à cet utilisateur un droit en lecture seule (une seule fois en tant que root ; remplacez par le nom d'utilisateur de config.php) :
sudo mysql : la liste des bases passe par sa propre connexion PDO.
PostgreSQL requiert un accès de niveau utilisateur postgres, dont ne dispose pas l'utilisateur web du panneau. Ouvrir un large sudo psql depuis PHP n'est pas sûr — à la place, le panneau appelle un wrapper restreint sans paramètres, qui affiche uniquement la version, le nombre de connexions et la liste des bases avec leurs tailles. Créez-le :
monitor-pgstat de sudoers (étape 13 de l'installation manuelle) et ne créez pas le script : la carte PostgreSQL restera simplement inactive.
Le tableau de bord montre ce qui se passe ; ci-dessous, que faire dans les cas courants. Principe général : ne pas paniquer, comparer avec l'activité légitime (vos actions, mises à jour, sauvegardes), et réagir selon la gravité.
ignoreip./etc, hors /usr/share) — falsification potentielle. Vérifiez le paquet : debsums PACKAGE_NAME, en cas de doute réinstallez-le (apt install --reinstall).127.0.0.1 ou fermez le port dans UFW. C'est une vraie faille.certbot renew ou les réglages dans le tableau de bord).sudo apt update && sudo apt upgrade ; après une mise à jour du noyau, redémarrez le serveur.