--- title: "How to Configure Aliases and Virtual Domains in Postfix" description: "Set up local aliases, forwarding-only virtual alias domains, virtual mailbox domains with Dovecot, catch-all addresses and plus addressing in Postfix." category: "Email Server" language: en source: https://cubepath.com/docs/email-server/alias-and-virtual-domains-configuration-in-postfix updated: 2026-09-25 --- # How to Configure Aliases and Virtual Domains in Postfix Postfix can deliver mail for many addresses and domains without creating a system account for each one. Aliases redirect one address to another, virtual alias domains forward a whole domain's mail elsewhere, and virtual mailbox domains host real mailboxes for several domains on one server. In this tutorial you will configure each of these on Ubuntu 24.04, add a catch-all address and plus addressing, and verify every lookup before sending real mail. ## Prerequisites To follow this tutorial, you need: - A server running Ubuntu 24.04 LTS with Postfix installed and receiving mail for your main domain, for example a CubePath VPS. - A non-root user with `sudo` privileges. - MX records pointing to your server for every domain you add. This guide uses `your_domain` as the main domain and `example.net` and `example.org` as additional domains. - For Step 3 only: Dovecot configured for virtual users and listening for LMTP, as covered in the Postfix and Dovecot setup guide. ## Understanding the three address classes Postfix decides how to handle a recipient by the domain it belongs to. A domain must be listed in exactly one of these classes: | Class | Parameter listing the domains | Recipients are | Typical use | |-------|------------------------------|----------------|-------------| | Local | `mydestination` | Linux user accounts, plus `/etc/aliases` | The server's own name, system mail | | Virtual alias | `virtual_alias_domains` | Only aliases, forwarded elsewhere | A domain with no mailboxes that forwards everything | | Virtual mailbox | `virtual_mailbox_domains` | Mailboxes not tied to Linux users | Hosting mail for several domains | `virtual_alias_maps` is special: it applies to every class, so it is also where you add aliases and catch-alls for virtual mailbox domains. > Warning: Never list the same domain in `mydestination` and in one of the virtual parameters. Postfix will log `do not list domain ... in BOTH mydestination and virtual_alias_domains` and mail for the domain will not be delivered as expected. Check your current settings: ```bash postconf mydestination virtual_alias_domains virtual_mailbox_domains ``` ```output mydestination = $myhostname, your_domain, localhost.localdomain, localhost virtual_alias_domains = $virtual_alias_maps virtual_mailbox_domains = $virtual_mailbox_maps ``` ## Step 1 - Configuring local aliases Local aliases in `/etc/aliases` apply to domains in `mydestination`. They are mainly used to route system mail (from cron jobs, `root` and daemons) to a person who reads it. Open the file: ```bash sudo nano /etc/aliases ``` Make sure it contains these lines, replacing `your_user` with your Linux user or an external address: ```text postmaster: root root: your_user webmaster: your_user abuse: your_user ``` An alias can point to several destinations separated by commas, for example `root: your_user, admin@example.com`. The `postmaster` and `abuse` addresses are expected to exist on every mail domain. Postfix reads the compiled version of this file, so rebuild it after every change: ```bash sudo newaliases ``` Check how an address resolves: ```bash postmap -q root hash:/etc/aliases ``` ```output your_user ``` ## Step 2 - Creating a forwarding-only virtual alias domain A virtual alias domain accepts mail for a domain and forwards every address to another mailbox, local or external. Postfix rejects any address in the domain that has no alias, so there is no risk of accepting mail it cannot deliver. Create the alias table: ```bash sudo nano /etc/postfix/virtual ``` Add one line per address, with the address on the left and one or more destinations on the right: ```text info@example.net you@your_domain sales@example.net you@your_domain, colleague@gmail.com support@example.net helpdesk@your_domain ``` Tell Postfix which domains are alias-only and where the table is: ```bash sudo postconf -e 'virtual_alias_domains = example.net' sudo postconf -e 'virtual_alias_maps = hash:/etc/postfix/virtual' ``` Compile the table into the indexed format Postfix reads, and reload: ```bash sudo postmap /etc/postfix/virtual sudo systemctl reload postfix ``` Every time you edit `/etc/postfix/virtual`, run `sudo postmap /etc/postfix/virtual` again. A reload is not needed for table changes; Postfix picks up the new `.db` file automatically. Test the lookup: ```bash postmap -q sales@example.net hash:/etc/postfix/virtual ``` ```output you@your_domain, colleague@gmail.com ``` > Note: Forwarding to external mailboxes such as Gmail breaks SPF for the original sender, and forwarding spam damages your server's reputation. Prefer local destinations, and filter spam before forwarding. ## Step 3 - Hosting mailboxes for several domains Virtual mailbox domains store mail in real mailboxes that do not need a Linux account. Postfix only decides whether the recipient exists and then hands the message to Dovecot over LMTP, which stores it. This step assumes Dovecot is already configured for virtual users. Create the mailbox table, listing every mailbox that exists: ```bash sudo nano /etc/postfix/vmailbox ``` ```text alice@example.org example.org/alice/ bob@example.org example.org/bob/ ``` When delivery goes to Dovecot, Postfix uses this table only to know which recipients are valid; the value on the right is ignored but must be present. The mailboxes themselves (and their passwords) are defined in Dovecot. Configure the domain, the table and the delivery transport: ```bash sudo postconf -e 'virtual_mailbox_domains = example.org' sudo postconf -e 'virtual_mailbox_maps = hash:/etc/postfix/vmailbox' sudo postconf -e 'virtual_transport = lmtp:unix:private/dovecot-lmtp' ``` `private/dovecot-lmtp` is the socket Dovecot creates at `/var/spool/postfix/private/dovecot-lmtp` when its LMTP service is configured for Postfix. Confirm it exists before continuing: ```bash sudo ls -l /var/spool/postfix/private/dovecot-lmtp ``` Compile the table and reload Postfix: ```bash sudo postmap /etc/postfix/vmailbox sudo systemctl reload postfix ``` To add an alias for a virtual mailbox domain, put it in `/etc/postfix/virtual`, the same table as Step 2: ```text hello@example.org alice@example.org ``` Then run `sudo postmap /etc/postfix/virtual`. ## Step 4 - Adding a catch-all address A catch-all receives mail for every address in a domain that does not match anything more specific. Write the domain with a leading `@` in `/etc/postfix/virtual`: ```text @example.net you@your_domain ``` For a forwarding-only domain like `example.net`, that is all you need. For a virtual mailbox domain, a catch-all in `virtual_alias_maps` also captures mail for the real mailboxes, because aliases are resolved before mailboxes. Map each existing mailbox to itself first, so it keeps receiving its own mail: ```text alice@example.org alice@example.org bob@example.org bob@example.org @example.org alice@example.org ``` Compile the table and test both a real and a nonexistent address: ```bash sudo postmap /etc/postfix/virtual postmap -q bob@example.org hash:/etc/postfix/virtual postmap -q anything@example.org hash:/etc/postfix/virtual ``` ```output bob@example.org ``` The second query prints nothing, because `postmap -q` looks up the exact key only. Postfix itself tries the full address first and then `@example.org`, so check the catch-all key directly: ```bash postmap -q @example.org hash:/etc/postfix/virtual ``` ```output alice@example.org ``` Catch-all addresses attract large amounts of spam sent to random addresses. Use them only for a limited time, for example while migrating a domain, and remove the `@domain` line when you no longer need it. ## Step 5 - Enabling plus addressing Plus addressing lets a user hand out variations of their address, such as `alice+shop@example.org`, that are all delivered to `alice@example.org`. It is useful for filtering and for spotting which service leaked an address. Enable it by setting the separator character: ```bash sudo postconf -e 'recipient_delimiter = +' sudo systemctl reload postfix ``` Check the value: ```bash postconf recipient_delimiter ``` ```output recipient_delimiter = + ``` Postfix now strips everything from `+` to `@` when an address with an extension does not have its own entry in the tables. Dovecot receives the full address, so Sieve rules can file messages by extension if Dovecot's `recipient_delimiter` setting is also `+` (which is its default). ## Step 6 - Sending test messages Table lookups prove the configuration, but a real delivery proves the whole chain. Send a message to each type of address from the server: ```bash printf 'Subject: alias test\n\nForwarding test.\n' | sudo sendmail sales@example.net printf 'Subject: mailbox test\n\nMailbox test.\n' | sudo sendmail alice+test@example.org ``` Follow the deliveries in the mail log: ```bash sudo tail -n 20 /var/log/mail.log ``` ```output postfix/smtp[7311]: 4cKz0f2GqXz9sWd: to=, orig_to=, relay=gmail-smtp-in.l.google.com[142.250.153.27]:25, ... status=sent (250 2.0.0 OK ...) postfix/lmtp[7312]: 4cKz0g0VtXz9sWf: to=, orig_to=, relay=mail.your_domain[private/dovecot-lmtp], ... status=sent (250 2.0.0 Saved) ``` `orig_to` shows the address the message was sent to, and `to` shows where the aliases sent it. Finally, test from outside by sending a message from an external mailbox to an address on each new domain, which also confirms that the MX records are correct. ## Troubleshooting - **`Recipient address rejected: User unknown in virtual alias table`.** The address is in a virtual alias domain but has no line in `/etc/postfix/virtual`, or you edited the file without running `postmap`. Add the line and run `sudo postmap /etc/postfix/virtual`. - **`Relay access denied` for a new domain.** The domain is not listed in `virtual_alias_domains`, `virtual_mailbox_domains` or `mydestination`. Check with `postconf` and add it. - **Changes to `/etc/aliases` have no effect.** Run `sudo newaliases`. The file only applies to domains in `mydestination`, not to virtual domains. - **Mail to a virtual mailbox stays deferred with `connect to private/dovecot-lmtp: No such file or directory`.** Dovecot's LMTP service is not running or not listening in the Postfix spool. Check `systemctl status dovecot` and its LMTP socket configuration. - **Real mailboxes stopped receiving mail after adding a catch-all.** Add the self-mapping lines shown in Step 4. ## Conclusion Your Postfix server now routes system mail through local aliases, forwards whole domains with virtual alias tables, hosts mailboxes for several domains through Dovecot, and supports catch-all and plus addresses. Each additional domain you host needs its own DNS records, so as next steps publish SPF and DMARC for it as described in [How to Configure SPF and DMARC Records](/docs/email-server/spf-and-dmarc-configuration) and add it to your DKIM signing table following [How to Set Up DKIM with OpenDKIM and Postfix](/docs/email-server/dkim-configuration-for-email-authentication).