I’m currently moving virtual servers from an old Virtualmin hosting instance to a new one. Because I do not have time for moving all virtual servers at once I need to make sure the commonly used server name for accessing IMAP, POP and SMTP will work for both - users already moved and users still using the old server. Since I did not find an easy to follow How-To for a scenario like this I just want to share here what worked for me.

Current and desired scenarios

That’s the situation before any users got moved - both servers are running the Virtualmin stack (Dovecot, Postfix):

  1. => CNAME for

The idea is to transparently switch to this configuration:

  2. => CNAME for

Still many users need to access their email at I don’t want to ask everyone to change the configuration of their email clients from to the new or old server depending on there current status.

Note:, and are just examples.


The solution is to have act as proxy for (common email protocols only): users of are able to authenticate at even if does not know them.

Instead need to forward (proxy) the authentication request to for unknown users. But it must only forward authentication requests for users or domains which actually exists at

Also need to proxy IMAP/POP data from the user’s email client to SMTP traffic does not need to be proxied because users can send email using both servers if the SPF record of their domains are configured accordingly.

Now to the real configuration as it is working at my - a box running CentOS 8 btw.

Proxying Dovecot authentication and traffic

Dovecot authentication is handled by password databases (passdb). It can use more than one. Good for us: a second one will be used as fallback if the first one failed. So what we need is a passdb which forwards authentication request to in case it doesn’t find the user locally (at

  1. Create a file /etc/dovecot/conf.d/old-server-auth-proxy.conf.ext containing:
# Authentication for passwd-file users. Included from 10-auth.conf.
# passwd-like file with specified location.
# <doc/wiki/AuthDatabase.PasswdFile.txt>

passdb {
  driver = passwd-file
  args = username_format=%Ld /etc/dovecot/old-server-proxy.passwd
  1. Create the passwd-like file /etc/dovecot/old-server-proxy.passwd which defines what domains are allowed to be proxied:
# Used by conf.d/old-server-auth-proxy.conf.ext
# No restart needed if conten changes.
domain1.tld::::::: nopassword=y proxy=y ssl=any-cert
domain2.tld::::::: nopassword=y proxy=y ssl=any-cert host=<IP of>
  • One line per domain (aka Virtual server). It will work for all users of that domain. You may use a user-centric approach instead.
  • nopassword=y Authentication takes place at (works for IMAP authentication mechanisms plain only).
  • proxy=y Enables the proxying.
  • ssl=any-cert Use SSL port (993) but disable SSL cert verification. I did not get verification working when using the Let’s Encrypt CA. See notes at the Proxy PasswordDatabase documentation about this.
  • Use hostname or IP of the server the authentication request must be send to.

See the Proxy PasswordDatabase documentation for more options and explanations.

  1. Load old-server-auth-proxy.conf.ext in the Dovecot configuration:
echo "!include old-server-auth-proxy.conf.ext" | sudo tee -a /etc/dovecot/conf.d/10-auth.conf

systemctl restart dovecot

That’s the IMAP/POP part - let’s test it.

At - no proxying needed

openssl s_client -connect

. login user@domain1.tld <password in plain text>
. list "" "*"
. logout

Should generate something like:

* LIST (\HasNoChildren \Drafts) "." Drafts
* LIST (\HasNoChildren \Sent) "." Sent
* LIST (\HasNoChildren) "." trash
* LIST (\HasNoChildren) "." spam
* LIST (\HasNoChildren \Trash) "." Trash
* LIST (\HasNoChildren) "." INBOX
. OK List completed.
* BYE Logging out
. OK Logout completed.

Now try the same with The same IMAP commands will work regardless if used directly at or forwarded to it by new-server.

Watch the Dovecot logs at for entries like:

Jul 30 10:26:07 auth[46950]: pam_unix(dovecot:auth): check pass; user unknown
Jul 30 10:26:07 auth[46950]: pam_unix(dovecot:auth): authentication failure; logname= uid=0 euid=0 tty=dovecot ruser=user@domain1.tld rhost=2a02:xxx:yyy:zzz:xxx:yyy:zzz:xxx

Jul 30 10:26:08 dovecot[1284]: imap-login: proxy(user@domain1.tld): started proxying to user=<user@domain1.tld>, method=PLAIN, rip=2a02:xxx:yyy:zzz:xxx:yyy:zzz:xxx, lip=2a01:xxx:yyy:zzz::4, TLS, session=<+AGX+FLINOMqAoEKgwAkgF2gVQTxqs9s>
Jul 30 10:26:08 dovecot[1284]: imap-login: proxy(user@domain1.tld): disconnecting 2a02:xxx:yyy:zzz:xxx:yyy:zzz:xxx (Disconnected by server(0s idle, in=307, out=761)): user=<user@domain1.tld>, method=PLAIN, rip=2a02:xxx:yyy:zzz:xxx:yyy:zzz:xxx, lip=2a01:xxx:yyy:zzz::4, TLS, session=<+AGX+FLINOMqAoEKgwAkgF2gVQTxqs9s>

As you can see Dovecot first tries to authenticate user@domain1.tld as local user (via PAM). When that fails it tries the next available mechanism which is our newly configured passwd-file based proxy.

Next step will be..

Proxying SMTP authentication

Only authentication requests need to be proxied from to old-server. Users of can send email through if will be added to the SPF record of the user’s domain as an allowed sending host.

So if the SPF record of domain1.tld was:

"v=spf1 mx -all"

It will become:

"v=spf1 mx -all"

That is still correct after moving domain1.tld from to although probably somewhat redundant if the MX(s) of domain1.tld will be the same as

Last todo is switching Postfix to authenticate using Dovecot. Dovecot has an answer for that too - search for the # Postfix smtp-auth part in /etc/dovecot/conf.d/10-master.conf and insert/activate there the following configuration there (inside of the service auth {} section):

# Postfix smtp-auth
unix_listener /var/spool/postfix/private/auth {
  mode = 0660
  user = postfix
  group = postfix

Postfix in Virtualmin is configured to use Cyrus SASL for authentication. Configure it to use Dovecot instead. At a teminal enter:

postconf smtpd_sasl_auth_enable=yes
postconf smtpd_sasl_path=private/auth
postconf smtpd_sasl_type=dovecot

Now restart both and watch their logs:

systemctl restart dovecot
postfix reload

journalctl -xf -u dovecot -u postfix

Test it using your Email client or a tool like Swaks - Swiss Army Knife SMTP:

swaks --from user@domain1.tld --to someone@else.tld \
  --auth --auth-user user@domain1.tld --auth-password '***' \
  --tls --server

You should see many lines of SMTP protocol speak and between it a successful authentication as well as sending of the email:

<~  235 2.7.0 Authentication successful
<~  250 2.0.0 Ok: queued as 65C3C2013C6D
 ~> QUIT
<~  221 2.0.0 Bye

The Dovecot log will contain the same imap-login: proxy(user@domain1.tld) entries as seen above.

Questions? Discuss it at the Virtualmin Forum.