1. Background
When managing mail servers, Fail2Ban is used to block malicious IPs and brute-force attempts.
On CentOS 7 (Fail2Ban v0.11.2 / Python 2.7), running:
fail2ban-regex /data/docker/mailsys/postfix/alpine-3.22.1/log/postfix.log /etc/fail2ban/filter.d/postfix-pipelining.conf -v
triggered the following error:
ConfigParser.InterpolationMissingOptionError:
Bad value substitution: key: __prefix_ipv4
2. Root Cause
Fail2Ban filters often reference shared variables like:
%(__prefix_ipv4)s, %(__prefix_ipv6)s, %(__prefix_line)s
These are defined in /etc/fail2ban/filter.d/common.conf.
However, on older versions (e.g., CentOS 7’s 0.11.x), the IPv4/IPv6 variables are missing,
causing fail2ban-regex to fail.
3. Fix Methods
✅ Method 1: Use <HOST> (Recommended)
Replace deprecated variables with Fail2Ban’s built-in <HOST> macro that matches both IPv4 and IPv6.
Edit /etc/fail2ban/filter.d/postfix-pipelining.conf:
[INCLUDES]
before = common.conf
[Definition]
_daemon = postfix(-.*)?/smtpd
failregex = ^%(__prefix_line)s(?:postfix/(?:smtpd|submission/smtpd)\[\d+\]: )NOQUEUE: lost connection after CONNECT from .*?\[(?P<host><HOST>)\].*$
ignoreregex =
Test:
fail2ban-regex /data/docker/mailsys/postfix/alpine-3.22.1/log/postfix.log /etc/fail2ban/filter.d/postfix-pipelining.conf -v
If the output shows:
Failregex: 10 total
Lines: 293 lines, 0 ignored, 10 matched
then your filter works correctly.
✅ Method 2: Manually Define Missing Variables
If you want to keep the original regex syntax, add these lines to the filter before failregex:
__prefix_ipv4 = (?:(?:25[0-5]|2[0-4]\d|[01]?\d?\d)(?:\.(?:25[0-5]|2[0-4]\d|[01]?\d?\d)){3})
__prefix_ipv6 = (?:[0-9A-Fa-f:]+)
4. Add a Jail for Postfix Pipelining
Create /etc/fail2ban/jail.d/postfix-pipelining.local:
[postfix-pipelining]
enabled = true
filter = postfix-pipelining
logpath = /data/docker/mailsys/postfix/alpine-3.22.1/log/postfix.log
port = smtp,submission,465,587
maxretry = 3
findtime = 10m
bantime = 1h
ignoreip = 127.0.0.1/8 ::1 your_whitelist_IPs
banaction = iptables-multiport
Reload:
fail2ban-server reload
fail2ban-client status postfix-pipelining
5. Extended Example: postfix-noqueue-connect Filter
[INCLUDES]
before = common.conf
[Definition]
_daemon = postfix(-.*)?/smtpd
failregex = ^%(__prefix_line)s(?:postfix/(?:smtpd|submission/smtpd)\[\d+\]: )?NOQUEUE: lost connection after CONNECT from (?:\S+)?\[(?P<host><HOST>)\]
ignoreregex =
Jail example:
[postfix-noqueue-connect]
enabled = true
filter = postfix-noqueue-connect
logpath = /data/docker/mailsys/postfix/alpine-3.22.1/log/postfix.log
backend = auto
port = smtp,submission,465,587
maxretry = 3
findtime = 10m
bantime = 1h
6. Conclusion
After applying these fixes, Fail2Ban successfully detects and bans IPs attempting noisy or malformed Postfix connections.
Using <HOST> ensures compatibility across Fail2Ban versions and avoids interpolation errors on older Python 2-based systems.