With the firewall configured, it was time to set up Fail2ban. It can be installed from pkg, along with pyinotify for kqueue support. ~~~ pkg install py37-fail2ban-0.11.1_2 pkg install py37-pyinotify-0.9.6 ~~~ The default configuration is in /usr/local/etc/fail2ban/jail.conf, and overrides should be put in jail.local. First I needed to tell Fail2ban to use PF. ~~~ [DEFAULT] banaction = pf ~~~ his refers to the file /usr/local/etc/fail2ban/action.d/pf.conf, which adds banned IP addresses to a PF table called fail2ban. This on its own doesn’t do anything but register the address with PF, so I needed to add a rule to pf.conf to block the traffic. ~~~ table persist block in quick from ~~~ I added this rule directly below block in all so that it took precedence over my ICMP rules. Back to Fail2ban, I enabled the SSH jail, which watches for failed logins in /var/log/auth.log. ~~~ [sshd] enabled = true ~~~ Then I reloaded the PF configuration and started Fail2ban. ~~~ service pf reload echo 'fail2ban_enable="YES"' >> /etc/rc.conf service fail2ban start ~~~ To see it in action, I can tail the Fail2ban log, list the addresses in the fail2ban table, and inspect the statistics for my PF rules. ~~~ tail /var/log/fail2ban.log pfctl -t fail2ban -T show pfctl -v -s rules ~~~ My final jail.local looks like this: ~~~ [DEFAULT] bantime = 86400 findtime = 3600 maxretry = 3 banaction = pf [sshd] enabled = true ~~~ https://www.sqlpac.com/fr/documents/linux-ubuntu-fail2ban-installation-configuration-iptables.html https://cmcenroe.me/2016/06/04/freebsd-pf-fail2ban.html