Hosting multi-domain email on an Ubuntu Linux server does not require creating a local UNIX system account in /etc/passwd for every mailbox. By configuring Postfix Virtual Mailbox Domains, systems administrators can route and store incoming mail for dozens of independent domains inside isolated filesystem directories, drastically reducing the server's SSH and local privilege-escalation attack surface.
Why Use Non-UNIX Virtual Mailboxes?
In a traditional local delivery setup, adding an address like support@example.com requires provisioning a system user via useradd. Even when restricted with /usr/sbin/nologin, maintaining hundreds of OS-level accounts clutters system authentication tables and creates namespace collisions when two hosted domains need an info@ or sales@ mailbox. Postfix's virtual(8) delivery agent solves this by mapping recipient addresses directly to Maildir paths owned by a single unprivileged virtual mail UID/GID.
Step 1: Package Installation & Reverse DNS (rDNS) Alignment
Begin by installing the Postfix mail transfer agent (MTA) on Ubuntu and selecting Internet Site when prompted by debconf:
sudo apt-get update
sudo apt-get install postfix mailutils
HELO Banner and PTR Record Matching
Before configuring virtual domains, verify that the server's public IP address has a valid Reverse DNS (PTR) record matching the hostname declared in Postfix's myhostname parameter. Major receiving providers—including Gmail, Outlook, and AOL—immediately reject or quarantine outbound SMTP sessions if the EHLO / HELO banner does not match the IP's reverse lookup:
# /etc/postfix/main.cf
myhostname = mail.winwinhost.com
mydomain = winwinhost.com
myorigin = $mydomain
inet_interfaces = all
inet_protocols = ipv4
Step 2: Creating the Dedicated Virtual Mail Owner & Directory Tree
A common pitfall when following abbreviated guides is neglecting to create the underlying base directory or assigning incorrect ownership. Postfix's virtual(8) delivery daemon requires a dedicated non-root system user (commonly vmail with UID/GID 5000) and pre-existing parent directories:
# Create a dedicated vmail group and user with UID/GID 5000
sudo groupadd -g 5000 vmail
sudo useradd -g vmail -u 5000 vmail -d /var/mail/vhosts -s /usr/sbin/nologin
# Create the base directory and domain-specific subdirectory
sudo mkdir -p /var/mail/vhosts/winwinhost.com
sudo chown -R vmail:vmail /var/mail/vhosts
sudo chmod -R 770 /var/mail/vhosts
Step 3: Configuring Virtual Mailbox Directives in main.cf
Append the virtual mailbox parameters to /etc/postfix/main.cf, pointing Postfix to the base storage path, the indexed lookup tables, and the static UID/GID maps:
# Virtual Mailbox Domain Configuration
virtual_mailbox_domains = winwinhost.com, example.org
virtual_mailbox_base = /var/mail/vhosts
virtual_mailbox_maps = hash:/etc/postfix/vmailbox
virtual_alias_maps = hash:/etc/postfix/virtual
virtual_minimum_uid = 100
virtual_uid_maps = static:5000
virtual_gid_maps = static:5000
If you ever need to verify an existing user's numeric UID and GID on the system, inspect /etc/passwd directly:
grep vmail /etc/passwd
# Output: vmail:x:5000:5000::/var/mail/vhosts:/usr/sbin/nologin
Step 4: Populating and Compiling Lookup Tables with postmap
Postfix does not read raw plaintext mapping files during live SMTP transactions; instead, it queries binary Berkeley DB (.db) hash files for $O(1)$ lookup speed. First, define your recipient-to-Maildir mappings in /etc/postfix/vmailbox (note that trailing slashes instruct Postfix to use Maildir format rather than legacy single-file mbox format):
# /etc/postfix/vmailbox
info@winwinhost.com winwinhost.com/info/
admin@winwinhost.com winwinhost.com/admin/
support@example.org example.org/support/
Next, define any forwarding aliases or catch-all rules in /etc/postfix/virtual:
# /etc/postfix/virtual
postmaster@winwinhost.com admin@winwinhost.com
sales@winwinhost.com info@winwinhost.com
Compiling the Binary Hash Databases
Whenever you create or modify /etc/postfix/vmailbox or /etc/postfix/virtual, you must compile them into vmailbox.db and virtual.db using postmap and reload the daemon:
sudo postmap /etc/postfix/vmailbox
sudo postmap /etc/postfix/virtual
sudo postfix check
sudo systemctl reload postfix
Step 5: Real-Time Diagnostics via /var/log/mail.log
When messages fail to deliver or remain stuck in the active queue, /var/log/mail.log provides immediate visibility into the exact failure stage:
sudo tail -f /var/log/mail.log
fatal: open database /etc/postfix/vmailbox.db: No such file or directory: Indicates thatsudo postmap /etc/postfix/vmailboxhas not been executed yet.status=deferred (maildir delivery failed: create maildir file ... Permission denied): Indicates that/var/mail/vhostsis not owned by the UID/GID specified invirtual_uid_mapsandvirtual_gid_maps.User unknown in virtual mailbox table: The recipient address is listed invirtual_mailbox_domains, but no matching entry exists in/etc/postfix/vmailboxor/etc/postfix/virtual.
