In Postfix, alias_maps
and virtual_alias_maps
serve distinct purposes despite their similar names. The traditional Unix aliases (handled by alias_maps
) primarily manage system-wide email forwarding for local accounts, while virtual_alias_maps
handles address rewriting for both local and non-local domains.
# Typical alias_maps configuration in main.cf
alias_maps = hash:/etc/aliases
alias_database = hash:/etc/aliases
# Typical virtual_alias_maps configuration
virtual_alias_maps = hash:/etc/postfix/virtual
The shift in Fail2ban's behavior occurs because Postfix processes virtual alias lookups before checking the system aliases. When both maps contain entries for the same address, the virtual alias takes precedence. This explains why your Fail2ban emails initially followed /etc/aliases but then switched to the virtual alias map.
Use alias_maps when:
- Managing local system account mail forwarding (root, postmaster, etc.)
- Working with traditional Unix mail services that expect /etc/aliases
- Handling system-generated messages from cron, logwatch, etc.
Use virtual_alias_maps when:
- Redirecting mail for non-local domains
- Creating catch-all addresses
- Implementing complex address rewriting
- Managing mail for virtual domains
Postfix evaluates addresses in this sequence:
- Virtual alias maps
- Canonical maps
- Local aliases (alias_maps)
This explains why your mail root
command failed when relying solely on /etc/aliases - the message was being treated as for a remote domain before the local alias could be applied.
Here's a robust setup that handles both local and virtual aliases:
# /etc/aliases
root: admin@actualdomain.com
postmaster: root
# /etc/postfix/virtual
root@mydomain.com admin@actualdomain.com
@otherdomain.com catchall@actualdomain.com
And the corresponding main.cf entries:
alias_maps = hash:/etc/aliases
alias_database = hash:/etc/aliases
virtual_alias_maps = hash:/etc/postfix/virtual
Problem: Some services ignore /etc/aliases
Solution: Ensure myorigin
matches your system's domain and consider adding virtual aliases for critical addresses.
Problem: Duplicate delivery when using both maps
Solution: Pick one system (usually virtual aliases) for each address to avoid conflicts.
For complex environments, consider using database-backed alias maps:
virtual_alias_maps = mysql:/etc/postfix/mysql-virtual-alias-maps.cf
Sample mysql-virtual-alias-maps.cf:
user = postfix
password = yourpassword
hosts = 127.0.0.1
dbname = postfix
query = SELECT destination FROM virtual_aliases WHERE source='%s'
After digging through Postfix documentation and numerous tests, I've identified the core distinction:
alias_maps
handles local system aliases (UNIX accounts)virtual_alias_maps
manages virtual domain aliases (email-only addresses)
The separation stems from historical UNIX mail architecture:
# Traditional UNIX aliases (/etc/aliases)
postmaster: root
webmaster: admin@domain.com
# Virtual aliases (/etc/postfix/virtual)
info@domain.com support-team@external.com
sales@domain.com person1@gmail.com,person2@protonmail.com
Your observations reveal the lookup sequence:
- Postfix first checks
virtual_alias_maps
when recipient contains '@' - For local delivery (no domain), it falls back to
alias_maps
- The
myorigin
parameter appends domain to bare addresses
Here's a working setup for a mail-only server:
# main.cf
alias_maps = hash:/etc/aliases
virtual_alias_maps = hash:/etc/postfix/virtual
# /etc/aliases
root: admin@primary.com
nobody: /dev/null
# /etc/postfix/virtual
root@serverhostname.com admin@primary.com
abuse@domain.com legal-team@company.org
The service switch occurs because:
- Initial setup: fail2ban sends to root@localhost → handled by alias_maps
- After virtual_alias_maps: Postfix recognizes localhost as a domain → prefers virtual mapping
For modern mail-only servers:
# Disable local delivery completely
mydestination =
local_recipient_maps =
alias_maps = hash:/etc/aliases # For legacy compatibility only
virtual_alias_maps = hash:/etc/postfix/virtual
The mail
utility behavior differs because:
- It treats 'root' as a local user (no @domain)
- Postfix adds
myorigin
during SMTP transaction - Resulting address matches virtual_alias_maps patterns