Add sudo prefix for firewall cmds; sudoers rule in install.sh

www-data needs root to run ufw and fail2ban-client. Added sudo prefix
in fw_exec() and a /etc/sudoers.d/novacpx-firewall file (NOPASSWD for
specific firewall commands only). install.sh now creates this file on
fresh installs.

Co-Authored-By: Claude Sonnet 4.6 <noreply@anthropic.com>
This commit is contained in:
2026-06-07 16:05:15 +00:00
parent 910427c46c
commit a0cd7d925e
2 changed files with 16 additions and 1 deletions
+13
View File
@@ -584,6 +584,19 @@ systemctl enable fail2ban >> "$LOG" 2>&1
systemctl restart fail2ban >> "$LOG" 2>&1
log "Fail2Ban configured"
# ── Sudoers for NovaCPX panel (www-data needs root for firewall/opendkim) ────
cat > /etc/sudoers.d/novacpx-firewall <<SUDOERS
Defaults:www-data !requiretty
www-data ALL=(root) NOPASSWD: /usr/sbin/ufw *
www-data ALL=(root) NOPASSWD: /usr/bin/fail2ban-client *
www-data ALL=(root) NOPASSWD: /bin/systemctl restart fail2ban
www-data ALL=(root) NOPASSWD: /bin/systemctl reload fail2ban
www-data ALL=(root) NOPASSWD: /bin/systemctl start fail2ban
www-data ALL=(root) NOPASSWD: /bin/systemctl stop fail2ban
SUDOERS
chmod 440 /etc/sudoers.d/novacpx-firewall
log "Sudoers rules installed"
# ── Cron jobs ─────────────────────────────────────────────────────────────────
step "Setting Up Cron Jobs"
cat > /etc/cron.d/novacpx <<CRON
+3 -1
View File
@@ -11,6 +11,8 @@ $db = DB::getInstance();
// ── Helpers ────────────────────────────────────────────────────────────────
function fw_exec(string $cmd): string {
// Prefix ufw and fail2ban-client with sudo (www-data has NOPASSWD via sudoers.d/novacpx-firewall)
$cmd = preg_replace('/^(ufw|fail2ban-client|systemctl (restart|reload|start|stop) fail2ban)\b/', 'sudo $1', $cmd);
$out = shell_exec($cmd . ' 2>&1');
return trim($out ?: '');
}
@@ -310,7 +312,7 @@ switch ($action) {
// ── Fail2Ban: restart ─────────────────────────────────────────────────
case 'f2b-restart':
$out = fw_exec('systemctl restart fail2ban 2>&1');
$out = fw_exec('sudo systemctl restart fail2ban 2>&1');
audit('firewall.f2b-restart', 'fail2ban');
Response::success(['output' => $out], 'Fail2Ban restarted');
break;