Securing SSH and Apache on Raspberry Pi with Fail2Ban and nftables

Introduction

This guide explains how to install and configure Fail2Ban on a Raspberry Pi to protect:

  • SSH (sshd) from brute-force attacks
  • Apache web server from malicious requests and bots

The setup uses nftables (modern firewall backend) instead of legacy iptables.


Prerequisites

  • Raspberry Pi running Raspberry Pi OS (Debian-based)
  • Root or sudo access
  • Apache installed and logging to:
    • /var/log/apache2/access.log

1. Install Required Packages

sudo apt update
sudo apt install fail2ban nftables -y

Enable and start nftables:

sudo systemctl enable nftables
sudo systemctl start nftables

2. Configure nftables (Base Firewall)

Edit the configuration:

sudo nano /etc/nftables.conf

Example minimal ruleset:

table inet filter {
    chain input {
        type filter hook input priority 0;
        policy drop;

        iif lo accept
        ct state established,related accept

        tcp dport 22 accept
        ip protocol icmp accept

        counter drop
    }
}

Apply the rules:

sudo nft -f /etc/nftables.conf

3. Configure Fail2Ban

Create a local configuration file:

sudo nano /etc/fail2ban/jail.local

Global Settings

[DEFAULT]
banaction = nftables-multiport
banaction_allports = nftables-allports

findtime = 10m
bantime = 1h
maxretry = 5

backend = systemd

ignoreip = 127.0.0.1/8 ::1

4. Protect SSH (sshd)

Add the following:

[sshd]
enabled = true
port = ssh
filter = sshd
backend = systemd

maxretry = 5
findtime = 10m
bantime = 1h

5. Protect Apache

Add protection for multiple access logs:

# Authentication failures
[apache-auth]
enabled  = true
port     = http,https
filter   = apache-auth
logpath  = /var/log/apache2/access.log
maxretry = 5
findtime = 10m
bantime  = 1h

# Bad bots and scanners
[apache-badbots]
enabled  = true
port     = http,https
filter   = apache-badbots
logpath  = /var/log/apache2/access.log
maxretry = 2
findtime = 10m
bantime  = 6h

# Script probing (phpmyadmin, etc.)
[apache-noscript]
enabled  = true
port     = http,https
filter   = apache-noscript
logpath  = /var/log/apache2/access.log
maxretry = 3
findtime = 10m
bantime  = 6h

# Exploit attempts
[apache-overflows]
enabled  = true
port     = http,https
filter   = apache-overflows
logpath  = /var/log/apache2/access.log
maxretry = 2
findtime = 10m
bantime  = 12h

6. Start and Enable Fail2Ban

sudo systemctl enable fail2ban
sudo systemctl start fail2ban

7. Verify Configuration

Check active jails:

sudo fail2ban-client status

Example output should include:

  • sshd
  • apache-auth
  • apache-badbots
  • apache-noscript
  • apache-overflows

Check a specific jail:

sudo fail2ban-client status sshd

8. Monitor Logs

Real-time monitoring:

sudo tail -f /var/log/fail2ban.log

Check SSH logs:

sudo journalctl -u ssh

9. Testing

Simulate failed SSH logins:

ssh invaliduser@localhost

After multiple failures, verify the ban:

sudo fail2ban-client status sshd

10. Important Notes

  • Ensure Apache logs use a standard format (combined log format recommended)
  • Avoid mixing iptables with nftables
  • Always whitelist your own IP using ignoreip
  • Custom log formats may require custom Fail2Ban filters

11. Optional Hardening

Edit SSH configuration:

sudo nano /etc/ssh/sshd_config

Recommended settings:

PermitRootLogin no
PasswordAuthentication no

Restart SSH:

sudo systemctl restart ssh

Conclusion

With this setup:

  • SSH brute-force attacks are automatically blocked
  • Apache scanners and malicious bots are banned
  • Firewall rules are handled efficiently using nftables

This provides a solid baseline security layer for any Raspberry Pi exposed to the internet.