HOWTO: Set up and configure security/sshguard-pf

This short HOWTO explains how to set up and configure the security/sshguard-pf port to provide extra protection against port knockers and such. The HOWTO is written for pf(4) because that is the firewall software I use personally.

I'm assuming that pf(4) has already been set up and running, please see the Handbook for details on how to set up PF on FreeBSD. I'm also showing how to start security/sshguard-pf as a service and not from syslogd.conf(5), I prefer the service(8) method.

  1. Install security/sshguard-pf port.

    # make -C /usr/ports/security/sshguard-pf install clean or # pkg_add -r sshguard-pf. When PKGNG repositories are available the installation is done as # pkg install sshguard-pf

  2. Configure and enable security/sshguard-pf service.

    There aren't many options to set. However, the current version of the port has some of the options mistakenly reversed and the defaults are not completely satisfactory. I'm here showing and also explaining my configuration in rc.conf(5).


    The first line enables the service as expected.

    The sshguard_safety_threshold setting sets the limit on how much "danger" a single IP address can cause before going to the block list. The lower the number the more sensitive blocking. This is the -a option of sshguard(8)

    The sshguard_pardon_min_interval setting sets the minimum amount of time in seconds an IP address will be on the blocklist once it has been added to it. SSHGuard may raise this limit on its own if it detects a repeat offender. This is the -p option of sshguard(8)

    The sshguard_prescribe_interval setting sets the time limit in seconds how long SSHGuard will remember an IP address that hasn't yet been blocked. Setting this too low can allow some attackers to send single probes with long intervals and not get blocked at all. This is the -s option of sshguard(8)

    A whitelist of addresses that are known to be safe can be added to file /usr/local/etc/sshguard.whitelist (an empty file will be created on first run of the service if the file is missing). For example the local LAN addresses could be added to it like this:


    SSHGuard also keeps a permanent (that survives reboots) blacklist of offenders that is stored as a binary file /var/db/sshguard/blacklist.db. The default is to place an IP address to this blacklist after 40 "danger" has been reached. The sshguard_blacklist setting in rc.conf(5) can be used to change this behavior. See the -b option of sshguard(8) for details.

  3. Add a table and a block rule to pf.conf(5).

    Edit /etc/pf.conf to include a persistent table for the blocklist.
    table <sshguard> persist

    Add a block rule in such a way that it's evaluated before any pass rules.

    # Default block rule.
    block all
    block drop in log quick on $ext_if inet from <sshguard> to any
    pass in...

    The official documentation for SSHGuard has an article that pretty much says the same:

  4. Reload pf(4) rules.

    # service pf reload

  5. Start the security/sshguard-pf service.

    # service sshguard start

  6. Inspecting the block list.

    Inspecting of the block list can be done with pfctl(8).

    # pfctl -T show -t sshguard

  7. More information, sshguard(8),
Last edited:
Hi @kpa

Thank you for your tutorial:)

I saw other people adding this line in their

Code:; |exec /usr/local/sbin/sshguard -a 3 -p 9200 -s 12000

Is that not necessary?
Last edited by a moderator:


You have a choice of starting it as a daemon or running it from /etc/syslog.conf, when run as a daemon there is no need to modify /etc/syslog.conf. I prefer the daemon way.
Thanks for this. I have a couple of queries: my phone's ip is on my blacklist (I intentionally tried logging in with incorrect passwords to make this happen), yet I can still login with the correct password (I know the ip is the same)... I thought this ip should now be blocked? Also, I cannot understand what information should be in /etc/pf.conf. I currently only have:
table <sshguard> persist
block in quick on ue0 proto tcp from <sshguard> to any port 22 label "ssh bruteforce"
Lastly, besides the four lines you added to /etc/rc.conf that begin with sshguard, would you suggest adding any of these: pf_enable="YES", pf_rules="/etc/pf.conf", pflog_enable="YES".

That's quite a handful of questions... just trying to understand the details :)


Staff member
You'll want to block everything, not just port 22. They've been poking at your SSH, it's likely they're poking at other things too. Just block everything.

block in quick on ue0 from <sshguard> label "SSH Guard"

If you can still get in your rules are probably not correct. Check if the IP has been added to the table: pfctl -t sshguard -T show | grep <myip>
Also double check you don't have a rule before the SSHGuard rule that allows access.


I left out the PF configuration in rc.conf(5) intentionally because there are other well written documents for that. From where are you testing the connection from your phone? The block rule only catches incoming traffic on the "WAN" interface, if you're testing from the inside "LAN" network the rule is not going to fire.
My bad. I did not have pf_enable="YES" in my /etc/rc.conf. The blacklist seems to have no effect after a reboot if this is not done. Should this be added to your first post kpa ... Does sshguard do anything otherwise?


Edited to include a link to PF set up part in the FreeBSD Handbook.

PF does all the heavy lifting here, if it's not enabled the firewall rules are not in effect and nothing will be blocked.
Small note to any future readers to this post -

In the tutorial of kpa, most/all of the configuration is done in the rc.conf.

An alternative, with the benefit of a leaner/cleaner rc.conf is to use the /usr/local/etc/sshguard.conf file. The default file contains sensible values and can be further modified.

Further, at least in the recent versions, it seems to be necessary to go in the sshguard.conf file and select the backend (pf/ipfw/..) based on one's firewall of choice as none is selected by default.
Last edited by a moderator: