posted on Wed, Jan 03 '24 under tag: sysadmin

I ran an open relay with Mailu for a few weeks. Here is how I fixed it.

I did this upgrade about a month and a half ago.

About two weeks ago I noticed strange “Message delivery failed” emails in my inbox. I was under the impression that someone is trying to hack me because there were a couple of attachments in it that looked fishy.

But then, a couple of days ago I got a flood of such error emails, many of them without suspicious attachments. That’s when I took it seriously and investigated. Turns out there were some bots connecting to my server and sending out emails.

From the rspamd logs, the pattern was like this:

Immediate Response

The domain that was in the “From” address was unused by me. So I quickly tried deleting the domain from Mailu. But that didn’t help.

Then I noticed that I was an idiot with respect to Mailu’s warnings about using IPv6. I didn’t read any of them. And I didn’t disable userland proxy or setup any mitigation measures as they asked.

So, I immediately reverted to disabling IPv6.

But then the mails started getting sent with the docker network’s IPv4 address.

That’s when I noticed that in the docker compose I was listening on all interfaces ( is the default when not specifying port.) So I changed the port mappings from this format


to this format:

I also disabled roundcube (later switch to snappymail) just because I couldn’t pin down what exactly could be causing the issue.

Anyhow, with listening on the public IP, the relay stopped.

I suspect the postfix inside the container was somehow getting confused that the remote client’s IP is the same as my local network IP. I haven’t been able to pinpoint why.

Anyhow, the conclusion is that I should be reading mailu docs and following it properly.

Further hardening

With this although the outgoing messages stopped, I could still see log entries of failed login attempts. This felt like a waste of resources.

I immediately set up UFW, allowed the ports I wanted, and denied these IP addresses. But the failed logins continued.

Then I realized that UFW rules are applied in order and the first rule that matches wins. Which means, when I set up the rule to allow ports, it took precedence. So I followed stackoverflow and inserted the IP blocks at the beginning.

But the failed logins continued. That’s when I realized that UFW inserts rules after docker’s rules in iptables and then docker completely bypasses the UFW blocks.

By now having learnt the lesson that I should stick with the documentation on Mailu, I read through and set up very carefully what Mailu suggested with Fail2Ban.

Fail2Ban immediately banned three IPs and started doing its job.

Like what you are reading? Subscribe (by RSS, email, mastodon, or telegram)!