Fix: harmonize Firewall and Fail2ban status, decouple strict mode and fix installer jail generation

This commit is contained in:
sorcier committed 2026-11-02 10:59:46 +01:00
1 parent 8bbeb9caae
commit 8b57981b1b
6 files changed
+69 -121

No files matched your search

+17 -48
View File
@@ -183,7 +183,7 @@ setfacl -R -d -m u:www-data:rwx,g:asterisk:rwx /etc/asterisk 2>/dev/null || true
# Droits sudoers pour l'interface web (www-data) # Droits sudoers pour l'interface web (www-data)
cat << 'EOF' > /etc/sudoers.d/nexus-pbx cat << 'EOF' > /etc/sudoers.d/nexus-pbx
# Privilèges spécifiques NexusPBX pour l'utilisateur Web www-data # Privilèges spécifiques NexusPBX pour l'utilisateur Web www-data
www-data ALL=(ALL) NOPASSWD: /usr/sbin/asterisk, /usr/sbin/nginx, /usr/bin/systemctl, /usr/bin/fail2ban-client, /var/www/nexus-pbx/scripts/nexus-firewall, /usr/bin/certbot, /usr/sbin/nft, /usr/sbin/iptables www-data ALL=(ALL) NOPASSWD: /usr/sbin/asterisk, /usr/sbin/nginx, /usr/bin/systemctl, /usr/bin/fail2ban-client, /bin/fail2ban-client, /var/www/nexus-pbx/scripts/nexus-firewall, /usr/bin/certbot, /usr/sbin/nft, /usr/sbin/iptables
EOF EOF
chmod 0440 /etc/sudoers.d/nexus-pbx chmod 0440 /etc/sudoers.d/nexus-pbx
@@ -355,18 +355,7 @@ $st = $db->query("SELECT admin_https_port, certbot_strict_port80 FROM settings W
App\FirewallManager::applyNginxConfig((int)($st["admin_https_port"] ?? 8443), (int)($st["certbot_strict_port80"] ?? 0)); App\FirewallManager::applyNginxConfig((int)($st["admin_https_port"] ?? 8443), (int)($st["certbot_strict_port80"] ?? 0));
' '
# Filtre Fail2ban Asterisk & Nexus-Web # Filtre Fail2ban pour l'interface Nexus-Web
cat << 'EOF' > /etc/fail2ban/filter.d/asterisk.conf
[INCLUDES]
before = common.conf
[Definition]
failregex = ^(%(__prefix_line)s|\[\]\s*)*(?:NOTICE|SECURITY)\[\d+\]:? (?:\S+: )?(?:Registration from |Call from |Invalid password for |Sending fake auth challenge to |No matching endpoint found for )?'<HOST>'(?::\d+)?
^(%(__prefix_line)s|\[\]\s*)*SECURITY\[\d+\]:? (?:\S+: )?SecurityEvent="(?:FailedACL|InvalidAccountID|ChallengeResponseFailed|InvalidPassword|AuthFailed)"(?:.*?)RemoteAddress="IPV[46]/(?:UDP|TCP|TLS)/<HOST>/\d+"
ignoreregex =
EOF
chmod 0644 /etc/fail2ban/filter.d/asterisk.conf
cat << 'EOF' > /etc/fail2ban/filter.d/nexus-web.conf cat << 'EOF' > /etc/fail2ban/filter.d/nexus-web.conf
[Definition] [Definition]
failregex = ^.*\[NEXUS-WEB-AUTH-FAIL\]:\s*<HOST>.*$ failregex = ^.*\[NEXUS-WEB-AUTH-FAIL\]:\s*<HOST>.*$
@@ -374,41 +363,21 @@ ignoreregex =
EOF EOF
chmod 0644 /etc/fail2ban/filter.d/nexus-web.conf chmod 0644 /etc/fail2ban/filter.d/nexus-web.conf
# Jails Fail2ban # Génération automatique et centralisée de /etc/fail2ban/jail.local (Source unique FirewallManager)
cat << 'EOF' > /etc/fail2ban/jail.local php -r '
[DEFAULT] require_once "/var/www/nexus-pbx/src/Database.php";
bantime = 3600 require_once "/var/www/nexus-pbx/src/FirewallManager.php";
findtime = 600 $st = App\FirewallManager::getSettings();
maxretry = 3 App\FirewallManager::generateJailLocal(
usedns = no $st["fail2ban_whitelist_ips"],
ignoreip = 127.0.0.1/8 ::1 10.0.0.0/8 172.16.0.0/12 192.168.0.0/16 (int)$st["fail2ban_sip_maxretry"],
(int)$st["fail2ban_sip_findtime"],
[asterisk] (int)$st["fail2ban_sip_bantime"],
enabled = true (int)$st["fail2ban_web_maxretry"],
port = 5060,5061 (int)$st["fail2ban_web_bantime"],
protocol = udp (int)$st["admin_https_port"]
filter = asterisk );
logpath = /var/log/asterisk/messages '
action = %(banaction)s[name=%(__name__)s, bantime="%(bantime)s", port="%(port)s", protocol="%(protocol)s", chain="%(chain)s"]
maxretry = 3
bantime = 3600
[nginx-http-auth]
enabled = true
port = http,https,8443
logpath = /var/log/nginx/*error.log
maxretry = 5
bantime = 3600
[nexus-web]
enabled = true
port = http,https,8443
filter = nexus-web
logpath = /var/log/nexus_security.log
maxretry = 3
findtime = 600
bantime = 3600
EOF
chown root:asterisk /etc/fail2ban/jail.local chown root:asterisk /etc/fail2ban/jail.local
chmod 0664 /etc/fail2ban/jail.local chmod 0664 /etc/fail2ban/jail.local
+5 -5
View File
@@ -417,7 +417,7 @@ function renderDashboardMetrics() {
const fwStatus = document.getElementById('dash-fw-status'); const fwStatus = document.getElementById('dash-fw-status');
const fwDetail = document.getElementById('dash-fw-detail'); const fwDetail = document.getElementById('dash-fw-detail');
const isFwActive = Boolean(sec.firewall_enabled || sec.strict_port80) && Boolean(sec.fail2ban_running); const isFwActive = Boolean(sec.firewall_enabled);
if (isFwActive) { if (isFwActive) {
if (fwDot) fwDot.className = 'w-2 h-2 rounded-full bg-emerald-400 shadow-sm shadow-emerald-500/50'; if (fwDot) fwDot.className = 'w-2 h-2 rounded-full bg-emerald-400 shadow-sm shadow-emerald-500/50';
if (fwStatus) { if (fwStatus) {
@@ -431,7 +431,7 @@ function renderDashboardMetrics() {
fwStatus.textContent = 'Inactif'; fwStatus.textContent = 'Inactif';
fwStatus.className = 'text-sm font-extrabold text-slate-400 mt-1'; fwStatus.className = 'text-sm font-extrabold text-slate-400 mt-1';
} }
if (fwDetail) fwDetail.textContent = !sec.fail2ban_running ? 'Moteur Fail2ban arrêté' : 'Tout le trafic autorisé'; if (fwDetail) fwDetail.textContent = 'Tout le trafic autorisé';
} }
const f2bDot = document.getElementById('dash-f2b-dot'); const f2bDot = document.getElementById('dash-f2b-dot');
@@ -445,7 +445,7 @@ function renderDashboardMetrics() {
f2bStatus.className = 'text-sm font-extrabold text-emerald-400 mt-1'; f2bStatus.className = 'text-sm font-extrabold text-emerald-400 mt-1';
} }
const activeJailCount = Object.keys(sec.jails || {}).length; const activeJailCount = Object.keys(sec.jails || {}).length;
if (f2bDetail) f2bDetail.textContent = `${activeJailCount} prison(s) active(s)`; if (f2bDetail) f2bDetail.textContent = activeJailCount > 0 ? `${activeJailCount} prison(s) active(s)` : 'Surveillance active';
} else { } else {
if (f2bDot) f2bDot.className = 'w-2 h-2 rounded-full bg-rose-500'; if (f2bDot) f2bDot.className = 'w-2 h-2 rounded-full bg-rose-500';
if (f2bStatus) { if (f2bStatus) {
@@ -3797,7 +3797,7 @@ document.addEventListener('DOMContentLoaded', () => {
if (btn) btn.disabled = true; if (btn) btn.disabled = true;
const payload = { const payload = {
firewall_enabled: f.elements['firewall_enabled']?.checked ? 1 : (f.elements['certbot_strict_port80']?.checked ? 1 : 0), firewall_enabled: f.elements['firewall_enabled']?.checked ? 1 : 0,
admin_https_port: Number(f.elements['admin_https_port']?.value || 8443), admin_https_port: Number(f.elements['admin_https_port']?.value || 8443),
certbot_strict_port80: f.elements['certbot_strict_port80']?.checked ? 1 : 0, certbot_strict_port80: f.elements['certbot_strict_port80']?.checked ? 1 : 0,
fail2ban_sip_maxretry: Number(f.elements['fail2ban_sip_maxretry']?.value || 3), fail2ban_sip_maxretry: Number(f.elements['fail2ban_sip_maxretry']?.value || 3),
@@ -4776,7 +4776,7 @@ function renderFirewall() {
form.elements['certbot_strict_port80'].checked = Number(s.certbot_strict_port80) === 1; form.elements['certbot_strict_port80'].checked = Number(s.certbot_strict_port80) === 1;
} }
if (form.elements['firewall_enabled']) { if (form.elements['firewall_enabled']) {
form.elements['firewall_enabled'].checked = (Number(s.firewall_enabled) === 1 || Number(s.certbot_strict_port80) === 1); form.elements['firewall_enabled'].checked = Number(s.firewall_enabled) === 1;
} }
if (form.elements['fail2ban_sip_maxretry']) { if (form.elements['fail2ban_sip_maxretry']) {
form.elements['fail2ban_sip_maxretry'].value = s.fail2ban_sip_maxretry || 3; form.elements['fail2ban_sip_maxretry'].value = s.fail2ban_sip_maxretry || 3;
+4 -4
View File
@@ -635,11 +635,11 @@ $currentUser = Auth::getUsername();
<!-- Statut Pare-feu --> <!-- Statut Pare-feu -->
<div class="p-3 rounded-xl bg-anthracite-950 border border-anthracite-700"> <div class="p-3 rounded-xl bg-anthracite-950 border border-anthracite-700">
<div class="flex items-center justify-between"> <div class="flex items-center justify-between">
<span class="text-[10px] text-slate-400 font-bold uppercase">Pare-feu Strict</span> <span class="text-[10px] text-slate-400 font-bold uppercase">Filtrage & Pare-feu</span>
<span id="dash-fw-dot" class="w-2 h-2 rounded-full bg-slate-500"></span> <span id="dash-fw-dot" class="w-2 h-2 rounded-full bg-emerald-400 shadow-sm shadow-emerald-500/50"></span>
</div> </div>
<div id="dash-fw-status" class="text-sm font-extrabold text-white mt-1">Inactif</div> <div id="dash-fw-status" class="text-sm font-extrabold text-emerald-400 mt-1">Actif</div>
<div id="dash-fw-detail" class="text-[10px] text-slate-400 truncate mt-0.5">Filtrage strict non actif</div> <div id="dash-fw-detail" class="text-[10px] text-slate-400 truncate mt-0.5">Port HTTPS : 8443</div>
</div> </div>
<!-- Statut Fail2ban --> <!-- Statut Fail2ban -->
+17 -47
View File
@@ -28,18 +28,7 @@ chmod 0664 /var/log/asterisk/messages /var/log/asterisk/security.log 2>/dev/null
chown www-data:asterisk /var/log/nexus_security.log 2>/dev/null || true chown www-data:asterisk /var/log/nexus_security.log 2>/dev/null || true
chmod 0664 /var/log/nexus_security.log 2>/dev/null || true chmod 0664 /var/log/nexus_security.log 2>/dev/null || true
echo "-> Filtres Fail2ban Asterisk & Nexus-Web..." echo "-> Filtres Fail2ban Nexus-Web..."
cat << 'EOF' > /etc/fail2ban/filter.d/asterisk.conf
[INCLUDES]
before = common.conf
[Definition]
failregex = ^(%(__prefix_line)s|\[\]\s*)*(?:NOTICE|SECURITY)\[\d+\]:? (?:\S+: )?(?:Registration from |Call from |Invalid password for |Sending fake auth challenge to |No matching endpoint found for )?'<HOST>'(?::\d+)?
^(%(__prefix_line)s|\[\]\s*)*SECURITY\[\d+\]:? (?:\S+: )?SecurityEvent="(?:FailedACL|InvalidAccountID|ChallengeResponseFailed|InvalidPassword|AuthFailed)"(?:.*?)RemoteAddress="IPV[46]/(?:UDP|TCP|TLS)/<HOST>/\d+"
ignoreregex =
EOF
chmod 0644 /etc/fail2ban/filter.d/asterisk.conf
cat << 'EOF' > /etc/fail2ban/filter.d/nexus-web.conf cat << 'EOF' > /etc/fail2ban/filter.d/nexus-web.conf
[Definition] [Definition]
failregex = ^.*\[NEXUS-WEB-AUTH-FAIL\]:\s*<HOST>.*$ failregex = ^.*\[NEXUS-WEB-AUTH-FAIL\]:\s*<HOST>.*$
@@ -47,40 +36,21 @@ ignoreregex =
EOF EOF
chmod 0644 /etc/fail2ban/filter.d/nexus-web.conf chmod 0644 /etc/fail2ban/filter.d/nexus-web.conf
cat << 'EOF' > /etc/fail2ban/jail.local echo "-> Génération et application de /etc/fail2ban/jail.local..."
[DEFAULT] php -r '
bantime = 3600 require_once "/var/www/nexus-pbx/src/Database.php";
findtime = 600 require_once "/var/www/nexus-pbx/src/FirewallManager.php";
maxretry = 3 $st = App\FirewallManager::getSettings();
usedns = no App\FirewallManager::generateJailLocal(
ignoreip = 127.0.0.1/8 ::1 10.0.0.0/8 172.16.0.0/12 192.168.0.0/16 $st["fail2ban_whitelist_ips"],
(int)$st["fail2ban_sip_maxretry"],
[asterisk] (int)$st["fail2ban_sip_findtime"],
enabled = true (int)$st["fail2ban_sip_bantime"],
port = 5060,5061 (int)$st["fail2ban_web_maxretry"],
protocol = udp (int)$st["fail2ban_web_bantime"],
filter = asterisk (int)$st["admin_https_port"]
logpath = /var/log/asterisk/messages );
action = %(banaction)s[name=%(__name__)s, bantime="%(bantime)s", port="%(port)s", protocol="%(protocol)s", chain="%(chain)s"] ' 2>/dev/null || true
maxretry = 3
bantime = 3600
[nginx-http-auth]
enabled = true
port = http,https,8443
logpath = /var/log/nginx/*error.log
maxretry = 5
bantime = 3600
[nexus-web]
enabled = true
port = http,https,8443
filter = nexus-web
logpath = /var/log/nexus_security.log
maxretry = 3
findtime = 600
bantime = 3600
EOF
echo "-> Droits applicatifs et ACL POSIX (/etc/asterisk et /var/www/nexus-pbx)..." echo "-> Droits applicatifs et ACL POSIX (/etc/asterisk et /var/www/nexus-pbx)..."
usermod -aG asterisk www-data 2>/dev/null || true usermod -aG asterisk www-data 2>/dev/null || true
@@ -112,7 +82,7 @@ chmod 0664 /etc/fail2ban/jail.local /etc/nginx/sites-available/nexus-pbx 2>/dev/
setfacl -m u:www-data:rw /etc/fail2ban/jail.local /etc/nginx/sites-available/nexus-pbx 2>/dev/null || true setfacl -m u:www-data:rw /etc/fail2ban/jail.local /etc/nginx/sites-available/nexus-pbx 2>/dev/null || true
cat << 'EOF' > /etc/sudoers.d/nexus-pbx cat << 'EOF' > /etc/sudoers.d/nexus-pbx
www-data ALL=(ALL) NOPASSWD: /usr/sbin/asterisk, /usr/sbin/nginx, /usr/bin/systemctl, /usr/bin/fail2ban-client, /var/www/nexus-pbx/scripts/nexus-firewall, /usr/bin/certbot, /usr/sbin/nft, /usr/sbin/iptables www-data ALL=(ALL) NOPASSWD: /usr/sbin/asterisk, /usr/sbin/nginx, /usr/bin/systemctl, /usr/bin/fail2ban-client, /bin/fail2ban-client, /var/www/nexus-pbx/scripts/nexus-firewall, /usr/bin/certbot, /usr/sbin/nft, /usr/sbin/iptables
EOF EOF
chmod 0440 /etc/sudoers.d/nexus-pbx chmod 0440 /etc/sudoers.d/nexus-pbx
+23 -14
View File
@@ -73,16 +73,22 @@ class FirewallManager
$settings = self::getSettings(); $settings = self::getSettings();
// 1. Détection service Fail2ban (avec timeout strict de 2s anti-blocage) // 1. Détection service Fail2ban (Statut Systemd + vérification socket ping)
exec('timeout 2 sudo /usr/bin/fail2ban-client ping 2>&1', $pingOut, $pingCode); $sysActive = trim((string)@shell_exec('systemctl is-active fail2ban 2>/dev/null')) === 'active';
$isRunning = ($pingCode === 0 && str_contains(implode(' ', $pingOut), 'Server replied: pong')); $pingCode = -1;
$pingOut = [];
if ($sysActive) {
exec('timeout 2 sudo -n /usr/bin/fail2ban-client ping 2>&1', $pingOut, $pingCode);
}
$pingOk = ($pingCode === 0 && str_contains(implode(' ', $pingOut), 'Server replied: pong'));
$isRunning = $sysActive || $pingOk;
$jails = []; $jails = [];
$bannedList = []; $bannedList = [];
$totalBannedCount = 0; $totalBannedCount = 0;
if ($isRunning) { if ($isRunning && $pingOk) {
exec('timeout 2 sudo /usr/bin/fail2ban-client status 2>&1', $statOut); exec('timeout 2 sudo -n /usr/bin/fail2ban-client status 2>&1', $statOut);
$statStr = implode("\n", $statOut); $statStr = implode("\n", $statOut);
// Extraction des prisons actives // Extraction des prisons actives
@@ -138,7 +144,7 @@ class FirewallManager
$unbannedFrom = []; $unbannedFrom = [];
if ($jail !== '' && $jail !== 'all') { if ($jail !== '' && $jail !== 'all') {
$cmd = "timeout 2 sudo /usr/bin/fail2ban-client set " . escapeshellarg($jail) . " unbanip " . escapeshellarg($ip) . " 2>&1"; $cmd = "timeout 2 sudo -n /usr/bin/fail2ban-client set " . escapeshellarg($jail) . " unbanip " . escapeshellarg($ip) . " 2>&1";
exec($cmd, $out, $code); exec($cmd, $out, $code);
if ($code === 0) { if ($code === 0) {
$unbannedFrom[] = $jail; $unbannedFrom[] = $jail;
@@ -146,7 +152,7 @@ class FirewallManager
} else { } else {
// Débannir de toutes les prisons connues // Débannir de toutes les prisons connues
foreach (['asterisk', 'nexus-web', 'sshd'] as $j) { foreach (['asterisk', 'nexus-web', 'sshd'] as $j) {
$cmd = "timeout 2 sudo /usr/bin/fail2ban-client set " . escapeshellarg($j) . " unbanip " . escapeshellarg($ip) . " 2>&1"; $cmd = "timeout 2 sudo -n /usr/bin/fail2ban-client set " . escapeshellarg($j) . " unbanip " . escapeshellarg($ip) . " 2>&1";
exec($cmd, $out, $code); exec($cmd, $out, $code);
if ($code === 0) { if ($code === 0) {
$unbannedFrom[] = $j; $unbannedFrom[] = $j;
@@ -175,7 +181,7 @@ class FirewallManager
} }
$jail = trim($jail) ?: 'asterisk'; $jail = trim($jail) ?: 'asterisk';
$cmd = "timeout 2 sudo /usr/bin/fail2ban-client set " . escapeshellarg($jail) . " banip " . escapeshellarg($ip) . " 2>&1"; $cmd = "timeout 2 sudo -n /usr/bin/fail2ban-client set " . escapeshellarg($jail) . " banip " . escapeshellarg($ip) . " 2>&1";
exec($cmd, $out, $code); exec($cmd, $out, $code);
@unlink('/tmp/nexus_fw_status_cache.json'); @unlink('/tmp/nexus_fw_status_cache.json');
@@ -195,7 +201,7 @@ class FirewallManager
$db = Database::getConnection(); $db = Database::getConnection();
$strictPort80 = !empty($data['certbot_strict_port80']) ? 1 : 0; $strictPort80 = !empty($data['certbot_strict_port80']) ? 1 : 0;
$firewallEnabled = (!empty($data['firewall_enabled']) || $strictPort80 === 1) ? 1 : 0; $firewallEnabled = isset($data['firewall_enabled']) ? (!empty($data['firewall_enabled']) ? 1 : 0) : 1;
$adminPort = max(1, min(65535, (int)($data['admin_https_port'] ?? 8443))); $adminPort = max(1, min(65535, (int)($data['admin_https_port'] ?? 8443)));
$sipMaxRetry = max(1, min(20, (int)($data['fail2ban_sip_maxretry'] ?? 3))); $sipMaxRetry = max(1, min(20, (int)($data['fail2ban_sip_maxretry'] ?? 3)));
$sipFindTime = max(60, min(86400, (int)($data['fail2ban_sip_findtime'] ?? 600))); $sipFindTime = max(60, min(86400, (int)($data['fail2ban_sip_findtime'] ?? 600)));
@@ -253,8 +259,11 @@ class FirewallManager
$adminPort $adminPort
); );
// 3. Rechargement de Fail2ban (timeout 3s) // 3. Rechargement / Redémarrage propre de Fail2ban
exec('timeout 3 sudo /usr/bin/fail2ban-client reload 2>&1', $f2bOut, $f2bCode); exec('timeout 3 sudo -n /usr/bin/fail2ban-client reload 2>&1', $f2bOut, $f2bCode);
if ($f2bCode !== 0) {
exec('timeout 5 sudo -n /usr/bin/systemctl restart fail2ban 2>&1');
}
// 4. Mise à jour de la configuration Nginx // 4. Mise à jour de la configuration Nginx
self::applyNginxConfig($adminPort, $strictPort80); self::applyNginxConfig($adminPort, $strictPort80);
@@ -482,18 +491,18 @@ EOF;
@chmod(self::NGINX_CONF_PATH, 0664); @chmod(self::NGINX_CONF_PATH, 0664);
// Test de syntaxe // Test de syntaxe
exec('sudo /usr/sbin/nginx -t 2>&1', $tOut, $tCode); exec('sudo -n /usr/sbin/nginx -t 2>&1', $tOut, $tCode);
if ($tCode !== 0) { if ($tCode !== 0) {
throw new RuntimeException("Erreur de syntaxe Nginx : " . implode("\n", $tOut)); throw new RuntimeException("Erreur de syntaxe Nginx : " . implode("\n", $tOut));
} }
// Rechargement Nginx sans coupure // Rechargement Nginx sans coupure
exec('sudo /usr/bin/systemctl reload nginx 2>&1'); exec('sudo -n /usr/bin/systemctl reload nginx 2>&1');
} }
private static function getJailDetails(string $jail): array private static function getJailDetails(string $jail): array
{ {
exec('timeout 2 sudo /usr/bin/fail2ban-client status ' . escapeshellarg($jail) . ' 2>&1', $out); exec('timeout 2 sudo -n /usr/bin/fail2ban-client status ' . escapeshellarg($jail) . ' 2>&1', $out);
$str = implode("\n", $out); $str = implode("\n", $out);
$currentlyFailed = 0; $currentlyFailed = 0;
+3 -3
View File
@@ -135,10 +135,10 @@ class SystemMetrics
$nginxActive = ($lines[1] ?? '') === 'active'; $nginxActive = ($lines[1] ?? '') === 'active';
$phpActive = ($lines[2] ?? '') === 'active'; $phpActive = ($lines[2] ?? '') === 'active';
$f2bActive = ($lines[3] ?? '') === 'active' || !empty($fwStatus['is_running']); $f2bActive = ($lines[3] ?? '') === 'active' || !empty($fwStatus['is_running']);
$isF2bRunning = !empty($fwStatus['is_running']) && (($lines[3] ?? '') === 'active'); $fwEnabled = !empty($fwStatus['settings']['firewall_enabled']) && $nginxActive;
$fwEnabled = !empty($fwStatus['settings']['firewall_enabled']) && $isF2bRunning;
$adminPort = $fwStatus['settings']['admin_https_port'] ?? 8443; $adminPort = $fwStatus['settings']['admin_https_port'] ?? 8443;
$isStrictPort80 = !empty($fwStatus['settings']['certbot_strict_port80']);
return [ return [
[ [
@@ -180,7 +180,7 @@ class SystemMetrics
[ [
'id' => 'firewall', 'id' => 'firewall',
'name' => 'Pare-feu & Filtrage', 'name' => 'Pare-feu & Filtrage',
'desc' => $fwEnabled ? 'Règles actives & Isolation 80' : 'Inactif (Tout autoriser)', 'desc' => $fwEnabled ? ($isStrictPort80 ? 'Mode Strict (Port 80 Isolé)' : 'Filtrage Nginx & Ports Actif') : 'Inactif (Tout autoriser)',
'port' => 'Filtrage IP & Nginx', 'port' => 'Filtrage IP & Nginx',
'active' => $fwEnabled, 'active' => $fwEnabled,
'status_text' => $fwEnabled ? 'Filtrage Actif' : 'Inactif', 'status_text' => $fwEnabled ? 'Filtrage Actif' : 'Inactif',