=== Introduction === I have now installed Mailman 3 for production on two different servers. This is intended to be documentation of my decisions and experiences in doing so. It will be more of a narrative than a how-to, but I hope a how-to can be distilled from it. See our [[https://docs.mailman3.org/en/latest/install/virtualenv.html|virtualenv installation document]] for our current installation recommendations. Other documents such as Brian Carpenter's [[DOC/Howto_Install_Mailman3_On_Debian10|Howto_Install_Mailman3_On_Debian10]] and Kelly Close's [[https://docs.google.com/document/d/1xIcSsoNFp2nHi7r4eQys00s9a0k2sHhu1V5PlantPTs/|Mailman 3 Setup Using Ubuntu Bionic]] are older and not maintained. The two servers are lists.mailman3.org (lm3o) and mail.python.org (mpo). Pre-existing things on those servers forced some decisions which were different between them, but the actual MM 3 installation was pretty much up to me, yet I did it differently the second time due to things I thought I'd learned the first time. A fundamental step in any installation is to ensure that you have the necessary infrastructure for reliably sending mail. This mostly involves DNS records. I won't go into detail, but you need an A and maybe AAAA record for your MAIL FROM domain and rDNS PTR records for the IPs pointing back to the domain. You may also need an MX record for your email domain pointing to the Mailman server. Also good is a mechanism for DKIM signing outgoing mail and DKIM and SPF records for the domain. This already existed on mpo, but needed to be set up on lm3o. lm3o is the same server as mirror.list.org/mirror.mailman3.org. This is a mirror of the GNU Mailman web site and was already set up using nginx as a web server. Thus, the MM 3 installation here uses nginx as the web server proxying to gunicorn for WSGI support. === Update === I have done a significant reinstallation on both servers. <> is no longer applicable to these servers. I have also installed MM 3 on a third server. I have now evolved my process and installations to a stable point. It is this configuration that I will describe. === Preliminaries === Both lm3o and mpo already had sass and memcached installed via `apt install ruby-sass`<
> `apt install memcached` I installed these on the third server. Also, lm3o and mpo are both Ubuntu 14.04 and the native Python 3 is Python 3.4, so I had previously installed Python 3.6 from source. It turned out that I also couldn't install libapache2-mod-wsgi-py3 on mpo via apt because that installed a Python 3.4 version. Ultimately on mpo I installed mod_wsgi via pip, but this required re-running `configure` and `make install` for Python 3.6 because I hadn't specified `--enable-shared` initially and that is required to build mod_wsgi. After some months, on mpo, Apache was upgraded by an automatic upgrade. This caused failures in mod_wsgi, probably because the upgraded Apache's mod_ssl used a different version of the SSL library than the one mod_wsgi was built with. See https://github.com/GrahamDumpleton/mod_wsgi/issues/370. However, before this was diagnosed, I switched mpo to use Gunicorn with Apache. The third server is Ubuntu 16.04 with Python 3.5, so it was OK as is. === Installation === For these installs, I opted to install the entire Mailman suite in a virtualenv. The biggest motivation for this choice was the fact that there are already production lists on both servers and using a virtualenv allowed me to do a lot of the work in advance without interfering with the production install. Possibly influenced by these experiences, I am now using virtualenv for all installs. Note that all of this is done as the `mailman` user. I already had some things set up in `/opt/mailman` including a `git` subdirectory containing clones of the !GitLab `mailman`, `mailmanclient`, `mailman-hyperkitty`, `hyperkitty`, `django-mailman3` and `postorius` projects. On the third server I have added `mailman-suite` because I use the settings.py from that project as the basis for mine. I then created a `/opt/mailman/mm` directory and within that a Python 3.6 virtualenv named `/opt/mailman/mm/venv`. I then activated the virtualenv and did `pip install psycopg2-binary`<
> `pip install pylibmc`<
> `pip install Whoosh` on both servers. These are dependencies for using the PostgreSQL database, memcached and the Whoosh backend for !HyperKitty archive search. I also did the same, but in a Python 3.5 virtualenv on the third server. Then because lm3o uses nginx and Gunicorn to support wsgi apps, I did `pip install gunicorn` there, and on mpo which uses Apache and mod_wsgi, I did `pip install mod_wsgi` but as noted above, mpo is now using Apache and Gunicorn like the third server. The third server uses Apache and Gunicorn so I did `pip install gunicorn` there. === Migration === The prior install on both servers used Mailman Bundler which is obsolete, however for consistency I kept some of the same names. Everything is in the /opt/mailman/ directory. I maintained the prior git/ subdirectory along with two bash scripts, [[attachment:pull_script.txt|pull|view]] and [[attachment:build_script.txt|build|view]] which are used to pull changes from !GitLab and build everything in the venv. I maintained this on the third server as well. === Recommended Configuration === Here are my recommendations for the rest of the configuration. The older installs don't adhere to this exactly, but this is what I'm doing going forward. Note: prior to 26 July 2020 there were paths in the files lm3o_nginx.txt, lm3o_nginx2.txt and mpo_wsgi.txt that were inconsistent with the layout below. These have been updated to be consistent. Create directories: * /opt/mailman/mm/bin/ * /opt/mailman/mm/var/ and files: * /opt/mailman/mm/__init__.py (empty) * /opt/mailman/mm/mailman.cfg ([[attachment:mailman.cfg|sample|view]]) * /opt/mailman/mm/mailman-hyperkitty.cfg ([[attachment:mailman-hyperkitty.cfg|sample|view]]) * /opt/mailman/mm/settings_local.py ([[attachment:settings_local.py|sample|view]]) * /opt/mailman/mm/settings.py (copy of [[https://gitlab.com/mailman/mailman-suite/blob/master/mailman-suite_project/settings.py|the mailman-suite settings.py file]] but with `DEBUG = False`) * /opt/mailman/mm/urls.py ([[attachment:urls.py|sample|view]]) * /opt/mailman/mm/wsgi.py ([[attachment:wsgi.py|sample|view]]) if using Gunicorn: * /opt/mailman/mm/gunicorn.conf ([[attachment:gunicorn.conf|sample|view]]) and a symlink: * /opt/mailman/mm/logs -> /opt/mailman/mm/var/logs In the /opt/mailman/mm/bin directory, create these executables: * /opt/mailman/mm/bin/django-admin ([[attachment:django-admin.txt|sample|view]]) Script to run Django management commands. * /opt/mailman/mm/bin/mailman ([[attachment:mailman.txt|sample|view]]) Script to run mailman commands. * /opt/mailman/mm/bin/mailman-post-update ([[attachment:mailman-post-update.txt|sample|view]]) Script to update static web and run migrations following a software update. if using Gunicorn: * /opt/mailman/mm/bin/gunicorn ([[attachment:gunicorn.txt|sample|view]]) Script to start Gunicorn. === Templates === There are several default templates that have incorrect or generic URLs for the web UI. To make these better, I installed these templates in /opt/mailman/mm/var/templates/site/en/ as follows: * [[attachment:domain:admin:notice:new-list.txt]] * [[attachment:list:admin:action:post.txt]] * [[attachment:list:member:digest:masthead.txt]] * [[attachment:list:member:generic:footer.txt]] * [[attachment:list:user:notice:post.txt]] * [[attachment:list:user:notice:probe.txt]] * [[attachment:list:user:notice:welcome.txt]] These are the lm3o templates. The mpo templates are the same except for URL. Of course, if you use these you need to edit the URLs for your site. === MTA === I use Postfix and configuration is straightforward. Mailman's default configuration is appropriate for Postfix listening on 127.0.0.1:25. The main.cf settings are well documented at https://mailman.readthedocs.io/en/latest/src/mailman/docs/mta.html#postfix. All that is really needed with recent postfix is `recipient_delimiter = +` and the additions to transport_maps, local_recipient_maps and relay_domains as described at https://mailman.readthedocs.io/en/latest/src/mailman/docs/mta.html#transport-maps or, if you are using alias domains, the additions to transport_maps, virtual_alias_maps and relay_domains as described at https://mailman.readthedocs.io/en/latest/src/mailman/docs/mta.html#unusual-postfix-configuration. === Web Server === As noted above the three servers I'm describing all have different web server configurations as follows: ===== nginx and Gunicorn ===== Here is the relevant nginx [[attachment:lm3o_nginx.txt|configuration|view]]. <
> And one that redirects [[attachment:lm3o_nginx2.txt|http to https|view]]. ===== Apache and mod_wsgi ===== Here's an Apache [[attachment:mpo_wsgi.txt|configuration|view]] for mod_wsgi which I no longer use. ===== Apache and Gunicorn ===== Here's an Apache [[attachment:apache_gunicorn.txt|configuration|view]] for Gunicorn. === Running Things === Finally, we need to arrange that all the services are running. Generally, the OS has taken care of init, upstart or systemd scripts for Postfix, the web server, PostgreSQL and memcached, but other things that need to be run are Mailman core, Django's qcluster and Gunicorn if that is used. Also, there are periodic crons that need to be run. Here are some samples. * Systemd [[attachment:systemd_mailman.txt|mailman.service|view]]. * Systemd [[attachment:systemd_qcluster.txt|qcluster.service|view]]. * Systemd [[attachment:systemd_gunicorn.txt|gunicorn.service|view]]. * Init [[attachment:init.d_mailman.txt|mailman init.d|view]]. * Upstart [[attachment:upstart_qcluster.txt|qcluster.conf|view]]. * Upstart [[attachment:upstart_gunicorn.txt|gunicorn.conf|view]]. * Cron [[attachment:mailman_crontab.txt|Mailman's crontab|view]]. <>