11451
Comment: Clarify it's my custom templates in site/en, not necessarily all templtes.
|
9563
Added link to mailman-suite settings.py
|
Deletions are marked like this. | Additions are marked like this. |
Line 11: | Line 11: |
{{{#!wiki note Postorius and HyperKitty have now changed from Mozilla Persona supplemented with Python Social Auth to Django Allauth for authentication, and the templating in Mailman Core has changed. The changes associated with this are outlined towards the end of this document. }}} |
|
Line 15: | Line 12: |
For both installs I started with mailman-bundler. === lists.mailman3.org === On lm3o, I created /opt/mailman and cloned mailman-bundler into /opt/mailman/mailman-bundler. I more or less followed its docs for a production install, but I decided not to use virtualenvs, so I set buildout.cfg for 'production' and ran buildout not in a virtualenv - also I probably had to ensure I had up to date setuptools and pip. |
=== Update === I have done a significant reinstallation on both servers. <<Action(recall,The prior version of this page,rev=10)>> 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. |
Line 19: | Line 15: |
I installed ruby-sass and postgreSQL. I installed psycopg2 with both pip and pip3. I also installed gunicorn as the WSGI server for nginx and [[attachment:lm3o_nginx.txt|configured]] ngnix. I configured gunicorn as an [[attachment:lm3o_gunicorn.txt|upstart job]] to run as user:group mailman:mailman and set its [[attachment:lm3o_gunicorn.conf.txt|config]] as recommended. | === Preliminaries === Both lm3o and mpo already had sass and memcached installed via |
Line 21: | Line 18: |
I created the mailmanweb postgreSQL DB and a postgreSQL mailman user. | `apt install ruby-sass`<<BR>> `apt install memcached` |
Line 23: | Line 21: |
The main departure from a bundler production install is that I wanted to install the various Mailman components (and dependencies) system wide from the heads of the respective gitlab branches. | I installed these on the third server. |
Line 25: | Line 23: |
To this end, I cloned the hyperkitty, mailmanclient, postorius, mailman and mailman-hyperkitty branches into /opt/git. and ran their respective 'setup.py install' scripts with the appropriate system Python (3.4 for mailman and mailman-hyperkitty and 2.7 for the rest). The next step is the hardest. For those packages in mailman-bundler/eggs that had corresponding system package (probably in /usr/lib/python2.7/dist-packages) that could be imported in the system Python, I just deleted the mailman-bundler/eggs/ package and similarly for those Python 3 packages in mailman-bundler/venv-3.4/lib/python3.4/site-packeges that had a corresponding system package. | 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. |
Line 27: | Line 25: |
I also went through the mailman-bundler/bin/* scripts and removed now non-existent paths from the list added to sys.path. | 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. |
Line 29: | Line 27: |
There were some issues because I used only Django 1.9. django-haystack 2.4 is not compatible with Django 1.9, so I cloned the django-haystack 2.5.dev branch from github and installed that. | The third server is Ubuntu 16.04 with Python 3.5, so it was OK as is. |
Line 31: | Line 29: |
There are also a lot of deprecation warnings in logs, some of which I've tried to address. | === 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. |
Line 33: | Line 32: |
The remainder consisted of putting desired configuration in [[attachment:lm3o_settings_local.txt|mailman-bundler/mailman_web/settings_local.py]], and editing [[attachment:lm3o_mailman.cfg.txt|mailman-bundler/deployment/mailman.cfg]], [[attachment:lm3o_hyperkitty.cfg.txt|mailman-bundler/deployment/mailman-hyperkitty.cfg]] and [[attachment:lm3o_urls.txt|mailman-bundler/mailman_web/urls.py]]. | Note that all of this is done as the `mailman` user. |
Line 35: | Line 34: |
I also tried to create an upstart script for mailman, but despite trying all options, I couldn't get it to get the proper demonized PID so I went with an [[attachment:mailman_init.txt|init.d script]]. | 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. |
Line 37: | Line 36: |
The Mailman specific Postfix [[attachment:lm3o_postfix.txt|things]] are very straightforward. | 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 |
Line 39: | Line 38: |
For authentication, I couldn't get Google OpenID to work, but I was able to use OAuth2. I tried Twitter, but you can't get email address from Twitter so that's out. See [[attachment:lm3o_settings_local.txt|settings_local.py]] for details. Also, I added a bit to mailman-bundler/bin/mailman-post-update to do {{{ cd $STATIC_DIR/hyperkitty/img/login ln -s google.png google-oauth2.png cd $OLDPWD }}} for the login graphic. |
`pip install psycopg2-binary`<<BR>> `pip install pylibmc`<<BR>> `pip install Whoosh` |
Line 47: | Line 42: |
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/mailman-bundler/var/templates/site/en/: * [[attachment:footer-generic.txt]] * [[attachment:masthead.txt]] * [[attachment:newlist.txt]] * [[attachment:probe.txt]] * [[attachment:welcome.txt]] and for each supported domain I installed in /opt/mailman/mailman-bundler/templates/domains/EMAIL_DOMAIN/en/: * [[attachment:postack.txt]] with the literal `EMAIL_DOMAIN` replaced by the actual domain name. === mail.python.org === The installation on mail.python.org was similar in many ways but different in others. The major differences are because mpo is an established server running Apache and Postfix and supporting over 300 Mailman 2.1 lists in the python.org domain which is a Postfix virtual alias domain. This complicated the Postfix configuration because we wanted Mailman 3 lists to also be in the python.org email domain and Postfix virtual alias domains don't honor transport maps which is the normal way of delivering mail from Postfix to MM 3. |
on both servers. These are dependencies for using the PostgreSQL database, memcached and the Whoosh backend for !HyperKitty archive search. |
Line 59: | Line 44: |
Another difference is I decided to use virtualenvs for this install. | I also did the same, but in a Python 3.5 virtualenv on the third server. |
Line 61: | Line 46: |
Much of the install was the same. I have some notes of what was done, and I will only elaborate differences. | Then because lm3o uses nginx and Gunicorn to support wsgi apps, I did |
Line 63: | Line 48: |
Steps were: | `pip install gunicorn` |
Line 65: | Line 50: |
Create /opt/mailman owned by mailman. | there, and on mpo which uses Apache and mod_wsgi, I did |
Line 67: | Line 52: |
As the mailmanuser, git clone mailman-bundler. | `pip install mod_wsgi` |
Line 69: | Line 54: |
Basically follow bundler docs. | but as noted above, mpo is now using Apache and Gunicorn like the third server. |
Line 71: | Line 56: |
Run buildout as production. | The third server uses Apache and Gunicorn so I did |
Line 73: | Line 58: |
Install ruby-sass. | `pip install gunicorn` |
Line 75: | Line 60: |
Install apache mod_wsgi. The Apache wsgi config is [[attachment:mpo_wsgi.txt]]. | there. |
Line 77: | Line 62: |
Make [[attachment:lm3o_settings_local.txt|mailman_web/local_settings.py]] with [[attachment:mpo_settings_diff.txt|differences]] | === 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. |
Line 79: | Line 65: |
Edit [[attachment:lm3o_urls.txt|mailman_web/urls.py]] (change urlpatterns to list for django 1.9 and remove `{"SSL": True\}` | I maintained this on the third server as well. |
Line 81: | Line 67: |
Edit base_url and api_key in [[attachment:lm3o_hyperkitty.cfg.txt|/opt/mailman/mailman-bundler/deployment/mailman-hyperkitty.cfg]] (values are different). | === Recommended Configuration === |
Line 83: | Line 69: |
Install postgresql create mailmanweb DB and mailman user. | 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. |
Line 85: | Line 71: |
Install postgresql-server-dev-9.3 and then pip install psycopg2 in both venvs. Make /opt/mailman/git/ and clone django-haystack mailman mailman-hyperkitty hyperkitty mailmanclient postorius repos and run the setups in the appropriate venv. Remove older mailman and mailman-hyperkitty from venv-3.4/lib/... In eggs/ for everything with a version in venv/lib/..., remove the eggs/ subdir and replace it with a symlink to the venv/lib/... version. Link both Django 1.8 and 1.9 to the Django 1.9 in venv/lib/... Create django superuser. Update Oauth providers to recognize the additional callback domain. Add custom templates as above for lm3o. === Postfix issues === A major issue on mpo was trying to have MM 3 lists have @python.org email addresses so these wouldn't need to change upon list migration. In cases where the list domain is in Postfix mydestinations, this is straightforward, but when the list domain is a virtual alias domain, it's more difficult. What I did is a bit of a kludge. We plan to make this a feature so it too will be straightforward, but it isn't there yet. The solution is as follows: Use virtual_alias_maps to map `list(-*)@python.org` to `list(-*)@x.python.org`, and then use transport_maps to relay `list(-*)@x.python.org` to Mailman's LMTP runner in the usual way, and finally modify Mailman's LMTP runner to rewrite the `x.python.org` recipient domain to `python.org` so the address corresponds to what Mailman expects. The details involve several pieces. Add a [[attachment:mpo_mailman.cfg.add.txt|section]] to mailman-bundler/deployment/mailman.cfg to reference [[attachment:mpo_postfix.cfg.txt|mailman-bundler/deployment/postfix.cfg]] which in turn sets postmap_command to [[attachment:mpo_postmap.txt|mailman-bundler/bin/postmap_command]] which creates additional files. Reference these files in [[attachment:mpo_postfix_main.txt|Postfix]] and [[attachment:mpo_lmtp_patch.txt|patch]] mailman/runners/lmtp.py. == Recent changes == === Postfix === At the current time, there is are proposals to modify the [[https://gitlab.com/mailman/mailman/merge_requests/202|core]] and [[https://gitlab.com/mailman/mailmanclient/merge_requests/18|mailman client]] to add an alias_domain attribute to the domain object to deal with the above Postfix configuration issue. Ultimately Postorius will also need to be updated to set/display the alias_domain. === Django Haystack === django-haystack 2.5 has been released and should be installed by bundler so it shouldn't be necessary to do anything special for Django Haystack compatibility with Django 1.9. === Templating Changes === The core's templating has changed. The information above about custom templates is no longer valid. The custom templates I am using are now all in /opt/mailman/mailman-bundler/var/templates/site/en/ as follows: |
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: |
Line 121: | Line 102: |
=== Django Allauth Changes === The change to Django Allauth as well as other changes (see below) required changes to files in /opt/mailman/mailman-bundler/mailman_web/. The three changed files are: * [[attachment:urls.py]] * [[attachment:production.py]] * [[attachment:settings_local.py]] These are the lm3o versions of these files with some passwords/keys elided. The differences for mpo are the same as for the prior versions. It is not clear that there aren't things in settings_local.py that should really be in production.py, but this is the config that works for me with social auth for Google, Facebook, !GitHub and !GitLab. Note that the keys and secrets for social auth providers are now set in the database via the Django admin web UI. === Other Changes === Parts of Postorius and HyperKitty have been split out into a [[https://gitlab.com/mailman/django-mailman3|django-mailman3]] branch which needs to be cloned and installed. It is installed along with Postorius and HyperKitty in the same way as they are installed. This also requires 'django_mailman3' to be added to INSTALLED_APPS in the Django config. See above. |
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]]. <<BR>> 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]]. <<IncludeComments>> |
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.
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. The prior version of this page 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, pull and build 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.
Create directories:
- /opt/mailman/mm/bin/
- /opt/mailman/mm/var/
and files:
/opt/mailman/mm/init.py (empty)
/opt/mailman/mm/mailman.cfg (sample)
/opt/mailman/mm/mailman-hyperkitty.cfg (sample)
/opt/mailman/mm/settings_local.py (sample)
/opt/mailman/mm/settings.py (copy of the mailman-suite settings.py file but with DEBUG = False)
/opt/mailman/mm/urls.py (sample)
/opt/mailman/mm/wsgi.py (sample)
if using Gunicorn:
/opt/mailman/mm/gunicorn.conf (sample)
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 (sample) Script to run Django management commands.
/opt/mailman/mm/bin/mailman (sample) Script to run mailman commands.
/opt/mailman/mm/bin/mailman-post-update (sample) Script to update static web and run migrations following a software update.
if using Gunicorn:
/opt/mailman/mm/bin/gunicorn (sample) 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:
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 configuration.
And one that redirects http to https.
Apache and mod_wsgi
Here's an Apache configuration for mod_wsgi which I no longer use.
Apache and Gunicorn
Here's an Apache configuration 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 mailman.service.
Systemd qcluster.service.
Systemd gunicorn.service.
Init mailman init.d.
Upstart qcluster.conf.
Upstart gunicorn.conf.
Cron Mailman's crontab.
Comments
This was written assuming that the reader is familiar with Python software installation and tools like git and virtualenv.
Also, please note the first paragraph of the introduction. This is documentation of my decisions and experiences. It is not a how-to and does not replace the documentation at http://docs.list.org/
I've been asked to provide more information about some of the things that may be unfamiliar to some users.
In the Migration section, I refer to a /opt/mailman/git/ directory containing clones of the various GitLab projects and the 'pull' and 'build' scripts to pull and install updates. First, you need git which can be installed via your OS package manager if you don't have it. The cloned projects themselves are created in the /opt/mailman/git/ directory. This is done using one of two git commands for each project. If you have a gitlab account with your SSH key(s), you can
cd /opt/mailman/git/
git clone git@gitlab.com:mailman/project_name.git
for each project. Otherwise, you can
cd /opt/mailman/git/
git clone https://gitlab.com/mailman/project_name.git
I also mention in the Installation section, creating a Python 3.6 virtualenv. Python 3.6 is currently the minimum required. It could just as well be any later Python 3 version and should be the latest available on your server.
Creating the /opt/mailman/mm/venv virtualenv is done by
cd /opt/mailman/mm
virtualenv venv
or if you want to specify a Python other than the default
cd /opt/mailman/mm
virtualenv -p /path/to/desired/python venv
This is then activated by
source /opt/mailman/mm/venv/bin/activate
When active in a particular shell, it can be deactivated with the command
deactivate
or by exiting that shell.
If you don't have virtualenv, it can be installed with pip or via your OS package manager. For the latter, it might be a package named virtualenv or python3-virtualenv.