Fail2Ban4Win is a background service that temporarily blocks IP ranges in Windows Firewall when enough authentication errors appear in Event Log in a given time period for those IP ranges.
You can customize the duration of the ban, the type of Event Log events to detect, and other options. The example configuration file will set Fail2Ban4Win to ban a /24 subnet for 24 hours after 10 failures to authenticate to Remote Desktop Services, sshd, or both.
- Fail2Ban4Win runs in the background as a Windows Service.
- Configuration comes from a JSON file in the installation directory.
- Fail2Ban4Win listens for Windows Event Log events from various logs and event IDs.
- When a matching event is logged by your server software, Fail2Ban4Win extracts the client's IP address from the event data. The IP address is aggregated into a /24 subnet IP range.
- Fail2Ban4Win keeps track of how many times each subnet (not each IP address) has triggered any auth failure events over the last 24 hours.
- When a given subnet has failed to authenticate 10 cumulative times in the last 24 hours across all Event Log selectors, a Windows Firewall rule is created to block incoming traffic from that subnet on all ports.
- After being banned for 1 day, the firewall rule is deleted and the subnet is allowed to fail 10 more times before being banned a second time.
- Each time a subnet is repeatedly banned, the ban duration increases by 1 day, up to a maximum of a 4 day ban, after which each subsequent ban will always be 4 days.
- When Fail2Ban4Win restarts, it deletes all firewall rules it created and starts from scratch. This allows it to fail open.
You can customize most of the above specifics to suit your banning needs.
- Windows 7 SP1, Windows Server 2008 R2 SP1, or later
- .NET Framework 4.7.2 or later, which are included in Windows 10 1803 (April 2018 Update), Windows Server 2019, and later
- Use Windows Firewall, as opposed to a third-party firewall solution
- Download the latest release. You have artifact options to choose from:
Fail2Ban4Win.zip— Single big EXE fileFail2Ban4Win-unpacked.zip— Folder full of DLLs, which may reduce antivirus false positives
The file structure is the only difference. Both artifacts are otherwise equivalent and have the same behavior, features, and bugs. - Extract the contents of the ZIP file to a directory like
C:\Program Files (x86)\Fail2Ban4Win\. - Open an elevated PowerShell window (run it as administrator).
- Allow PowerShell scripts to run until you close the window.
Set-ExecutionPolicy RemoteSigned -Scope Process -Force
- Register Fail2Ban4Win as a service.
& 'C:\Program Files (x86)\Fail2Ban4Win\Install service.ps1'
- Configure the service in the next section before starting it.
- Download the latest release, as described above.
- Extract the ZIP file to the installation directory.
Caution
Don't overwrite config files like configuration.json or NLog.config.
- Restart the service using
services.msc(GUI),Restart-Service Fail2Ban4Win(PowerShell), ornet stop Fail2Ban4Win & net start Fail2Ban4Win(Command Prompt).
The provided example configuration file has selectors for Remote Desktop Services, Cygwin OpenSSH sshd (updated in 1.3.1), and Windows OpenSSH sshd (updated in 1.3.1). It also has some example values for neverBanSubnets and other properties that you can replace with your own values.
Important
Be aware that isDryRun is set to true in the example configuration to avoid accidentally blocking traffic until you're ready.
- Open the
configuration.jsonfile from the Fail2Ban4Win installation directory in a text editor. (You may need to start the editor elevated depending on your file permissions.) - Set any of the following properties.
Property name Default when omitted Description isDryRunfalseFirewall rules will only be created or deleted when this is false.maxAllowedFailures9If an IP range (of size banSubnetBits) exceeds this number of failures during thefailureWindow, it will be banned. By default, the 10th failure is a ban.failureWindow1.00:00:00(1 day)How long to consider auth failures. By default, 10 failures in 1 day results in a ban. The format is d.hh:mm:ss.banPeriod1.00:00:00(1 day)After enough failures, the IP range will be banned by adding a Windows Firewall block rule, which will then be removed after this period of time. The format is d.hh:mm:ss. By default, a ban lasts 1 day.banSubnetBits0Optional CIDR subnet aggregation size when both counting failures and blocking traffic. The example value of 8bits blocks the /24 subnet, or 255.255.255.0. You can restrict blocking only to the exact IP address by setting this to0, which is equivalent to /32.banRepeatedOffenseCoefficient0.0How much of the banPeriodto add on subsequent offenses (optional). The defaultbanPeriodof 1 day and example coefficient of 1.0 results in a 1 day ban for first offenders, 2 days for 2nd offenders, 3 days for 3rd offenders, and 4 days for 4th offenders or greater. Changing this coefficient from1.0to2.0would result in successive ban durations of 1 day, 3 days, 5 days, and 7 days instead. Defaults to all subsequent bans having the same duration as initial bans.banRepeatedOffenseMax4An optional limit on how many repeated offenses can be used to calculate ban duration. By default, the 5th offense and subsequent bans will be capped at the same duration as the 4th offense ban, which is 4 days. neverBanSubnets[]Optional whitelist of IP ranges that should never be banned, regardless of how many auth failures they generate. Each item can be a single IP address, like 67.210.32.33, or a range, like67.210.32.0/24.neverBanReservedSubnetstrueBy default, IP addresses in the reserved blocks 10.0.0.0/8,172.16.0.0/12, and192.168.0.0/16will not be banned, to avoid unintentionally blocking LAN access. To allow all three ranges to be banned, change this tofalse. To then selectively prevent some of those ranges from getting banned, you may add them to theneverBanSubnetslist above. The loopback addresses 127.0.0.0/8 will never be banned, regardless of this setting.unbanAllOnStartuptrueWhether Fail2Ban4Win should, when it launches, delete all of its existing firewall rules which it previously created. This is trueby default, to fail open. To preserve existing bans, e.g. after a computer reboot, set this tofalse. When resuming existing unban timers, the duration is corrected for the time Fail2Ban4Win wasn't running. Unrelated firewall rules (Windows defaults, your custom rules) are never touched, regardless of this setting.eventLogSelectors[]Required list of event criteria to listen for in Event Log. Each object in the list can have the following properties. selectorName: optional friendly name of your choice for this selector. This does not affect matching, and only appears in this program's log file when an event is matched to make it more readable.logName: required, which log in Event Viewer contains the events, e.g.Application,Security,OpenSSH/Operational.eventId: required, numeric ID of event logged on auth failure, e.g.4625for RDP auth errors.source: optional Source, AKA Provider Name, of events, e.g.sshd-sessionfor Cygwin OpenSSH sshd. If omitted, events will not be filtered by Source.ipAddressEventDataName: optional, theNameof theDataelement in the event XML'sEventDatain which to search for the client IP address of the auth request, e.g.IpAddressfor RDP. If omitted, the firstDataelement will be searched instead.ipAddressEventDataIndex: optional, the 0-indexed offset of theDataelement in the XML'sEventDatain which to search for the client IP address, e.g.3to search for IP addresses in the fourthDataelement inEventData. Useful ifEventDatahas multipleDatachildren, but none of them have aNameattribute to specify inipAddressEventDataName, and the IP address doesn't appear in the first one. This offset is applied after anyNameattribute filtering, and applies whether or notipAddressEventDataNameis specified. If omitted, defaults to0.ipAddressPattern: optional, regular expression pattern string that matches the IP address in theDataelement specified above. Useful if you want to filter out some events from the log with the desired ID and source but that don't describe an auth failure (e.g. sshd's disconnect events). If omitted, searches for all IPv4 addresses in theDataelement's text content. To set options like case-insensitivity, put(?i)at the start of the pattern. Patterns are not anchored to the entire input string unless you surround them with^and$. If you specify a pattern, ensure the desired IPv4 capture group in your pattern has the nameipAddress, e.g.Failed: (?<ipAddress>(?:\d{1,3}\.){3}\d{1,3})
eventPredicate: optional, XPath 1.0 query fragment to filter events based on arbitrary elements, matched against the<Event>element. Useful if not all events with the givenlogName,eventId, andsourceshould trigger bans, like IIS HTTP 200 responses, e.g.[EventData/Data[@Name='sc-status']=403]. Most XPath functions are not supported by Windows ETW.
- After saving the configuration file, restart the Fail2Ban4Win service using
services.msc(GUI),Restart-Service Fail2Ban4Win(PowerShell), ornet stop Fail2Ban4Win & net start Fail2Ban4Win(Command Prompt) for your changes to take effect. Note that the service will clear existing bans when it starts (unless you changedunbanAllOnStartuptofalse).
Fail2Ban4Win uses NLog to log messages. By default, messages of Info severity and above are written to logs\Fail2Ban4Win.log in the installation directory.
You can configure this logging by editing NLog.config in the Fail2Ban4Win installation directory. See NLog documentation for this XML config file, the format of log messages, file handling, and other places to write logs besides a local file.
In this example, we will go through the process of creating an event for Windows OpenSSH sshd. This event is already supported in the example configuration file, but the following process covers all of the necessary steps to add any other event.
- Ensure OpenSSH Server is installed and running in Windows.
- Install the latest sshd version from Microsoft's PowerShell/Win32-OpenSSH, which has important security fixes that are often missing from the older built-in version below (for Terrapin, VerifyHostKeyDNS, and DoS attacks).
- Otherwise, install OpenSSH Server in the Windows Settings app (
explorer.exe ms-settings:optionalfeatures):- Windows 10: System › Optional features › Add a feature › OpenSSH Server
- Windows 11: System › Optional features › View features › See available features › OpenSSH server
- Windows Server 2019: Apps › Apps & features › Manage optional features › Add a feature › OpenSSH Server
- Windows Server 2022: Apps › Apps & features › Optional features › Add a feature › OpenSSH Server
- Windows Server 2025: OpenSSH Server is preinstalled, so start the
sshdservice and set its startup type to Automatic
- Open Event Viewer (
eventvwr.msc). - Find an instance of the event you want. If one doesn't exist, start an SSH client like ssh or PuTTY and fail to authenticate on purpose.
- The
logNamevalue of the event log selector object comes from the Log Name shown here, in this case,OpenSSH/Operational. - The optional
sourcevalue comes from the Source shown here, in this case,OpenSSH. You can also omitsourcein this case because all events in this log have the same Source. - The
eventIdvalue comes from the Event ID shown here, in this case,4. - Switch to the Details (XML View) of the event to determine how the IP address is represented in the
<EventData>. - The IP address is found in the following element.
<Data Name="payload">Failed password for invalid user foo bar from 192.168.1.7 port 49721 ssh2</Data>
- The
ipAddressEventDataNamevalue comes from theNameattribute value of the<Data>element which contains the IP address in its text content, in this case,payload.- If there were just one
<Data>element with noNameattribute, you would omit theipAddressEventDataNameproperty from the event log selector object. - If there were multiple
<Data>elements with noNameattributes, you would omit theipAddressEventDataNameproperty and setipAddressEventDataIndexto the position of the desiredDataelement (where the firstDatachild of theEventDataelement would have index 0).
- If there were just one
- The
ipAddressPatternhelps narrow down which events represent auth failures. Some events in this log with ID 4 are caused by successful auth attempts or disconnections, which should not trigger firewall bans. By matching the text of an auth failure, only the correct events will be processed. The following pattern matches only auth failures and captures the IP address in a named group for processing.^Failed password for(?: invalid user)? .+ from (?<ipAddress>(?:\d{1,3}\.){3}\d{1,3}) port \d{1,5} ssh\d?$
- The
selectorNameis optional and can be any name you want for this selector. It has nothing to do with Event Log event contents and does not affect how events are matched. It only appears in theFail2Ban4Win.loglog file when an event is matched to make the logs more readable, especially during debugging. - Here is the resulting event log selector object from all of the above properties.
{ "selectorName": "My OpenSSH selector", "logName": "OpenSSH/Operational", "source": "OpenSSH", "eventId": 4, "ipAddressEventDataName": "payload", "ipAddressPattern": "^Failed password for(?: invalid user)? .+ from (?<ipAddress>(?:\\d{1,3}\\.){3}\\d{1,3}) port \\d{1,5} ssh\\d?$" } - You can add this selector object to
configuration.jsonby inserting it into theeventLogSelectorsarray.{ "maxAllowedFailures": 9, "eventLogSelectors": [ { "selectorName": "Remote Desktop Services", "logName": "Security", "eventId": 4625, "ipAddressEventDataName": "IpAddress" }, { "selectorName": "My OpenSSH selector", "logName": "OpenSSH/Operational", "source": "OpenSSH", "eventId": 4, "ipAddressEventDataName": "payload", "ipAddressPattern": "^Failed password for(?: invalid user)? .+ from (?<ipAddress>(?:\\d{1,3}\\.){3}\\d{1,3}) port \\d{1,5} ssh\\d?$" } ] }
Do any of the following.
- Start the
Fail2Ban4Winservice from theservices.mscGUI. - Start the service from PowerShell using
Start-Service Fail2Ban4Win. - Start the service from Command Prompt using
net start Fail2Ban4Win. - Run the service in the foreground by starting
Fail2Ban4Win.exein a console window. This is useful for looking at the log output and verifying your configuration, especially whenisDryRunis true. You can stop the process using Ctrl+C.
You can see the block rules created by Fail2Ban4Win in Windows Firewall.
- Start Windows Firewall with Advanced Security (
wf.msc). - Go to
Inbound Rules. - To only show rules created by Fail2Ban4Win, select Action › Filter by Group › Filter by Fail2Ban4Win.
- If Fail2Ban4Win has not created any rules yet (for example, if it started running recently), the Filter by Fail2Ban4Win option will not appear in the Filter by Group menu. Click Refresh to update the collection of rules and groups.
- To sort by creation time, select View › Add/Remove Columns and Add the Description column, then click the Description column header.
Get-NetFirewallRule -DisplayGroup Fail2Ban4Win | ft DisplayName, DescriptionDisplayName Description
----------- -----------
Banned 172.232.9.0/24 Banned 2025-09-22T23:09:58. Will unban 2025-10-13T23:09:58. Offense #3.
Banned 108.181.178.0/24 Banned 2025-09-22T23:34:07. Will unban 2025-10-13T23:34:07. Offense #3.
Banned 102.67.139.0/24 Banned 2025-09-23T00:52:14. Will unban 2025-10-14T00:52:14. Offense #3.
See Get-NetFirewallRule documentation.
- My parents for free Windows Server hosting with a static IP address for anyone to connect to.
- A vague awareness of the existence of
fail2banthat convinced me that non-stop RDP and SSH login attempts might have a solution. wail2banby Katie McLaughlin (glasnt) for being archived and motivating me to create my own non-archived implementation.win2banfor charging an entire fourty-nine American dollars for some cobbled together free open-source projects, which made me indignant enough to create my own free, open-source, clean-room implementation.- Soroush (
falahati) for the excellent .NET wrapper for the Windows Firewall COM API. - Robert Mustacchi (
rmustacc) for talking me out of trying to implement a wait-free list to store failure times and instead continuing to lock array lists.


