| SYSTEM INFORMATION | |
|---|---|
| OS type and version | Ubuntu Linux 24.04.4 |
| Webmin version | 2.653 |
| Virtualmin version | 8.1.0 GPL |
| Webserver version | ? |
| Related packages | PHP 8.5 |
Hi Virtualmin team and community,
I’m writing to share an issue I encountered and suggest improvements that could benefit all Virtualmin users, especially those running Ubuntu 24.04.
The problem
My Virtualmin server (Ubuntu 24.04, 16 GB RAM, 4 GB swap) went down multiple times due to SMTP brute-force attacks that overwhelmed Postfix.
The attacks generated thousands of SASL authentication failures per hour, consuming RAM and eventually triggering the OOM killer, which terminated PHP-FPM and made the entire server unresponsive.
What I found
After investigating, I discovered two issues that I believe are worth addressing:
- Postfix had no rate limiting configured
By default, my Postfix installation (managed by Virtualmin) had all rate limiting parameters set to 0 (disabled):
smtpd_client_connection_rate_limit = 0
smtpd_client_message_rate_limit = 0
smtpd_client_recipient_rate_limit = 0
smtpd_client_auth_rate_limit = 0
This meant a single IP could open unlimited connections and attempt unlimited authentication failures without any throttling. During a brute-force attack, this quickly overwhelmed the server.
I had to manually add these settings to /etc/postfix/main.cf:
smtpd_client_connection_rate_limit = 10
smtpd_client_message_rate_limit = 30
smtpd_client_recipient_rate_limit = 50
smtpd_client_auth_rate_limit = 5
anvil_rate_time_unit = 60s
This is a recent edit I done so is still under testing but I believe should not cause issues.
2. Fail2ban was not reading Postfix logs correctly
Fail2ban was installed and running, but it was configured with backend = systemd (the default on Ubuntu 24.04). This backend reads from the systemd journal, but Postfix on Ubuntu 24.04 logs to /var/log/mail.log, not to the journal.
As a result, Fail2ban showed as “active” but was effectively blind to the SMTP attacks:
# Before the fix:
sudo fail2ban-client get postfix logpath
No file is currently monitored
I had to manually configure /etc/fail2ban/jail.local to use backend = polling and specify the correct log paths:
[DEFAULT]
backend = polling
[postfix]
enabled = true
mode = aggressive
logpath = /var/log/mail.log
[postfix-sasl]
enabled = true
backend = polling
logpath = /var/log/mail.log
[dovecot]
enabled = true
logpath = /var/log/mail.log
[sshd]
enabled = true
logpath = /var/log/auth.log
After the fix, Fail2ban immediately started banning dozens of attacking IPs:
# After the fix:
sudo fail2ban-client get postfix logpath
Current monitored log file(s):
`- /var/log/mail.log
Status for the jail: postfix
|- Actions
| |- Currently banned: 49
| `- Total banned: 49
Suggestions for Virtualmin
I believe these issues could be addressed in Virtualmin to improve security out of the box:
- Consider adding Postfix rate limiting by default when Virtualmin configures a mail server. Even conservative values like the ones above would provide a first line of defense against brute-force attacks without impacting legitimate mail flow.
- Detect and fix Fail2ban log backend issues during installation. On Ubuntu 24.04, Virtualmin could check whether Postfix logs to the journal or to
/var/log/mail.log, and configure Fail2ban accordingly. Alternatively, display a warning in the Virtualmin dashboard if Fail2ban is not monitoring Postfix logs.
Additional notes
I also protected my PHP cron jobs with flock and enabled PHP-FPM auto-restart via systemd, but these are general best practices not specific to Virtualmin.
The main takeaway is that Postfix without rate limiting + Fail2ban not reading the correct logs = server vulnerable to brute-force attacks. I hope this feedback helps improve Virtualmin for everyone.
Happy to provide more details or test any proposed changes.
Cheers!