OpenSMTPD on the Local Network
One of the many great things about OpenBSD is that it comes with OpenSMTPD by default, allowing my servers to communicate with themselves and each other via the SMTP protocol. This is used to send insecurity reports, failed cron jobs, et cetera to various users on the system.
However, I don’t want to have to check each machine’s mail spool to see if there are any messages I need to act upon. I’d much rather have a central mail server to collect all these messages so that I have a single place to check.
This is easily done as smtpd.conf(5)
has an easy to understand manual page.
Mail Server Configuration
First, let’s provision a new virtual machine with OpenBSD 7.0 installed, setup NTP, and so on and so forth.
I’m going to need to generate a self-signed certificate in order to enable TLS, so let’s create a private key:
$ doas openssl genrsa -out /etc/ssl/private/mx0.jfc.dev.key 4096
Make sure that the permissions for the key are 600
, otherwise starting smtpd
will probably fail.
$ doas chmod 600 /etc/ssl/private/mx0.jfc.dev.key
Once I have that, I can generate the certificate. It will take a few variables, which I’ve exported:
export OPENSSL_COUNTRY=...
export OPENSSL_STATE=...
export OPENSSL_LOCALITY=...
export OPENSSL_ORGANIZATION=...
export OPENSSL_COMMON_NAME=...
$ doas openssl req -x509 -new -key /etc/ssl/private/mx0.jfc.dev.key \
-out /etc/ssl/mx0.jfc.dev.crt \
-days 18250 \
-subj "/C=$OPENSSL_COUNTRY/ST=$OPENSSL_STATE/L=$OPENSSL_LOCALITY/O=$OPENSSL_ORGANIZATION/OU=/CN=$OPENSSL_COMMON_NAME"
I’ve set it to an absurdly high amount of years, because I don’t want to bother with it again.
Once that’s done, I can configure the mail server’s /etc/mail/smtpd.conf
file:
table addresses { $SERVER_IP_1, $SERVER_IP_2, $SERVER_IP_3 }
table domains { devbox-ntp.home.lan, devbox-svc0.home.lan, devbox-wg0.home.lan }
table aliases file:/etc/mail/aliases
pki mx0.jfc.dev cert "/etc/ssl/mx0.jfc.dev.crt"
pki mx0.jfc.dev key "/etc/ssl/private/mx0.jfc.dev.key"
listen on lo0
listen on vio0 tls-require pki mx0.jfc.dev
action local_delivery maildir "/home/%{user.username}/Maildir" alias <aliases>
match from local for local action local_delivery
match from src <addresses> for domain <domains> action local_delivery
The first couple of lines sets up the tables I’ll need later on in the configuration. I’ve also let smtpd(8)
know where to find the key and certificate.
The server will listen on both the loopback device and the virtual network device, though it will require TLS. I don’t want to set the verify
option because I don’t want to require a valid certificate from a certificate authority or manage my own.
The last few lines deliver all of the incoming mail to each user using the Maildir format. I also use expansion mapping, so mail directed to the root
user is directed to me, i.e. joseph
. Check out the /etc/mail/aliases
file:
root: joseph
And run doas newaliases
. After that’s done, I need to restart smtpd
:
$ doas rcctl restart smtpd
Next, I need to set up the machine’s firewall by editing the /etc/pf.conf
file:
if = "vio0"
set skip on lo0
block return
pass in on $if inet proto icmp
pass in on $if inet proto tcp to port {ssh}
pass in on $if inet proto tcp to port {smtp}
pass out on $if
The only thing to note here is that I’m passing in the smtp
port. Restart the firewall:
$ doas pfctl -f /etc/pf.conf
Other Server Configuration
Next I need to set up each and every other virtual machine I have to send their mail to the mail server.
On each of those servers, I update the /etc/mail/smtpd.conf
file as follows:
listen on lo0
action relay_to_mx0 relay host smtp+tls://$MAIL_SERVER_IP tls no-verify
match from local action relay_to_mx0
Again I set the no-verify
option because I don’t want to generate a certificate for each server.
Now let’s edit the /etc/pf.conf
file:
if = "vio0"
set skip on lo
block return
pass in on $if inet proto icmp
pass in on $if inet proto {tcp} to port {ssh}
pass out on $if
I think that’s fairly straightforward as it’s identical to the one on the mail server, except the line for the smtp
port.
Finally, let’s run:
$ doas rcctl restart smtpd
$ doas pfctl -f /etc/pf.conf
Testing
We need to make sure this setup actually works. We can do that by using sendmail(8)
:
$ sendmail joseph
Subject: Test Subject
Hello, EHLO!
If we check the mail server’s Maildir:
Return-Path: <joseph@devbox-ntp.home.lan>
Delivered-To: joseph@devbox-ntp.home.lan
Received: from devbox-ntp.home.lan (devbox-ntp.home.lan [$NTP_SERVER_IP])
by devbox-mx0.home.lan (OpenSMTPD) with ESMTPS id 64f3eab9 (TLSv1.3:AEAD-AES256-GCM-SHA384:256:NO)
for <joseph@devbox-ntp.home.lan>;
Thu, 23 Dec 2021 14:23:47 -0700 (MST)
Received: from localhost (devbox-ntp.home.lan [local])
by devbox-ntp.home.lan (OpenSMTPD) with ESMTPA id f55200d4
for <joseph@devbox-ntp.home.lan>;
Thu, 23 Dec 2021 14:23:46 -0700 (MST)
From: <joseph@devbox-ntp.home.lan>
Date: Thu, 23 Dec 2021 14:23:32 -0700 (MST)
Subject: Test Subject
Message-ID: <6579236dae00ceb2@devbox-ntp.home.lan>
Hello, EHLO!
The mail actually came in!
Conclusion
Using this setup, I can manage all of my network’s communication from the central mail server. I can view insecurity reports and make sure that certain files have correct permissions or if there’s been any software installed that I don’t know about. I can make sure that the cronjobs are running correctly through any error mails that may come in.
Once the message is on my mail server, I can retrieve it through the IMAP protocol, though setting up an IMAP server will have to wait until a future essay.