"description":"Install Fail2Ban with three jails tuned for Proxmox (SSH aggressive, Proxmox UI 8006, ProxMenux Monitor 8008). Includes the journald MaxLevelStore fix, custom log services for reliability, auto-detected nftables/iptables backend and SSH MaxAuthTries hardening.",
"ogTitle":"Fail2Ban | ProxMenux Documentation",
"ogDescription":"Brute-force protection for SSH and Proxmox web UIs, with Proxmox-specific journald and backend fixes."
},
"header":{
"title":"Fail2Ban",
"description":"Installs Fail2Ban with a Proxmox-specific configuration: three jails (SSH aggressive, Proxmox UI on port 8006, ProxMenux Monitor on port 8008 + reverse proxy), a journald log-level fix so SSH auth events are actually stored, two journal-to-file logger services that work around a known Fail2Ban systemd-backend issue, auto-detected firewall backend and SSH MaxAuthTries hardening.",
"section":"Security"
},
"intro":{
"title":"What this does",
"body":"Installs Fail2Ban from the Debian repos and writes a complete Proxmox-tuned configuration that protects three attack surfaces (SSH, Proxmox UI, ProxMenux Monitor) out of the box. Detects an existing install and offers a manage menu (reinstall / remove) instead of re-running the installer."
},
"firstLaunch":{
"heading":"First-launch dialog",
"body":"On a host without Fail2Ban, the script shows a confirmation dialog summarising everything it's about to install and configure. Cancel exits without changes; confirm starts the install flow.",
"imageAlt":"Fail2Ban install confirmation dialog listing the three jails, journald fix and SSH hardening"
"outro":"Global defaults from <code>jail.local</code>: <code>ignoreip = 127.0.0.1/8 ::1</code>, <code>ignoreself = true</code>,<code> bantime = 86400</code> (24h fallback for jails that don't override it), <code>maxretry = 2</code>, <code>findtime = 1800</code>."
},
"journald":{
"heading":"Why the journald fix matters",
"intro":"Proxmox ships <code>/etc/systemd/journald.conf</code> with <codeNw>MaxLevelStore=warning</codeNw>. journald drops every log message <em>below</em> warning before storing it. SSH and PAM emit auth failures at <em>info</em> / <em>notice</em> levels, so:",
"fail2banDetail":"sees nothing\n→ never bans anything",
"arrowLabel":"default Proxmox"
},
"afterDiagram":"The installer detects this and writes a drop-in at <codeXs>/etc/systemd/journald.conf.d/proxmenux-loglevel.conf</codeXs> raising both <code>MaxLevelStore</code> and <code>MaxLevelSyslog</code> to <code>info</code>:",
"outro":"Then restarts <code>systemd-journald</code>. The drop-in is removed on uninstall, restoring the original Proxmox default."
},
"loggers":{
"heading":"Why two custom logger services",
"intro1":"Fail2Ban can read directly from the systemd journal (<code>backend = systemd</code>), but on Proxmox this backend has known reliability issues with <code>pvedaemon</code> worker processes (auth events appear in the journal but Fail2Ban doesn't always pick them up) and intermittently with <code>sshd</code>.",
"intro2":"The workaround: ProxMenux creates two tiny systemd services that <code>journalctl -f</code> the relevant units and append every line to a file. Fail2Ban then reads those files with the rock-solid <code>backend = auto</code> (file mode):",
"headerService":"Service",
"headerSource":"Source unit",
"headerOutput":"Output file",
"rows":[
{
"service":"proxmox-auth-logger.service",
"source":"pvedaemon.service",
"output":"/var/log/proxmox-auth.log"
},
{
"service":"ssh-auth-logger.service",
"source":"ssh.service",
"output":"/var/log/ssh-auth.log"
}
],
"outro":"Both services are declared <code>PartOf=fail2ban.service</code> so they restart with Fail2Ban and stop with it. Mode 640 owned by <code>root:adm</code> on the log files. The third log used by the <code>[proxmenux]</code> jail (<code>/var/log/proxmenux-auth.log</code>) is written directly by the ProxMenux Monitor Flask app — no logger service needed for that one."
},
"backend":{
"heading":"Firewall backend auto-detection",
"intro":"The installer probes the host: if <code>nft list ruleset</code> works, it picks <code>nftables</code> as the ban action. Otherwise it falls back to <code>iptables-multiport</code> / <code>iptables-allports</code>. The choice is written into <code>jail.local</code>:",
"intro":"Lynis control <strong>SSH-7408</strong> recommends <code>MaxAuthTries 3</code> in <code>sshd_config</code>. The SSH jail uses <code>maxretry = 2</code> to trigger a ban after repeated failures, while MaxAuthTries limits attempts within a connection. The explicit SSH setting adds defence in depth, including when Fail2Ban is stopped for maintenance.",
"Reloads <code>sshd</code> (reload, not restart, to keep existing sessions alive)."
],
"outro":"On uninstall, the saved original value is restored and <code>sshd</code> is reloaded again."
},
"manage":{
"heading":"Manage an existing install",
"intro":"If Fail2Ban is already installed when you open the menu, the script detects it and shows a manage menu instead of re-running the installer:",
"headerAction":"Action",
"headerWhat":"What it does",
"rows":[
{
"action":"Reinstall",
"what":"Re-runs the full installer — rewrites all jails with the current ProxMenux defaults. Use this after a ProxMenux update bumps the recommended values."
},
{
"action":"Remove",
"what":"Stops fail2ban and the two logger services, purges the apt package, removes all jail / filter files, deletes the journald drop-in (restoring the Proxmox default), and restores the original SSH MaxAuthTries."
}
]
},
"verify":{
"heading":"Verify it's working",
"intro":"After installation, useful commands from the host:",
"code":"# Service status and version\nsystemctl status fail2ban\nfail2ban-client --version\n\n# All active jails\nfail2ban-client status\n\n# Detail on one jail\nfail2ban-client status sshd\nfail2ban-client status proxmox\nfail2ban-client status proxmenux\n\n# Currently banned IPs in a jail\nfail2ban-client status sshd | grep \"Banned IP\"\n\n# Manually unban an IP (use this if you ban yourself)\nfail2ban-client unban 192.0.2.10\n\n# Tail the auth logs Fail2Ban watches\ntail -f /var/log/ssh-auth.log\ntail -f /var/log/proxmox-auth.log\ntail -f /var/log/fail2ban.log"
},
"troubleshoot":{
"heading":"Troubleshooting",
"neverBansTitle":"Fail2Ban runs but never bans anything",
"neverBansBody":"Check that <code>tail -f /var/log/ssh-auth.log</code> receives an entry after a wrong-password SSH attempt from another machine. If it stays empty, inspect <code>systemctl status ssh-auth-logger.service</code>. If the logger is active, inspect recent SSH events with <code>journalctl -u ssh.service -n 50 --no-pager -p info</code> and check whether the journald drop-in permits the <em>info</em> level.",
"monitorEmptyTitle":"ProxMenux Monitor jail has no entries even after failed logins",
"monitorEmptyBody":"The <code>[proxmenux]</code> jail reads <code>/var/log/proxmenux-auth.log</code>, which is written by the ProxMenux Monitor Flask app — not by a journald logger. If you don't run the Monitor, the file stays empty and the jail never fires. That's expected; the jail config is harmless. If you do run the Monitor and the log is empty, check the Flask logging config.",
"selfBanTitle":"I banned myself",
"selfBanIntro":"From a console / IPMI / iKVM (or another whitelisted IP):",
"selfBanCode":"fail2ban-client unban '<'YOUR_IP'>'\n\n# To prevent it next time, edit /etc/fail2ban/jail.local and add your IP:\nignoreip = 127.0.0.1/8 ::1 192.168.1.0/24 203.0.113.42\n\n# Then reload\nfail2ban-client reload",
"aptFailTitle":"apt-get fails: ''Unable to locate package fail2ban''",
"aptFailBody":"The host is missing the Debian repos (common on barebones Proxmox installs). The installer detects this and writes <code>/etc/apt/sources.list.d/debian.sources</code> with the right codename (<code>bookworm</code> / <code>trixie</code>) before retrying. If it still fails, check <code>/etc/os-release</code> for <code>VERSION_CODENAME</code> and confirm the repo URL is reachable.",
"lockoutTitle":"SSH locks me out after install",
"lockoutBody":"The installer sets <code>MaxAuthTries=3</code>. If your password manager / agent retries multiple keys, you may exceed that on a single connection attempt. Limit the keys offered: <code>ssh -o IdentitiesOnly=yes -i ~/.ssh/specific_key user@host</code>. Or temporarily raise <code>MaxAuthTries</code> in <code>sshd_config</code> while you debug."
},
"files":{
"heading":"Files written",
"code":"/etc/fail2ban/jail.local # global defaults + [sshd]\n/etc/fail2ban/jail.d/proxmox.conf # [proxmox]\n/etc/fail2ban/jail.d/proxmenux.conf # [proxmenux]\n/etc/fail2ban/filter.d/proxmox.conf # auth-failure regex for pvedaemon\n/etc/fail2ban/filter.d/proxmenux.conf # auth-failure regex for Monitor\n/etc/systemd/system/proxmox-auth-logger.service # journal → file (pvedaemon)\n/etc/systemd/system/ssh-auth-logger.service # journal → file (sshd)\n/etc/systemd/journald.conf.d/proxmenux-loglevel.conf # MaxLevelStore=info\n/etc/ssh/sshd_config # MaxAuthTries=3 (in-place edit)\n/var/log/proxmox-auth.log # written by logger service\n/var/log/ssh-auth.log # written by logger service\n/var/log/proxmenux-auth.log # written by Monitor Flask app\n/usr/local/share/proxmenux/sshd_maxauthtries_backup # for restore on uninstall"
"monitorTail":" — same install reachable from the dashboard, plus live jail status, banned IPs and per-jail retry / ban-time tuning from the browser.",
"lynisLabel":"Lynis",
"lynisTail":" — run a security audit before/after to confirm the SSH-7408 control is satisfied.",