Postfix Alias Maps vs Virtual Alias Maps: Key Differences and Practical Usage Guide


1 views

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:

  1. Virtual alias maps
  2. Canonical maps
  3. 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:

  1. Postfix first checks virtual_alias_maps when recipient contains '@'
  2. For local delivery (no domain), it falls back to alias_maps
  3. 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:

  1. It treats 'root' as a local user (no @domain)
  2. Postfix adds myorigin during SMTP transaction
  3. Resulting address matches virtual_alias_maps patterns