Configure Fail2Ban Email Alerts on Ubuntu VPS: Full Setup

What This Tutorial Covers
Fail2Ban is already running on most hardened VPS setups — scanning logs, banning IPs, and quietly doing its job. But without email alerts configured, you won't know when it's actually firing. A server can block dozens of brute-force attempts overnight and you'd have no idea until you checked the logs manually.
This tutorial walks through setting up Fail2Ban email alerts on Ubuntu VPS from scratch. By the end, you'll get a real email every time a jail bans an IP — including which jail triggered it, the offending address, and the relevant log lines. Useful signal, not noise.
This guide targets Ubuntu 22.04 and 24.04. The steps are nearly identical on both.
Before You Start: What You'll Need
You need a working mail transfer agent (MTA) on the VPS to send alerts. The two most practical options are Postfix (sending via your own domain) or sSMTP / msmtp (relaying through an external SMTP provider like Gmail, Mailgun, or Amazon SES).
This tutorial uses Postfix in satellite/relay mode — the most reliable setup for a VPS that already handles its own mail or can relay through your hosting provider's SMTP. If you're starting from scratch with no mail stack, the Postfix mail relay setup guide covers the full installation before you return here.
You'll also need:
- Root or sudo access to your Ubuntu VPS
- Fail2Ban already installed (or ready to install)
- A valid destination email address to receive alerts
- The
sendmailormailcommand available (viamailutils)
Step 1 — Install Fail2Ban and mailutils
If Fail2Ban isn't installed yet, start here:
sudo apt update
sudo apt install fail2ban mailutils -y
The mailutils package provides the mail command that Fail2Ban uses to dispatch alerts. Without it, the action scripts fail silently — no errors, no emails.
Confirm Fail2Ban is running:
sudo systemctl status fail2ban
You should see active (running). If not:
sudo systemctl enable --now fail2ban
Step 2 — Understand Fail2Ban's Configuration Structure
Fail2Ban keeps its defaults in /etc/fail2ban/jail.conf. Never edit that file directly — it gets overwritten on upgrades. Your changes belong in /etc/fail2ban/jail.local, which takes precedence.
Check whether jail.local already exists:
ls /etc/fail2ban/jail.local
If it doesn't, you can copy the default as a starting point:
sudo cp /etc/fail2ban/jail.conf /etc/fail2ban/jail.local
That said, creating a minimal jail.local from scratch is cleaner and easier to maintain. That's the approach this tutorial takes.
Configure Fail2Ban Email Alerts in jail.local
Open (or create) your local config file:
sudo nano /etc/fail2ban/jail.local
Add the following [DEFAULT] block at the top. Adjust the addresses and sender name to match your setup:
[DEFAULT]
# Email settings
destemail = admin@yourdomain.com
sender = fail2ban@yourdomain.com
mta = sendmail
# Action: ban + send email with log lines
action = %(action_mwl)s
# Basic ban settings
bantime = 3600
findtime = 600
maxretry = 5
Three things worth explaining:
- action_mwl — Fail2Ban's built-in action that bans the IP and sends an email with matching log lines plus a whois lookup. The most informative option available.
- mta = sendmail — tells Fail2Ban to use the
sendmailbinary, which Postfix installs as a compatibility wrapper. If you're usingmsmtp, set this tomailinstead. - bantime = 3600 — bans last one hour by default. Raise it if your server sees persistent attackers.
Now add the SSH jail below the DEFAULT block:
[sshd]
enabled = true
port = ssh
logpath = %(sshd_log)s
backend = %(sshd_backend)s
maxretry = 3
Save with Ctrl+O, exit with Ctrl+X.
Step 3 — Verify the sendmail Path
Fail2Ban needs to locate sendmail correctly. Check where it lives:
which sendmail
On Ubuntu with Postfix installed, the output is typically /usr/sbin/sendmail. If the path differs, update the relevant action file. You can inspect /etc/fail2ban/action.d/sendmail-whois-lines.conf — the actionban line shows the exact command used.
Send a quick test to confirm your mail stack is working:
echo "Test from VPS" | mail -s "Fail2Ban test" admin@yourdomain.com
If the message doesn't arrive within a minute or two, troubleshoot your Postfix relay config before going further. MTA-level delivery problems will silently block every alert, regardless of how Fail2Ban is configured. If your outbound mail is landing in spam, the Postfix SPF authentication guide is worth checking.
Step 4 — Restart Fail2Ban and Check Jail Status
Apply your configuration changes:
sudo systemctl restart fail2ban
Confirm the SSH jail is active:
sudo fail2ban-client status sshd
Expected output:
Status for the jail: sshd
|- Filter
| |- Currently failed: 0
| |- Total failed: 0
| `- File list: /var/log/auth.log
`- Actions
|- Currently banned: 0
|- Total banned: 0
`- Banned IP list:
If you get an error saying the jail doesn't exist, check the [sshd] block in jail.local for typos. Also verify the log path. On Ubuntu 24.04 with systemd, SSH logs land in /var/log/auth.log by default, but some minimal installs use journald only. If /var/log/auth.log doesn't exist, try:
logpath = /var/log/syslog
Step 5 — Trigger a Test Ban to Confirm Alerts Work
The easiest verification is to manually ban a harmless IP and watch for the email. Use a reserved documentation address like 192.0.2.1 — it won't affect anything:
sudo fail2ban-client set sshd banip 192.0.2.1
An alert should land in your inbox within 30–60 seconds. The subject line will look something like: [Fail2Ban] sshd: banned 192.0.2.1 from YourHostname. The body includes the whois output and the log lines that triggered the ban.
Unban the test IP when you're done:
sudo fail2ban-client set sshd unbanip 192.0.2.1
If no email arrives, check the Fail2Ban log for action errors:
sudo tail -50 /var/log/fail2ban.log | grep -i error
Step 6 — Add More Jails with Email Notifications
The alert action you set in [DEFAULT] applies to every jail automatically. Adding more jails is straightforward — define them and they inherit the alert config.
To watch for web server brute-force attempts and Postfix abuse, add these sections to jail.local:
[apache-auth]
enabled = true
port = http,https
logpath = %(apache_error_log)s
maxretry = 5
[postfix]
enabled = true
port = smtp,465,submission
logpath = %(postfix_log)s
maxretry = 5
Running Nginx instead of Apache? Replace the apache-auth block with:
[nginx-http-auth]
enabled = true
port = http,https
logpath = %(nginx_error_log)s
maxretry = 5
Restart Fail2Ban after any change to jail.local. Each jail you enable will send its own alert emails when it fires, keeping your inbox quiet until something actually needs attention.
For a broader look at what's worth monitoring alongside ban events, the VPS monitoring guide for hosting customers covers load, disk, and uptime checks as well.
Keeping Alert Volume Manageable
On a public-facing VPS, you might see several bans per hour during a sustained scan. That's normal — but it can flood your inbox fast. A few adjustments help:
- Increase bantime: Set
bantime = 86400(24 hours) or-1(permanent) for repeat offenders. Fewer bans means fewer emails. - Use the recidive jail: The built-in
[recidive]jail re-bans IPs that get banned multiple times in a short window. Add it tojail.localwithenabled = trueand a longer bantime — a week is reasonable. - Switch to action_mw for noisy jails:
%(action_mw)ssends email with whois but skips the log lines, producing shorter emails for high-volume jails.
You can override the action per jail. To suppress email for a particularly chatty jail while keeping bans active:
[nginx-http-auth]
enabled = true
port = http,https
logpath = %(nginx_error_log)s
maxretry = 5
action = %(action_)s
The %(action_)s macro bans without sending any email, while other jails continue alerting normally.
Checking the Fail2Ban Log Directly
Even with alerts running, it's worth knowing where Fail2Ban records its own activity:
sudo tail -f /var/log/fail2ban.log
Every ban and unban is timestamped here. When troubleshooting a missing alert, look for ERROR or WARNING lines around the time of the expected ban. They'll usually point to a mail delivery failure or a misconfigured action path.
If your VPS runs a control panel like cPanel or DirectAdmin, those panels often manage their own firewall and ban lists — CSF/LFD in cPanel, for instance. Running Fail2Ban alongside CSF is fine, but confirm they're not conflicting on iptables rules. The VPS security checklist covers this interaction in detail.
Setting this up on a fresh VPS? Hostperl VPS plans come with full root access on Ubuntu 22.04 and 24.04, so you can follow this tutorial from step one without restrictions. Support is available around the clock if you hit a wall with mail relay configuration or jail errors. Need more isolation for a high-traffic site? Dedicated server hosting gives you the same flexibility at a larger scale.
Frequently Asked Questions
- Why am I not receiving Fail2Ban alert emails?
- The most common cause is a broken mail stack. Run
echo "test" | mail -s "test" you@yourdomain.comto confirm the MTA works independently of Fail2Ban. Then check/var/log/fail2ban.logfor action errors after triggering a manual ban. - Can I send Fail2Ban alerts to a Gmail address?
- Yes. Configure Postfix as a Gmail SMTP relay, or install
msmtpwith your Gmail app password. Once your MTA can deliver to Gmail, alerts follow automatically — Fail2Ban just callssendmailinternally and doesn't care where it ends up. - What's the difference between action_mw and action_mwl?
action_mwbans the IP and sends an email with whois data.action_mwldoes the same but appends the log lines that triggered the ban — more useful for diagnosis, but produces longer emails.- Will alerts still work after a reboot?
- Yes, as long as Fail2Ban is enabled as a systemd service (
sudo systemctl enable fail2ban). It reloads its jails and resumes monitoring on startup. Previously banned IPs are re-applied from the database at/var/lib/fail2ban/fail2ban.sqlite3. - Can I monitor multiple servers with one alert destination?
- Yes. Set the same
destemailon each VPS. The email subject includes the hostname, so you can tell at a glance which server fired. For clearer labeling across multiple machines, add a custom subject line injail.localusingsubject = [Fail2Ban][%(fq_hostname)s] ....
