You know how it is. Your little mail host has just sat there for a long while, slowly accreting a user here and a user there. They are all full users on the machine, so they have logins and everything, and exim
is configured to deliver their mails to ~/Maildir.
And then some dangerous loon suddenly demands that you add mailboxes for people using a completely different domain. They're not really much to do with you, and certainly shouldn't be full-blown users on your host.
Time, then, to add virtual mailboxes to your poor little mail host.
There all sorts of HOWTOs on doing this, of various ages and usefulness. I'm adding this page to the malestrom just to document the configuration changes I did. Or rather, the configuration changes I ended up with. The details of configuration aren't original, but synthesised from too many of the HOWTOs I read to properly credit each.
I'm illustrating this by setting up a new domain example.mod with user tommy.atkins.
First I created a user and group vmail
to own all virtual mailboxes. I make the user a normal user because Dovecot will try to access all virtual mailboxes as that vmail
user, and in Dovecot 2.x on Debian the config first_valid_uid
is set to 500 to prevent attempts to access daemon mailboxes.
# adduser --home /var/local/vmail --group vmail
and a configuration directory.
# mkdir /etc/vmail
Configuration information for the domain will be under /etc/vmail/<domain>
. If that directory doesn't exist, the domain isn't supported.
# mkdir /etc/vmail/example.mod
The general scheme is that we have mailboxes under /var/local/vmail/<domain>/<user>/Maildir
. Why Maildir
? Because our existing users will continue to get mail in ~/Maildir
and it keeps dovecot
config a little simpler.
# mkdir -p /var/local/vmail/example.mod # chown -R vmail:vmail /var/local/vmail
Now add two configuration files. The first, aliases
, is a conventional aliases file for the domain.
# cat > /etc/vmail/example.mod/aliases postmaster: root webmaster: root security: root admin: root root: guru@example-owner.mod squaddie: tommy.atkins ^D
The second, passwd
contains the account information for the domain. There are two items on a line, username and password hash, separated by a colon. Generate the password has using the dovecotadm pw
utility. Just to be on the safe side, we'll ensure the password file isn't world readable and is readable by Dovecot and Exim.
# doveadm pw -s SHA256-CRYPT -p password {SHA256-CRYPT}$5$TQGxffy9XCxe53vu$L2NWgKJ47w3PoAIj3/IxLJIREA9QSyBKdKDMJlXvn07 # cat > /etc/vmail/example.mod/passwd tommy.atkins:{SHA256-CRYPT}$5$TQGxffy9XCxe53vu$L2NWgKJ47w3PoAIj3/IxLJIREA9QSyBKdKDMJlXvn07 ^D # chown dovecot:vmail /etc/vmail/example.mod/passwd # adduser Debian-exim vmail # chmod 0660 /etc/vmail/example.mod/passwd
The next step is to configure Exim to deliver to virtual mailboxes.
Exactly how you do this depends on which of Debian's configuration schemes you are using. I am using the conf.d
multiple configuration file hierarchy with the config type internet
. From here on, I'll show what I ended up with in the Exim configuration file, and indicate where I put each entry in the conf.d
hierarchy. Please treat these as an illustration; if you have a setup reasonably close to the standard installed version then I think these will probably work for you, but I can't promise.
The first thing to do is to add the domain to the list of local domains. You need to end up with a configuration file with the domain as part of the domainlist local_domains
. I wanted to have the virtual mail domains work automatically, rather than have to add them manually to the list of local domains. I first added a configuration main/00_vmail_config
with some definitions:
VMAIL_DELIVERY=dovecot_vmail VMAIL_DOMAINS=dsearch;/etc/vmail VMAIL_ALIASES=/etc/vmail/$domain/aliases VMAIL_PASSWD=/etc/vmail/$domain/passwd VMAIL_MAILBOX_DIR=/var/local/vmail/$domain
That dsearch;/etc/vmail
will expand to a list of the files/directories under /etc/vmail. Which will be the domains to be handled.
I then made a small modification to main/01_exim4-config_listmacrosdefs
to add the virtual mail domains to the list of local domains:
# Local modification - add vmail domains to local domains, and provide # main_local_domains for the non-vmail domains. domainlist local_domains = MAIN_LOCAL_DOMAINS : VMAIL_DOMAINS domainlist main_local_domains = MAIN_LOCAL_DOMAINS
(I use main_local_domains
elsewhere in my processing of non-virtual mail domains.)
Next I need a router to expand virtual domain aliases. I put this into router/170_vmail_aliases
.
vmail_aliases: driver = redirect domains = VMAIL_DOMAINS allow_fail allow_defer data = ${lookup{$local_part}lsearch{VMAIL_ALIASES}} qualify_domain = $domain
qualify_domain = $domain
ensures the expanded alias, if any, has the same domain as the original, if the domain is not specified in the alias.
Once that's done, I can think about routing virtual mail users to a transport for delivery, and rejecting messages to unknown users in a virtual mail domain. I put this into router/180_vmail_user
.
vmail_user: driver = accept domains = VMAIL_DOMAINS local_parts = lsearch;VMAIL_PASSWD transport = VMAIL_DELIVERY vmail_no_such_user: driver = redirect domains = VMAIL_DOMAINS allow_fail = true data = :fail: Unknown user more = false
Here I'm accepting the mail on condition that the local part of the address appears in the domain's password file. If it does, the message proceeds to the virtual mail delivery transport. Otherwise, the user does not exist in the virtual mail domain and I can fail delivery and give up.
Now to the transports. I am now delivering all mail using Dovecot deliver
. I define a transport for this in transport/30_dovecot_vmail
and select it using the VMAIL_DELIVERY definition.
dovecot_vmail: driver = pipe command = /usr/lib/dovecot/deliver -d $local_part@$domain -f $sender_address -a $original_local_part@$original_domain message_prefix = message_suffix = log_output delivery_date_add envelope_to_add return_path_add user = vmail temp_errors = 64 : 69 : 70: 71 : 72 : 73 : 74 : 75 : 78
Prior to using Dovecot deliver
, I had Exim deliver virtual mail itself, with this transport in transport/30_vmail_home
.
vmail_home: driver = appendfile envelope_to_add directory = VMAIL_MAILBOX_DIR/$local_part/Maildir maildir_format create_directory = true user = vmail group = vmail return_path_add
This transport adds the message to the user's Maildir
. It runs as user and group vmail
and will create any directories that don't exist.
By the way, when you add a user, it's an idea to either send them a welcome mail to check things are working properly and create their Maildir
into the bargain. Otherwise, you should create the Maildir
by hand, so that there is something there when they try to read their mail.
When that's done, test your handiwork:
# exim4 -bt tommy.atkins@example.mod tommy.atkins@example.mod router = vmail_user, transport = dovecot_vmail
Now we need to modify the Dovecot setup to allow our user to read mail.
I'm assuming your dovecot.conf
already has
mail_location = maildir:~/Maildir
in it, telling Dovecot to find your regular users mail in ~/Maildir
.
We need to add the virtual domains to the
auth default { }
section of the configuration. The first stage is to add the virtual users password files.
passdb passwd-file { args = username_format=%n /etc/vmail/%d/passwd }
Here's a tip. My configuration also has a configuration for PAM
passdb pam { }
Put the virtual users passwd-file
entry before the pam
section. If you don't, your virtual usernames will be tried in pam
first. Confusion will abound if they succeed. And if they don't, it will look to programs like denyhosts
or fail2ban
as if a PAM login failed, and you may find access to the host unexpectedly blocked.
Now you need to add a userdb
section telling Dovecot how to find the mailbox. You will have a
userdb passwd { }
section serving your existing users. After that, add a catch-all for the virtual mailbox users.
userdb static { args = uid=vmail gid=vmail home=/var/local/vmail/%d/%n }
This tells Dovecot to use vmail
permissions to access the mailbox, and that the user home is at /var/local/main/<domain>/<user>
. Dovecot will apply it's existing rule that the mail is to be found in directory Maildir
under the user's home, and you are off to the races.
In practice, you'll most probably run into authentication problems. For help sorting them out, add
auth_debug = yes auth_debug_passwords = yes
to your dovecot.conf
while you try and work out what's going wrong.
Again, I'm assuming that 10-mail.conf
has
mail_location = maildir:~/Maildir
in it, telling Dovecot to find your regular users mail in ~/Maildir
.
I first added a new auth configuration file, auth-vmail.conf.ext
.
# Virtual mailbox passwords. passdb { driver = passwd-file args = username_format=%n /etc/vmail/%d/passwd } # VMail static settings. userdb { driver = static args = uid=vmail gid=vmail home=/var/local/vmail/%d/%n }
This gives Dovecot the essential password and user info settings.
I then modified 10-auth.conf
, adding the new vmail
auth at the end of the file.
!include auth-vmail.conf.ext
To debug authentication problems, enable auth_debug
and auth_debug_passwords
in 10-logging.conf
.
Your virtual mail users will probably want to send some mail, too. So you may want to give them access to your Exim server to relay mail. But, of course, you don't want world+dog also relaying their spam through your host.
There's several ways of cracking this nut. I'll just mention that if you do it by allowing authenticated SMTP, I found it easiest to do by handing the authentication over to Dovecot.
I needed to create the Dovecot authenticator socket by adding
socket listen { client { path = /var/run/dovecot/auth-client mode = 0666 } }
to the
auth default { }
section in dovecot.conf
. It's commented out by default in Debian. Without other arrangements, Exim needs its mode to be 0666; comments in the Dovecot config suggest this is generally safe.
Then, in the Exim configuration, add auth/30_dovecot_auth
containing:
dovecot_plain: driver = dovecot public_name = PLAIN server_socket = /var/run/dovecot/auth-client #server_set_id = $auth2 server_mail_auth_condition = false dovecot_login: driver = dovecot public_name = LOGIN server_socket = /var/run/dovecot/auth-client #server_set_id = $auth2 server_mail_auth_condition = false
In 10-master.conf
I add a Dovecot authenticator socket with permissions for Exim by adding the following lines in the section service auth
.
unix_listener auth-client { mode = 0660 group = Debian-exim }
Then add auth/30_dovecot_auth
to the Exim configuration as above.