mailman with nginx on freebsd
2012-05-24
I like Nginx a lot.
Not because I’m some sort of hipster sysadmin either.
I like it because it is small, fast, and as a FreeBSD port, it compiles and updates quickly.
What I also like is the separation of services and processes. For example, if I want to run a PHP script, I don’t load “mod_php” like you would with Apache. Instead, you have a PHP processor, like php-fpm, running (on localhost, or, another server that only processes PHP scripts).
This is not about PHP though, this is about Mailman :)
Most of the “freebsd + mailman + nginx” search results did not turn up specific instructions on running Mailman with Nginx, on FreeBSD. So, here is what I did:
Software Installation
FreeBSD’s ports tree has all of the required packages:
- mail/mailman
- www/nginx
- www/fcgiwrap
To install those:
$ sudo portinstall mail/mailman www/nginx www/fcgiwrap
Or, if you want pacakges:
$ sudo pkg_add -r mailman nginx fcgiwrap
I recommend building and configuring ports, it doesn’t take long, and you will know what options you are compiling in.
All three, Mailman, Nginx and fcgiwrap need to run as services, so you’ll need to enable them either in rc.conf, or, with the rcNG structure in /etc/rc.conf.d/
I prefer the rcNG style of enabling and configuring services, so this is how I enable all three:
$ sudo echo mailman_enable=YES > /etc/rc.conf.d/mailman; \
echo nginx_enable=YES > /etc/rc.conf.d/nginx; \
echo fcgiwrap_enable=YES > /etc/rc.conf.d/fcgiwrap
Additionally, I explicitly declared fcgiwrap to run as the www user:
$ sudo echo 'fcgiwrap_user="www"' >> /etc/rc.conf.d/fcgiwrap
so this is what my /etc/rc.conf.d/fcgiwrap file looks like:
fcgiwrap_enable=YES
fcgiwrap_user="www"
Configuration
Mailman
On FreeBSD, the mailman port installs itself in /usr/local/mailman
The only thing I changed was the mm_cfg.py script to reflect the FQDN of the Mailman server.
fcgiwrap
The Fast CGI wrapper daemon did not require any additional work. Just note that the default rc script on FreeBSD creates a socket in /var/run/fcgiwrap/fcgiwrap.sock which is used by the nginx server.
Nginx
Nginx needs to point to the correct location to run the CGI scripts, as well as source the fcgiwrap configuration.
www/nginx installs fastcgi_params-dist in /usr/local/etc/nginx. Rename that:
$ sudo cp /usr/local/etc/nginx/fastcgi-params-dist /usr/local/etc/fastcgi-params
Now, edit /usr/local/etc/nginx/nginx.conf for mailman:
root /usr/local/mailman/cgi-bin;
location = / {
rewrite ^ /mailman/listinfo permanent;
}
location / {
rewrite ^ /mailman$uri;
}
location ~ ^/mailman(/[^/]*)(/.*)?$ {
fastcgi_split_path_info (^/mailman/[^/]*)(.*)$;
include fastcgi_params;
fastcgi_param GATEWAY_INTERFACE CGI/1.1;
fastcgi_param SCRIPT_FILENAME $document_root$1;
fastcgi_param PATH_INFO $fastcgi_path_info;
fastcgi_param PATH_TRANSLATED $document_root$2;
fastcgi_pass unix:/var/run/fcgiwrap/fcgiwrap.sock;
}
location /images/mailman {
alias /usr/local/mailman/icons;
}
location /icons {
alias /usr/local/mailman/icons;
}
location /pipermail {
alias /usr/local/mailman/archives/public;
autoindex on;
}
This is inside one of the “server { }” stanza’s, I have mine in a SSL Aware block:
server {
listen 443;
server_name lists.example.com;
ssl on;
ssl_certificate /var/puppet/ssl/certs/lists.example.com.pem;
ssl_certificate_key /var/puppet/ssl/private_keys/lists.example.com.pem;
ssl_session_timeout 5m;
ssl_protocols SSLv2 SSLv3 TLSv1;
ssl_ciphers HIGH:!aNULL:!MD5;
ssl_prefer_server_ciphers on;
root /usr/local/mailman/cgi-bin;
location = / {
rewrite ^ /mailman/listinfo permanent;
}
location / {
rewrite ^ /mailman$uri;
}
location ~ ^/mailman(/[^/]*)(/.*)?$ {
fastcgi_split_path_info (^/mailman/[^/]*)(.*)$;
include fastcgi_params;
fastcgi_param GATEWAY_INTERFACE CGI/1.1;
fastcgi_param SCRIPT_FILENAME $document_root$1;
fastcgi_param PATH_INFO $fastcgi_path_info;
fastcgi_param PATH_TRANSLATED $document_root$2;
fastcgi_pass unix:/var/run/fcgiwrap/fcgiwrap.sock;
}
location /images/mailman {
alias /usr/local/mailman/icons;
}
location /icons {
alias /usr/local/mailman/icons;
}
location /pipermail {
alias /usr/local/mailman/archives/public;
autoindex on;
}
}
I used Puppet as our internal Root CA, so deploying SSL based services is INCREDIBLY simple :)
Wrapping Up
You can now start the fcgiwrap daemon, nginx and mailman, and you are off and running:
$ sudo /usr/local/etc/rc.d/fcgiwrap start
$ sudo /usr/local/etc/rc.d/mailman start
$ sudo /usr/local/etc/rc.d/nginx start
Point your browser to you list server, and you should see either your existing lists, or the option to create a new ones: Our lists, blurred because I forgot my glasses
One last thing, and this is because it drove me crazy.
The Mailman interface will show you the lists for the hostname that the browser requests…
Does that makes sense? Okay, if you point your web browser to: https://lists.example.com/, Mailman will only show you the lists that have been created from lists.example.com.
If you use the IP address: https://10.10.10.10/, you will only see lists for 10.10.10.10, even if that resolves to lists.example.com.
I did not know this, and I was testing a replacement server for lists, and I called it lists-2, so I never saw the mailing lists through the web interface (even though bin/list_lists showed everything for lists.example.com).
Finally, I edited my /etc/hosts file on my workstation to point lists.example.com to the IP address of lists-2.example.com, and it all worked.