Configuring a personal mail server with OpenSMTPD and MailRoute

It’s been less than a year since the first production release of OpenSMTPD, but I’d heard good things and wanted to give it a try. Like most OpenBSD projects the manpages are excellent, but like all young projects examples are thin on the ground.

I decided to try setting it up for my new home server: a tiny domU holding mail for just 4 accounts. All of my mail is relayed via MailRoute, and while it’s a normal smarthost setup I didn’t find any clear examples, so here’s mine in the hope that it might be of some benefit.

Goals:

  1. Only accept inbound mail if it is relayed through MailRoute.
  2. Relay all outbound mail through MailRoute, including mail generated locally on the machine (passively from scripts or actively with mutt).
  3. Allow clients to submit mail from any IP but only if they authenticate.
  4. Require encryption on all connections, inbound and outbound.
  5. Listen on a non-standard port. MailRoute lets you specify one, and as we’re only accepting mail from them this helps reduce load on an underpowered vm.

The following smtpd.conf achieves this:

# Certificate conf
pki example.com certificate "/path/to/certs/example.crt"
pki example.com key "/path/to/private/example.key"

listen on eth0 port 45678 tls-require pki example.com auth-optional
listen on lo

# Aliases: remember to run "smtpctl update table aliases"
table aliases file:/etc/smtpd/aliases

# Deliver inbound mail from MailRoute
accept from source 199.89.0.0/21 \
  for domain "example.com" alias <aliases> \
  deliver to maildir

# Deliver local mail
accept from local \
  for local alias <aliases> \
  deliver to maildir

# Relay outbound mail to MailRoute
# N.B. this works because authenticated users are treated as local
accept from local \
  for any \
  relay via tls://outbound.mailroute.net verify

I’ve been running this for a few days now, handling my normal mail load (~200 mails per day). The total private memory used according to pmap:

# pgrep smtpd | xargs pmap -d \
   | grep -o "private: \([0-9]\+\)" \
   | awk '{ SUM += $2 } END { print SUM / 1024 " MB"}'
12.8633 MB

(I’m aware this isn’t an accurate measure.)