Document Owner: IT / Network

Scope: Linux servers running OpenSSH where Fail2Ban enforces bans and notifies n8n via webhook.

Goal: Permanently ban brute-force SSH IPs locally (bantime = -1) and send events to n8n for enrichment and alerting.

Table of Contents

  1. How It Works
  2. Architecture
  3. Prerequisites
  4. SOP 1 — Install Fail2Ban
  5. SOP 2 — Create n8n Webhook Action
  6. SOP 3 — Configure SSH Jail (Permanent Ban + Multi-Action)
  7. SOP 4 — Validate and Test
  8. SOP 5 — Operations (Monitoring and Health Checks)
  9. SOP 6 — Manual Unban
  10. SOP 7 — Incident Recovery (Accidental Self-Ban)
  11. SOP 8 — Secure the Webhook (Production Standard)
  12. SOP 9 — Change Control

How It Works

Every SSH server on the internet faces constant brute-force login attempts. Fail2Ban monitors your SSH log files for repeated authentication failures and automatically blocks offending IP addresses at the firewall level. In this configuration, bans are permanent (bantime = -1), meaning an attacker does not get a second chance.

On its own, Fail2Ban only protects the individual server it runs on. This setup extends it by adding a webhook action that sends ban and unban events to an n8n workflow. n8n acts as the centralized brain — it can enrich each event with threat intelligence (such as IP geolocation or abuse reports), send notifications to Slack or email, and correlate attacks across multiple servers. The result is a two-layer system: Fail2Ban handles real-time local enforcement, and n8n handles visibility and alerting across your entire fleet.

The webhook is designed to be failure-safe. If n8n is unreachable, the curl command times out after 8 seconds and exits silently. The firewall ban still applies regardless. Enforcement never depends on the webhook succeeding.

Architecture

Fail2Ban serves as the local enforcement layer, while n8n provides centralized alerting and intelligence. The data flows as follows:

  • sshd writes authentication failures to /var/log/auth.log (or journald, depending on your distribution).
  • Fail2Ban detects brute-force patterns based on the jail’s maxretry and findtime thresholds, then applies a local firewall ban.
  • n8n receives webhook events and can enrich them with IP intelligence, send notifications to Slack, and correlate bans across multiple servers.
sshd logs → Fail2Ban jail → firewall ban (%(action_)s)
                         ↘︎ webhook notify → n8n workflow
  • Ubuntu/Debian server (or a compatible distribution)
  • OpenSSH installed and running
  • SSH authentication log available at /var/log/auth.log
  • Outbound HTTPS traffic allowed to your n8n domain
  • An n8n webhook endpoint created and set to accept POST requests

SOP 1 — Install Fail2Ban

Procedure

  1. Install the package and enable the service:
sudo apt update
sudo apt install -y fail2ban
sudo systemctl enable --now fail2ban
systemctl is-active fail2ban
sudo fail2ban-client ping

SOP 2 — Create n8n Webhook Action

This step creates a custom Fail2Ban action that sends a webhook to n8n whenever an IP is banned or unbanned. The action does not replace the firewall ban — it runs alongside it.

Procedure

  1. Create the action definition file:
sudo nano /etc/fail2ban/action.d/n8n-webhook.conf

Procedure

  1. Edit the jail configuration:
sudo nano /etc/fail2ban/jail.local

Key Settings Explained

  • maxretry = 5: An IP is banned after 5 failed login attempts.
  • findtime = 600: Those 5 failures must occur within 600 seconds (10 minutes).
  • bantime = -1: Bans are permanent. The IP stays blocked until manually unbanned (see SOP 6).
  • Multi-action: Two actions run on every ban — the default firewall rule and the n8n webhook notification.

Critical Token Warning

Avoid using the # character in your token. Fail2Ban’s configuration parser treats # as the start of a comment, which will silently truncate your token value.

  • Safe: SecureToken_ABC123
  • If you must use #: Escape it with a backslash (e.g., abc\#123)

Apply the Changes

sudo systemctl restart fail2ban

Review Fail2Ban logs

sudo tail -n 200 /var/log/fail2ban.log

Trigger a test ban

To test the full pipeline without locking yourself out:

  1. Use a separate source IP — not your admin IP.
  2. Attempt several failed SSH logins from that IP to exceed the maxretry threshold.
  3. Confirm the ban appears in fail2ban-client status sshd.

Verify the n8n webhook

  • Open your n8n workflow and confirm the webhook executed.
  • Check that the payload includes event, ip, fq_hostname, and jail.

SOP 5 — Operations (Monitoring and Health Checks)

Daily health checks

Run the following commands to verify that Fail2Ban is active and the SSH jail is functioning:

systemctl is-active fail2ban
sudo fail2ban-client status sshd
sudo tail -n 200 /var/log/fail2ban.log
sudo grep "Ban" /var/log/fail2ban.log | tail -n 50

List currently banned IPs

sudo fail2ban-client status sshd

SOP 7 — Incident Recovery (Accidental Self-Ban)

If you accidentally lock yourself out by triggering the ban threshold from your own IP, follow these steps.

Recovery steps

  1. Access the server through an alternative method — cloud provider console, physical access, or out-of-band management.
  2. Unban your IP:
sudo fail2ban-client set sshd unbanip YOUR.PUBLIC.IP.ADDRESS
[sshd]
ignoreip = 127.0.0.1/8 YOUR.PUBLIC.IP.ADDRESS

SOP 8 — Secure the Webhook (Production Standard)

The webhook endpoint should be hardened before deploying to production. At minimum, implement the following:

  • Validate the token: The n8n workflow should check the token field as its first step and reject requests with an invalid or missing token by returning a 401 or 403 response.
  • Rate-limit the endpoint: Apply rate limiting at your reverse proxy (Nginx, Traefik, or Cloudflare) to prevent abuse.
  • Restrict source IPs: Optionally, limit inbound access to the webhook URL to only the IP addresses of your servers.

SOP 9 — Change Control

Always follow this process when modifying the Fail2Ban configuration.

Before making changes

Create a timestamped backup of the entire configuration directory:

sudo cp -a /etc/fail2ban /etc/fail2ban.bak.$(date +%F)
sudo systemctl restart fail2ban
sudo fail2ban-client status sshd
sudo tail -n 100 /var/log/fail2ban.log

End of SOP.