Server — Mail — Virtual Domains

Posted on 9 2026

A fresh Postfix installation accepts mail for one domain: the server’s own hostname, set in mydestination. That is enough for a server sending system notifications to a local user. It is not enough for a server that needs to receive mail for yourdomain.com, serve it over IMAP to a mail client, and potentially receive mail for a second domain alongside the first.

Virtual domains are Postfix’s mechanism for accepting mail for any number of domains beyond the server’s own hostname. Understanding how Postfix thinks about domains before configuring anything prevents the most common category of mistakes.

How Postfix categorises domains

Postfix has three distinct ways of handling a domain, and they are mutually exclusive. A domain can be in exactly one of these categories. Putting a domain in more than one produces errors and unpredictable behaviour.

Local domains (mydestination) are the server’s own identities. Mail for a local domain is delivered to system user mailboxes by the local delivery agent. localhost, february, and february.home.arpa are local domains. Your internet-facing domain should not be in mydestination unless you want mail delivered to Linux system accounts.

Virtual alias domains (virtual_alias_domains) accept mail for a domain and rewrite each address to a different address before delivering it. Mail for user@yourdomain.com might be rewritten to localuser (a system account) or to someone@elsewhere.com (a remote address). The domain itself has no mailboxes; it is entirely an alias layer on top of something else.

Virtual mailbox domains (virtual_mailbox_domains) accept mail for a domain and deliver it to virtual mailboxes: directories on disk that are not tied to Linux system accounts. This is the right approach for a proper multi-domain mail server where each address has its own mailbox, accessible over IMAP via Dovecot.

For February’s setup, virtual mailbox domains is the correct model. Each address at each domain gets its own Maildir on disk. Dovecot serves those Maildirs over IMAP. Neither approach requires creating a Linux user account for each mail address.

The vmail system user

Virtual mailboxes are stored on disk and need to be owned by a system user. The convention is a dedicated vmail user with a fixed UID and GID, which Postfix uses for all virtual mailbox delivery. This user has no shell and no home directory in the conventional sense; it exists purely to own the mail storage.

Create it:

sudo groupadd -g 2000 vmail
sudo useradd -g vmail -u 2000 vmail -d /var/vmail -m -s /sbin/nologin

Create the mail storage directory:

sudo mkdir -p /var/vmail
sudo chown -R vmail:vmail /var/vmail
sudo chmod 770 /var/vmail

Every virtual mailbox on February will be a subdirectory under /var/vmail, structured as /var/vmail/domain/localpart/ in Maildir format. Postfix creates these directories automatically on first delivery.

Configuring virtual mailbox domains in Postfix

Virtual domain configuration in Postfix involves three files working together, referenced from /etc/postfix/main.cf.

main.cf additions

Add the following to /etc/postfix/main.cf:

# Virtual mailbox domain configuration
virtual_mailbox_domains = /etc/postfix/virtual_domains
virtual_mailbox_base = /var/vmail
virtual_mailbox_maps = hash:/etc/postfix/virtual_mailbox_maps
virtual_alias_maps = hash:/etc/postfix/virtual_aliases
virtual_minimum_uid = 100
virtual_uid_maps = static:2000
virtual_gid_maps = static:2000

virtual_mailbox_domains points to a file listing the domains Postfix should accept mail for as virtual mailbox domains. Each domain in this file must not appear in mydestination.

virtual_mailbox_base is the root directory for all virtual mailbox storage. Postfix prepends this path to the mailbox paths defined in virtual_mailbox_maps.

virtual_mailbox_maps maps each email address to a mailbox path relative to virtual_mailbox_base. The trailing slash designates Maildir format rather than mbox.

virtual_alias_maps handles address aliases: addresses that should deliver to a different address rather than their own mailbox.

virtual_uid_maps = static:2000 and virtual_gid_maps = static:2000 tell Postfix to use UID 2000 (the vmail user) for all virtual mailbox delivery.

Critically: ensure that none of the domains you add to virtual_mailbox_domains appear in mydestination. Check the current value:

postconf mydestination

The output will show something like:

mydestination = $myhostname, february, localhost.localdomain, localhost

None of your internet-facing domains should be in this list. If they are, remove them before adding them to virtual_mailbox_domains.

virtual_domains

Create /etc/postfix/virtual_domains:

yourdomain.com      OK
seconddomain.com    OK

Each line is a domain followed by any non-empty value. The value is arbitrary; OK is conventional. Add one line per domain February should accept mail for.

This file is read directly by Postfix without indexing. No postmap command needed for this one.

virtual_mailbox_maps

Create /etc/postfix/virtual_mailbox_maps:

you@yourdomain.com          yourdomain.com/you/
admin@yourdomain.com        yourdomain.com/admin/
postmaster@yourdomain.com   yourdomain.com/postmaster/
you@seconddomain.com        seconddomain.com/you/

Each line maps an email address to a mailbox path relative to /var/vmail. The trailing slash is required: it designates Maildir format. Without it, Postfix uses mbox format, which is the wrong choice for a server also running Dovecot.

After creating or modifying this file, rebuild the index:

sudo postmap /etc/postfix/virtual_mailbox_maps

Run postmap every time this file changes. Postfix reads the indexed .db file, not the plain text file. Changes to the plain text file without running postmap are silently ignored.

virtual_aliases

Create /etc/postfix/virtual_aliases:

postmaster@yourdomain.com   you@yourdomain.com
abuse@yourdomain.com        you@yourdomain.com
root@yourdomain.com         you@yourdomain.com

RFC 2142 requires that certain addresses exist at every domain: postmaster, abuse, and a few others. Rather than creating separate mailboxes for each, alias them to a real mailbox. Mail to postmaster@yourdomain.com delivers to you@yourdomain.com’s mailbox.

Build the index:

sudo postmap /etc/postfix/virtual_aliases

Reloading and testing

Reload Postfix to pick up the configuration changes:

sudo postfix check
sudo systemctl reload postfix

postfix check validates the configuration before reloading. Fix any errors it reports before proceeding.

Verify Postfix recognises the virtual domain:

postmap -q yourdomain.com /etc/postfix/virtual_domains

This should return OK. If it returns nothing, the domain is not in the file or the file path in main.cf is wrong.

Verify an address maps to a mailbox:

postmap -q you@yourdomain.com hash:/etc/postfix/virtual_mailbox_maps

This should return yourdomain.com/you/. If it returns nothing, either the address is not in the file or postmap has not been run since the last change.

Adding a new domain

The process for adding a second or subsequent domain is always the same:

  1. Add the domain to /etc/postfix/virtual_domains.
  2. Add the addresses and mailbox paths to /etc/postfix/virtual_mailbox_maps.
  3. Add any required aliases to /etc/postfix/virtual_aliases.
  4. Run postmap on both hash map files.
  5. Add the MX record in PowerDNS.
  6. Reload Postfix.

The order matters slightly: Postfix should be reloaded only after the MX record is live, or inbound mail may arrive before the local configuration is ready to accept it. In practice the DNS propagation delay provides enough of a buffer, but the habit of doing DNS last is worth keeping.

What is not covered here

This article covers the Postfix side of virtual domain configuration. Two things connect to it that are covered separately:

Dovecot needs to be configured to serve the Maildir mailboxes that Postfix delivers into. The mail_location setting in Dovecot must match the virtual_mailbox_base path and the directory structure defined in the mailbox maps. That configuration is in the Dovecot article.

DNS needs MX records for each virtual domain pointing at February. Without the MX record, mail for that domain is not directed to February and no local configuration matters. The DNS records article covers MX alongside SPF, DKIM, and DMARC.