Posts tagged 'opensmtpd'

Running Mailman on OpenBSD

I maintain a mailing list for the local web and digital community in Bristol and Bath. This mailing list is coming up to 18 years old and until now has been hosted at my previous company Netsight. It was running on their main mail server, which had evolved into quite a complex setup of Exim, Cyrus Imap, SpamAssassin, Mailman, Squirrelmail, and a number of related tools. All running on FreeBSD.

It came time to move the mailing list off onto it's own to simplify the complex setup and enable parts to be upgraded with less risk. So I thought I'd move it off onto it's own OpenBSD virtual machine, as it is pretty lightweight and running on it's own VM it would stay fairly self contained.

I wanted to try and use as much of the 'built in' components in OpenBSD as possible, namely the MTA (OpenSMTP) and the HTTP server (httpd). The mailing list runs Mailman version 2. There has since been a complete re-write of Mailman, version 3, which is a totally different beast, and based on Django app. As I wanted to keep this pretty minimal and try and move over as much of the setup as I could, I stuck with the legacy mailman 2 setup.

Oh, and just one more thing, as I'm currently doing a lot of experimentation with IPv6 at the moment I thought I'd try and set it up with just IPv6. The VM is running on a server in my office, and my ISP has given me just a single IPv4 address, but an entire /60 IPv6 address space to play with. So by putting it on IPv6 I don't have to worry about NAT to get it accessible from the outside world. As the rest of the world is still mainly IPv4 I set up an SMTP route on my main mail server, hosted with Bytemark to forward mail from IPv4 to the IPv6 mailman server. Similarly with HTTP traffic.

OpenBSD's https server tries to chroot itself to /var/www in order to limit the potential damage an exploit could do. Alas, mailman is quite tricky to get running in a chroot environment. As this whole VM will be exclusively running this mailman server and nothing else, I decided to forego the chroot side of things and get the httpd server to chroot to / which effectively negates the benefits of chroot, but allows us to more easily run mailman.

I installed mailman-2.1.17p0 from OpenBSD's packages collection. Then for /etc/mail/smtpd.conf

# $OpenBSD: smtpd.conf,v 1.7 2014/03/12 18:21:34 tedu Exp $

# This is the smtpd server system-wide configuration file.
# See smtpd.conf(5) for more information.

listen on 2a01:500:6:200:2::2
listen on ::1

table aliases db:/etc/mail/aliases.db

accept from any for domain "" alias <aliases> deliver to mbox

accept from local for any relay via smtp://

and in /etc/mail/aliases appended the aliases for mailman:

# underscore mailing list
underscore:              "|/usr/local/lib/mailman/mail/mailman post underscore"
underscore-admin:        "|/usr/local/lib/mailman/mail/mailman admin underscore"
underscore-bounces:      "|/usr/local/lib/mailman/mail/mailman bounces underscore"
underscore-confirm:      "|/usr/local/lib/mailman/mail/mailman confirm underscore"
underscore-join:         "|/usr/local/lib/mailman/mail/mailman join underscore"
underscore-leave:        "|/usr/local/lib/mailman/mail/mailman leave underscore"
underscore-owner:        "|/usr/local/lib/mailman/mail/mailman owner underscore"
underscore-request:      "|/usr/local/lib/mailman/mail/mailman request underscore"
underscore-subscribe:    "|/usr/local/lib/mailman/mail/mailman subscribe underscore"
underscore-unsubscribe:  "|/usr/local/lib/mailman/mail/mailman unsubscribe underscore"

Then set up /etc/httpd.conf to serve up the mailman web UI. This is based on classical CGI scripts. OpenBSD's httpd doesn't support the classical CGI setup, but only the newer 'fastcgi' which is a way of passing requests to a long running process, rather than spawn a process per request.

Luckily OpenBSD also includes slowcgi a gateway from FastCGI to the traditional CGI process. So firstly /etc/httpd.conf

chroot "/"
logdir "/var/www/logs"

server "default" {
       listen on 2a01:500:6:200:2::2 port 80

       root "/var/www/htdocs"

       # The actual mailman CGI scripts
       location "/mailman/*" {
               fastcgi socket "/var/www/run/slowcgi.sock"
               root { "/usr/local/lib/mailman/cgi-bin/", strip 1 }

       # The icons referred to by the web interface
       location "/icons/*" {
               root { "/usr/local/lib/mailman/icons/", strip 1 }

       # The mailing list archives
       location "/pipermail/*" {
               root { "/var/spool/mailman/archives/public/", strip 1 }

Note that I set the chroot parameter to /. This in effect disables the chroot security mechanism. You need to be OK with that. In theory you shouldn't need to do this, as only the slowcgi process needs to be able to see the actual mailman CGI scripts, but due to the way the path to the scripts is calculated, you have to disable the chroot in httpd too. The first location block above is the one that points to the main CGI scripts for mailman. It passes the location via the unix domain socket specified.

The slowcgi process doesn't need any setup, just starting. So my /etc/rc.conf.local file looks like:

slowcgi_flags="-p /"

Passing the -p / flag to slowcgi disables the chroot as well, so that it is able to find the mailman scripts to run.

So there we have a pretty minimal setup, just enough to accept mail via SMTP, process it in mailman and send mail out to smarthost relay, also access to the archives and web management interface via HTTP.

In total there are about 40 processes running:

load averages:  0.15,  0.17,  0.14 21:34:22
43 processes: 42 idle, 1 on processor
CPU states:  0.0% user,  0.0% nice,  0.2% system,  0.0% interrupt, 99.8% idle
Memory: Real: 173M/445M act/tot Free: 540M Cache: 187M Swap: 0K/480M

14917 _mailman   2    0   23M   32M sleep     select    0:43  0.00% python2.7
25162 _mailman   2    0   21M   30M sleep     select    0:42  0.00% python2.7
25278 _mailman   2    0   17M   25M sleep     select    0:40  0.00% python2.7
14513 _mailman   2    0   20M   30M sleep     select    0:40  0.00% python2.7
 5857 _mailman   2    0   16M   24M sleep     select    0:39  0.00% python2.7
26636 _mailman   2    0 8704K   15M sleep     select    0:38  0.00% python2.7
 7008 _mailman   2    0 8440K   15M sleep     select    0:38  0.00% python2.7
13568 _pflogd    4    0  684K  404K sleep     bpf       0:20  0.00% pflogd
19428 _smtpq     2    0 1900K 2876K idle      kqread    0:02  0.00% smtpd
 3726 _smtpd     2    0 2868K 5004K idle      kqread    0:01  0.00% smtpd
11513 root       2    0  792K 1136K sleep     poll      0:01  0.00% cron
    1 root      10    0  536K  552K sleep     wait      0:01  0.00% init
12359 matt       2    0 3680K 3028K idle      select    0:01  0.00% sshd
32041 _smtpd     2    0 1608K 2520K idle      kqread    0:00  0.00% smtpd
  428 _smtpd     2    0 1756K 2644K idle      kqread    0:00  0.00% smtpd
 2484 www        2    0 1212K 2316K sleep     kqread    0:00  0.00% httpd
 8653 _mailman   2    0   16M   24M idle      select    0:00  0.00% python2.7
19052 root       3    0  652K  760K idle      ttyin     0:00  0.00% ksh
 2330 www        2    0 1156K 2180K sleep     kqread    0:00  0.00% httpd
 1102 _smtpd     2    0 1668K 2476K idle      kqread    0:00  0.00% smtpd
19445 _syslogd   2    0 1124K 1504K idle      kqread    0:00  0.00% syslogd
16320 matt       2    0 3692K 3056K sleep     select    0:00  0.00% sshd
28230 _ntp       2  -20 1084K 2896K idle      poll      0:00  0.00% ntpd
26805 root       3    0  664K  772K idle      ttyin     0:00  0.00% ksh
 1199 www        2    0 1140K 2180K idle      kqread    0:00  0.00% httpd
23519 www        2    0  996K 1884K idle      kqread    0:00  0.00% httpd
19390 www        2    0  696K 1288K idle      kqread    0:00  0.00% slowcgi
28522 root      18    0  656K  752K sleep     pause     0:00  0.00% ksh
 2809 root       2    0 3800K 3556K idle      poll      0:00  0.00% sshd
30896 root       2    0 3792K 3564K idle      poll      0:00  0.00% sshd
 7317 root       2    0 1544K 2300K idle      kqread    0:00  0.00% smtpd
14527 _smtpd     2    0 1396K 2104K idle      kqread    0:00  0.00% smtpd
12559 _mailman  10    0 8484K 5232K idle      wait      0:00  0.00% python2.7
 9705 root       2    0 1036K 1436K idle      select    0:00  0.00% sshd
 3165 matt      18    0  632K  732K idle      pause     0:00  0.00% ksh
 6618 matt      18    0  628K  728K idle      pause     0:00  0.00% ksh
18860 root       2    0 1124K 1336K idle      netio     0:00  0.00% syslogd
 5870 root       2    0 1136K 2164K idle      kqread    0:00  0.00% httpd
17986 root       2  -20  668K 1528K idle      poll      0:00  0.00% ntpd
23120 root       2    0  620K  600K idle      netio     0:00  0.00% pflogd
17361 root      -6    0  236K  200K sleep     piperd    0:00  0.00% cat
17714 root      28    0  592K 1760K onproc    -         0:00  0.00% top
11321 _ntp       2    0  944K 1260K idle      poll      0:00  0.00% ntpd

The VM has 1G of memory, but looks like it could probabaly get away with 512MB just fine.