WIP!
Most of this site is incomplete, and the current state is available as an open draft. Most of the text here is likely incomplete, misinformed, or just plain wrong. I'm looking for feedback on my website, so that I can:
- Fill in what I'm missing
- Take out what's unnecessary
- Figure out my target audience
- Find the right way to structure the site
- Filter out any errors
To anyone who wants to send me feedback, thank you, and shoot me an email!
The OpenSMTPD virtuals table enables mutliple “virtual” email accounts across various domains to be bound to a single “real” BSD user. This has a couple advantages:
- Each mail account doesn’t require creating a new unprivileged BSD user.
- The same mail server can serve multiple domains without conflating accounts with the same “user” portion of the address.
One main disadvantage is that, because OpenSMTPD and Dovecot will not read user details from the same file, there will be some level of redundancy across both services.
Preparation
This is a continuation of the parent article for hosting a mail server on OpenBSD.
This tutorial is tailored towards mail servers who will deliver mail for multiple domains, however you can just as easily follow if you only want mail for one domain.
My mail server will be called mail.example.org for this tutorial, and it will serve the domains example.org as well as websteading.net.
Setup DNS and rDNS records
Just like single-domain mail servers, each domain will need MX/SPF/DKIM/DMARC DNS keys for the Internet to tell from your sites’ address’ domains where to send mail to, which servers to trust mail from, how to check how mail came from there, and who to send reports to if anything went awry.
Create the DKIM keys
If you’ve followed the main tutorial, you already have one DKIM key. You may use the same key for all domains, but because a DKIM record has to exist for each domain, I’ll make a unique key for each domain anyways.
Last tutorial already has example.org.20220118.key
, so I’ll make websteading.net.20230131.key
.
Create the key(s):
$ cd /etc/mail
$ #doas mkdir -m 700 dkim
$ #doas openssl genrsa -out dkim/example.org.20220118.key 2048
$ doas openssl genrsa -out dkim/websteading.net.20230131.key 2048
$ doas chmod 400 dkim/*.key
$ doas chown -R _rspamd dkim
Create the public key(s), and keep its contents to the side.
It will be the p
field of your DKIM DNS record:
$ doas openssl rsa -in /etc/mail/dkim/example.org.20220118.key -pubout | grep -v ^--- | tr -d '\n'
writing RSA key
MIIBIjANBgkqhkiG9w0BAQEFAAOCAQ8AMIIBCgKCAQEA0wwm......TNOPwG1//++gfl/hwIDAQAB
$ doas openssl rsa -in /etc/mail/dkim/websteading.net.20230131.key -pubout | grep -v ^--- | tr -d '\n'
writing RSA key
MIIBIjANBgkqhkiG9w0BAQEFAAOCAQ8AMIIBCgKCAQEAqiX7......dFmToxOlXaZ1qWhtJ7taQID
Setup DNS
For each domain, add these 4 DNS records:
example.org. MX "mail.example.org" 10
20220118._domainkey.example.org TXT "v=DKIM1; k=rsa; p=MIIBIj......hwIDAQAB "
example.org. TXT "v=spf1 mx -all"
_dmarc.example.org. TXT "v=DMARC1; p=reject; rua=mailto:reports@example.org; fo=1"
Setup rDNS
If you haven’t already, add a reverse DNS record to your server that matches your domains’ MX records. How to do this depends entirely on your ISP (or VPS provider).
Setup the vmail user
I mention virtual users will remove the need to create unix accounts, but
there’s one exception: _vmail
will be the one unix account that owns all
users’ mail. It will be an unprivileged user, so it will have no home folder,
no login shell, no password to login with, and no access to any files besides
the users’ mail.
Create the user:
$ doas useradd -s /sbin/nologin -c "Virtual Mail User" _vmail
While this user will have no home, there should still be a “home” for all the mail. Create the directory and give the vmail user ownership:
$ doas mkdir -m 700 /var/vmail
$ doas chown _vmail:_vmail /var/vmail
Reconfigure Rspamd
Rspamd will need to know which DKIM keys it will need to sign for which domain. You may configure Rspamd to use the same key for all domains if you’d like. I’m going to make them use one key for each domain because I can, also since I have to add a DKIM DNS record for each domain anyways.
My /etc/rspamd/local.d/dkim_signing.conf looks like this:
allow_username_mismatch = true;
path = "/etc/mail/dkim/$domain.$selector.key"
domain {
example.org {
selector = "20220118"
}
websteading.net {
selector = "20230131"
}
}
Restart Rspamd
Start and check Rspamd:
$ doas rcctl restart rspamd
rspamd(ok)
$ doas rcctl check rspamd
rspamd(ok)
Reconfigure Dovecot
Dovecot’s user and password database sources will need to be rerouted from
BSD’s standard passwd file and auth system to a fresh file dedicated to email
users. Change the userdb
and passdb
sections, and auth_username_format
, in /etc/dovecot/dovecot.conf:
auth_username_format = %Lu
userdb {
driver = passwd-file
args = /etc/mail/imap.passwd
override_fields = uid=_vmail gid=_vmail home=/var/vmail/%u
}
passdb {
drivr = passwd-file
args = /etc/mail/imap.passwd
}
Create the new passwd file
The file should be read-writable only by Dovecot:
$ doas touch /etc/mail/imap.passwd
$ doas chmod 600 /etc/mail/imap.passwd
$ doas chown _dovecot /etc/mail/imap.passwd
Restart Dovecot
Check and restart Dovecot:
$ doas doveconf -n
$ doas rcctl restart dovecot
Reconfigure OpenSMTPD
To support virtual users, OpenSMTPD needs a new file that maps them to real users, and another file that maps each virtual users with the password they need to authenticate.
Create both files and limit their access only to _smtpd
:
$ doas touch /etc/mail/{virtuals,credentials}
$ doas chown _smtpd /etc/mail/{virtuals,credentials}
$ doas chmod 700 /etc/mail/{virtuals,credentials}
Open /etc/mail/smtpd.conf
. Alongside the <virtuals>
table, add in the table for virtual users, credentials, and domains you wish to serve:
table aliases file:/etc/mail/aliases
table virtuals file:/etc/mail/virtuals
table credentials file:/etc/mail/credentials
table domains { websteading.net, example.org }
Move down to the Inbound Mail rules, and replace the action "inbound"
and match
directives with:
#action "inbound" maildir "~/Mail/Inbox" alias
#match from any for local action "inbound"
# The format specifier %{dest:lowercase|strip} would transform
# an address like "Someone+tag@EXAMPLE.COM" to "someone@example.com"
# (the tag is stripped and is sent into th user's mail folder).
action "inbound" maildir "/var/vmail/%{dest:lowercase|strip}/Mail/Inbox" virtual
match from any for domain action "inbound"
Scroll further down to the Outbound Mail rules, and replace the auth
option in the listen
directives with auth <credentials>
:
#listen on egress port msa tls-require pki mail.example.org auth filter "rspamd"
#listen on egress smtps pki mail.example.org auth filter "rspamd"
listen on egress port msa tls-require pki mail.example.org auth filter "rspamd"
listen on egress smtps pki mail.example.org auth filter "rspamd"
Finally, in between inbound mail and outbound mail, add a Local Mail section to ensure real users can still send local mail to each other.
Move the listen on socket
directive up to this section and add one more
action
and match
:
# ---Local Mail---
listen on socket filter "rspamd"
action "local_mail" mbox alias <aliases>
match from local for local action "local_mail"
Restart smtpd
Check the configuration is OK, and restart smtpd:
$ doas smtpd -n
$ doas rcctl restart smtpd
Create an Email Account
With all wiring set up, it’s time to add virtual users.
Generate the password
The password is stored in two places /etc/mail/credentials and /etc/mail/imap.passwd, and there are fittingly two methods to generate passwords. Both use the multicrypt format, and so both are interchangeable with each other.
Bcrypt is a safe and adjustable password scheme for accounts, and is the default scheme OpenBSD uses for unix accounts. To genrate a bcrypt password with Dovecot:
$ doveadm pw -s crypt
Enter new password:
Retype new password:
{CRYPT}$2y$05$LTOBmYA/hKr5n8D50AtF.eAoILnUBxljpTVC100j06OSuIP8x9oX2
OpenBSD provides encrypt and smtpctl encrypt which both works in the same way:
$ smtpctl encrypt
<type in the password here>
$2b$09$dlt4zAHrfJ9Pqw0phPUbhO08PaVfi6SyMXr17UM6Zpq1surTa1L8q
Add the user to the Virtuals and Crdentials tables
Adding a user to /etc/mail/virtuals is extraordinarily simple. Add this line:
someone@example.com _vmail
And to /etc/mail/credentials (without the Dovecot {CRYPT}
phrase):
someone@example.com $2y$05$LTOBmYA/hKr5n8D50AtF.eAoILnUBxljpTVC100j06OSuIP8x9oX2
Inform smtpd the tables are updated without restarting it:
$ doas smtpctl update table virtuals
$ doas smtpctl update table credentials
Add the user to imap.passwd
As far as Dovecot is concerned, the main structure of the passwd file should look like this:
user:{SCHEME}password::::::extra args
For example:
someone@example.org:{CRYPT}$2y$05$uqzC8dLUpKaft1xC4S7OKOzO1yAX9nlBweB.q7.qmZ27gBv7UCuhq::::::
Add the line like above, and tell Dovecot it should flush the authentication cache for the user:
$ doas doveadm auth cache flush someone@example.org
Optional: Add Well-known Aliases
There are a few well-known aliases for each domain often used for legitimate
business, networking-related or service-related reasons. You may funnel all these emails to a single user, let’s say pat@example.org
.
Prepend these aliases to the beginning of /etc/mail/virtuals
:
# RFC2142 Well-Known Mailbox Names
# Business
info pat@example.org
marketing pat@example.org
sales pat@example.org
support pat@example.org
# Networking
abuse pat@example.org
noc pat@example.org
security pat@example.org
# Service
postmaster pat@example.org
reports pat@example.org
webmaster pat@example.org
www pat@example.org
Inform smtpd to update the table:
$ doas smtpctl update table virtuals
Appendix: Troubleshooting
Both smtpd and Dovecot forwards its logs to /var/log/maillog.
Issue: dovecot: imap-login: Disconnected: Connection closed (auth failed)
Double-check in /etc/dovecot/dovecot.conf that auth_username_format = %Lu
,
or auth_username_format
is unset. Also double-check that there is no
username_format
option in either of the passdb
/userdb
args.
The format %Lu
matches the full canonical email address lowercased, such as
someone@example.org
, while %l
matches only the name part of the address,
someone
. %l
is a common configuration setting for single-domain mail
servers.