Replace Fail2Ban's basic email notifications with beautiful, information-rich HTML emails. Get comprehensive incident reports delivered straight to your inbox with detailed context about security events.
- Incident Details - IP address, jail name, failure count, timestamps
- WHOIS Lookup - Geographic and network information for banned IPs
- Log Context - Recent log entries showing the actual attack patterns
- Fail2Ban Statistics - Total banned IPs, active jails, per-jail metrics
- System Health - CPU, memory, disk, network connections, GPU usage, Docker stats, uptime
- Ban - When an IP is blocked
- Unban - When an IP ban expires or is manually removed
- Start - When Fail2Ban service starts
- Stop - When Fail2Ban service stops
- Prerequisites
- Quick Start
- Installation
- Configuration Reference
- Troubleshooting
- Uninstalling
- Contributing
- License
Don't have Fail2Ban installed yet?
See INSTALL.md for a complete installation and configuration guide covering common services like SSH, Nginx, and Postfix.
This guide assumes you already have Fail2Ban installed and running on your system.
# 1. Install system packages
sudo apt update
sudo apt install -y python3 python3-pip whois
# 2. Install Python dependencies
sudo apt install python3-psutil
# Optional: GPU monitoring (Nvidia only)
sudo python3 -m pip install nvidia-ml-py --break-system-packages
# 3. Install notification script
sudo cp fail2ban_notify.py /usr/local/bin/fail2ban_notify.py
sudo chmod +x /usr/local/bin/fail2ban_notify.py
sudo chown root:root /usr/local/bin/fail2ban_notify.py
# 4. Install Fail2Ban action
sudo cp sendmail-python.conf /etc/fail2ban/action.d/sendmail-python.conf
sudo chmod 644 /etc/fail2ban/action.d/sendmail-python.conf
# 5. Configure jail.local (see section 4 below)
# 6. Setup Postfix (see section 5 below)
# 7. Restart Fail2Ban
sudo systemctl restart fail2banInstall required system packages:
sudo apt update
sudo apt install -y python3 python3-pip whoisVerify Python installation:
which python3
# Should output: /usr/bin/python3Supported Systems:
- Ubuntu 18.04+
- Debian 10+
- Any Linux distribution with Python 3.6+ and Fail2Ban 0.11+
Install required Python packages:
sudo apt install python3-psutilOptional: If you have an Nvidia GPU and want GPU stats in emails:
sudo python3 -m pip install nvidia-ml-py --break-system-packagesNote: The
--break-system-packagesflag is needed on newer Python versions to install packages system-wide. Skip the GPU package if you don't have Nvidia hardware.
Install the notification script:
sudo cp fail2ban_notify.py /usr/local/bin/fail2ban_notify.py
sudo chmod +x /usr/local/bin/fail2ban_notify.py
sudo chown root:root /usr/local/bin/fail2ban_notify.pyVerify installation:
ls -l /usr/local/bin/fail2ban_notify.py
# Should show: -rwxr-xr-x 1 root root ... /usr/local/bin/fail2ban_notify.pyInstall the custom action file:
sudo cp sendmail-python.conf /etc/fail2ban/action.d/sendmail-python.conf
sudo chmod 644 /etc/fail2ban/action.d/sendmail-python.conf
sudo chown root:root /etc/fail2ban/action.d/sendmail-python.confVerify:
sudo fail2ban-client reload
# Should reload without errorsEdit your Fail2Ban configuration (typically /etc/fail2ban/jail.local):
sudo nano /etc/fail2ban/jail.localAdd or update the [DEFAULT] section:
[DEFAULT]
# Email configuration
destemail = your-email@example.com
sender = fail2ban@yourhostname.com
sendername = Fail2Ban Alert System
linecount = 15
# Action with Python HTML notifications
action_mwl = iptables-multiport[name=%(__name__)s, port="%(port)s", protocol="%(protocol)s"]
sendmail-python[name=%(__name__)s, sender="%(sender)s", dest="%(destemail)s", logpath="%(logpath)s", sendername="%(sendername)s", linecount="%(linecount)s"]
# Apply to all jails (or specify per jail)
action = %(action_mwl)sConfiguration Variables:
| Variable | Description | Example |
|---|---|---|
destemail |
Email address to receive notifications | admin@example.com |
sender |
From email address | fail2ban@server.com |
sendername |
Display name in email client | Fail2Ban Security |
linecount |
Number of log lines to include in email | 15 |
Custom SMTP Port (Bridge Network):
If you're running Postfix on a different port (e.g., 2525 on localhost):
Edit /etc/fail2ban/action.d/sendmail-python.conf and modify the actionban, actionunban, actionstart, and actionstop sections to include:
--smtp-host 127.0.0.1 --smtp-port 2525Postfix acts as an email relay to send notifications through your email provider.
- Visit Google App Passwords
- Create a new app password named "Postfix" or "Fail2Ban"
- Copy the 16-character password (remove spaces)
- Use this password in the configuration below
Note: You must have 2-Factor Authentication enabled on your Google account to use App Passwords.
Edit docker-compose.yaml with your credentials:
version: "3.8"
services:
postfix:
image: boky/postfix:latest
container_name: postfix
restart: unless-stopped
ports:
- "127.0.0.1:2525:25" # Expose on 127.0.0.1:2525
environment:
RELAYHOST: "[smtp.gmail.com]:587"
RELAYHOST_USERNAME: "youremail@gmail.com"
RELAYHOST_PASSWORD: "your_app_password_here"
HOSTNAME: "mail"
ALLOWED_SENDER_DOMAINS: "example.com localhost"
MESSAGE_SIZE_LIMIT: "52428800"
SMTP_TLS_SECURITY_LEVEL: "may"
SMTP_USE_TLS: "yes"
SMTPD_USE_TLS: "yes"Deploy:
docker compose up -dVerify:
docker compose ps
docker compose logs postfix -fFor non-Docker Compose deployments:
docker run -d \
--name postfix \
--restart unless-stopped \
-p 127.0.0.1:2525:25 \
--security-opt no-new-privileges:true \
--cap-drop ALL \
--cap-add CHOWN \
--cap-add DAC_OVERRIDE \
--cap-add SETGID \
--cap-add SETUID \
--cap-add NET_BIND_SERVICE \
--health-cmd "nc -z localhost 25" \
--health-interval 30s \
--health-timeout 10s \
--health-retries 3 \
--health-start-period 10s \
-e RELAYHOST="[smtp.gmail.com]:587" \
-e RELAYHOST_USERNAME="youremail@gmail.com" \
-e RELAYHOST_PASSWORD="your_app_password_here" \
-e HOSTNAME="mail" \
-e ALLOWED_SENDER_DOMAINS="example.com localhost" \
-e MESSAGE_SIZE_LIMIT="52428800" \
-e SMTP_HEADER_CHECKS="regexp:/etc/postfix/smtp_header_checks" \
-e SMTP_TLS_SECURITY_LEVEL="may" \
-e SMTP_USE_TLS="yes" \
-e SMTPD_USE_TLS="yes" \
-e INBOUND_DEBUGGING="0" \
-e DISABLE_SMTP_UTF8="0" \
boky/postfix:latestVerify:
docker ps
docker logs postfix -fWhile this guide focuses on Gmail, other providers work similarly. Update the RELAYHOST and credentials accordingly:
- Outlook/Office365:
[smtp.office365.com]:587 - Yahoo:
[smtp.mail.yahoo.com]:587 - SendGrid:
[smtp.sendgrid.net]:587 - AWS SES:
[email-smtp.us-east-1.amazonaws.com]:587
Send a test notification:
/usr/bin/python3 /usr/local/bin/fail2ban_notify.py \
--event ban \
--ip "1.2.3.4" \
--jail "test-jail" \
--hostname "$(hostname -f)" \
--logpath "/var/log/fail2ban.log" \
--failures "5" \
--dest "your@email.com" \
--sender "fail2ban@test" \
--sendername "Fail2Ban-Test" \
--linecount 10If using port 2525:
/usr/bin/python3 /usr/local/bin/fail2ban_notify.py \
--event ban \
--ip "1.2.3.4" \
--jail "test-jail" \
--hostname "$(hostname -f)" \
--logpath "/var/log/fail2ban.log" \
--failures "5" \
--dest "your@email.com" \
--sender "fail2ban@test" \
--sendername "Fail2Ban-Test" \
--linecount 10 \
--smtp-host 127.0.0.1 \
--smtp-port 2525Apply all changes:
sudo systemctl restart fail2banCheck status:
sudo fail2ban-client status
sudo systemctl status fail2banTest with SSH from another machine:
# From another computer, try SSH with wrong password 3+ times
ssh wronguser@yourserver
# Check if ban occurred
sudo fail2ban-client status sshdYou should receive an email notification!
The fail2ban_notify.py script accepts these arguments:
| Argument | Required | Description |
|---|---|---|
--event |
Yes | Event type: ban, unban, start, stop |
--ip |
For ban/unban | IP address being banned/unbanned |
--jail |
Yes | Fail2Ban jail name (e.g., sshd, nginx-limit-req) |
--hostname |
Yes | Server hostname |
--logpath |
Yes | Path to log file being monitored |
--failures |
For ban | Number of failures that triggered the ban |
--dest |
Yes | Destination email address |
--sender |
Yes | Sender email address |
--sendername |
Yes | Sender display name |
--linecount |
No | Number of log lines to include (default: 10) |
--smtp-host |
No | SMTP server hostname (default: localhost) |
--smtp-port |
No | SMTP server port (default: 25) |
| Variable | Description | Default |
|---|---|---|
RELAYHOST |
Upstream SMTP server | None |
RELAYHOST_USERNAME |
SMTP authentication username | None |
RELAYHOST_PASSWORD |
SMTP authentication password | None |
HOSTNAME |
Postfix hostname | Container hostname |
ALLOWED_SENDER_DOMAINS |
Domains allowed to send email | None |
MESSAGE_SIZE_LIMIT |
Max message size in bytes | 10240000 (10MB) |
SMTP_TLS_SECURITY_LEVEL |
TLS security level | may |
SMTP_USE_TLS |
Enable outbound TLS | no |
SMTPD_USE_TLS |
Enable inbound TLS | no |
Check Fail2Ban logs:
sudo tail -f /var/log/fail2ban.logCheck Postfix logs:
docker logs postfix -f
# Look for SMTP errors or authentication failuresVerify script has execute permissions:
ls -l /usr/local/bin/fail2ban_notify.py
# Should show: -rwxr-xr-xTest script manually:
sudo /usr/bin/python3 /usr/local/bin/fail2ban_notify.py --help
# Should display help without errorsCheck spam folder - Initial emails may be filtered as spam
Verify Gmail App Password:
- Password should be 16 characters without spaces
- 2FA must be enabled on Google account
Check sender domain:
- Make sure
senderdomain is inALLOWED_SENDER_DOMAINS
Test Postfix directly:
docker exec -it postfix bash
echo "Test email body" | mail -s "Test Subject" your@email.comMissing dependencies:
# Reinstall psutil
sudo apt install --reinstall python3-psutil
# Check if psutil loads
python3 -c "import psutil; print(psutil.__version__)"Permission errors:
# Ensure script is owned by root
sudo chown root:root /usr/local/bin/fail2ban_notify.py
sudo chmod 755 /usr/local/bin/fail2ban_notify.pyInstall whois:
sudo apt install whois
which whois # Should output /usr/bin/whoisVerify Nvidia drivers:
nvidia-smi # Should display GPU infoInstall pynvml:
sudo python3 -m pip install nvidia-ml-py --break-system-packagesReload Fail2Ban:
sudo fail2ban-client reloadVerify action file exists:
ls -l /etc/fail2ban/action.d/sendmail-python.confCheck configuration syntax:
sudo fail2ban-client -t
# Should output "OK" if configuration is validVerify Postfix is listening:
netstat -tlnp | grep 2525
# Or
ss -tlnp | grep 2525Test connection:
telnet localhost 2525
# Should connect to PostfixUpdate action file:
Make sure /etc/fail2ban/action.d/sendmail-python.conf includes the port parameter in all action sections.
To completely remove fail2email and revert to default Fail2Ban notifications:
Docker Compose:
cd /path/to/fail2email
docker compose downDocker Run:
docker stop postfix
docker rm postfixEdit /etc/fail2ban/jail.local:
sudo nano /etc/fail2ban/jail.localRemove or comment out the fail2email configuration:
[DEFAULT]
# Remove or comment these lines:
# destemail = your-email@example.com
# sender = fail2ban@yourhostname.com
# sendername = Fail2Ban Alert System
# linecount = 15
# action_mwl = iptables-multiport[name=%(__name__)s, port="%(port)s", protocol="%(protocol)s"]
# sendmail-python[name=%(__name__)s, sender="%(sender)s", dest="%(destemail)s", logpath="%(logpath)s", sendername="%(sendername)s", linecount="%(linecount)s"]
# action = %(action_mwl)sOr revert to default Fail2Ban action:
[DEFAULT]
# Use default mail action (optional)
destemail = your-email@example.com
action = %(action_)ssudo rm /etc/fail2ban/action.d/sendmail-python.confsudo rm /usr/local/bin/fail2ban_notify.pyOnly remove if not used by other applications:
# Remove GPU monitoring (if installed)
sudo python3 -m pip uninstall -y nvidia-ml-py
# Note: Keep python3-psutil if other applications use it
# sudo apt remove python3-psutil # Only if you're sure nothing else needs itApply the changes:
sudo systemctl restart fail2banVerify Fail2Ban is running:
sudo systemctl status fail2ban
sudo fail2ban-client statusRemove the Postfix Docker image if no longer needed:
docker rmi boky/postfix:latestAfter uninstalling, test that Fail2Ban still works:
# Check status
sudo fail2ban-client status
# Trigger a test ban (from another machine)
# Try failed SSH logins 3+ times
# Verify ban occurred
sudo fail2ban-client status sshdYou should see bans occurring but no email notifications being sent through fail2email.
If you want to use Fail2Ban's default email notifications after uninstalling:
-
Install a local mail server:
sudo apt install mailutils postfix # Choose "Internet Site" during setup -
Configure
/etc/fail2ban/jail.local:[DEFAULT] destemail = your-email@example.com sender = fail2ban@yourhostname action = %(action_mw)s
-
Restart Fail2Ban:
sudo systemctl restart fail2ban
Contributions are welcome! Please feel free to submit a Pull Request.
- Fork the repository
- Clone your fork:
git clone https://github.com/rcland12/fail2email.git - Create a feature branch:
git checkout -b feature/amazing-feature - Make your changes
- Test thoroughly
- Commit:
git commit -m 'Add amazing feature' - Push:
git push origin feature/amazing-feature - Open a Pull Request
Always test changes with:
# Syntax check
python3 -m py_compile fail2ban_notify.py
# Manual test
sudo /usr/bin/python3 fail2ban_notify.py [args...]This project is licensed under the MIT License - see the LICENSE file for details.
- Fail2Ban - Intrusion prevention framework
- boky/postfix - Docker Postfix image
- All contributors who have helped improve this project
Made with ❤️ for the security community