Mailman

From NixOS Wiki
Revision as of 05:22, 20 February 2020 by imported>Benley (first draft (more to come))
(diff) ← Older revision | Latest revision (diff) | Newer revision → (diff)

Requires at least NixOS 20.03; the services.mailman module in NixOS 19.09 is insufficient.

This example includes:

  • Postfix as the MTA
  • uwsgi to host Mailman's web interface and archives (Postorius and Hyperkitty)
  • nginx to terminate TLS, proxy to uwsgi, and serve static assets
  • letsencrypt to acquire TLS certificates for nginx
{ config, pkgs, ... }:

let
  OWNER_EMAIL = "postmaster@example.org";  # Change this!
  MAILMAN_HOST = "mailman.example.org";    # Change this!
in

{
  services.postfix = {
    enable = true;
    relayDomains = ["hash:/var/lib/mailman/data/postfix_domains"];
    config = {
      transport_maps = ["hash:/var/lib/mailman/data/postfix_lmtp"];
      local_recipient_maps = ["hash:/var/lib/mailman/data/postfix_lmtp"];
    };
  };

  services.mailman = {
    enable = true;
    siteOwner = OWNER_EMAIL;
    webUser = config.services.uwsgi.user;
    hyperkitty.enable = true;
    webHosts = [MAILMAN_HOST];
  };

  # Make sure that uwsgi gets restarted if any django settings change.
  # I'm not sure why this isn't covered by the "before" and
  # "requiredBy" settings present in mailman-web.service. Maybe
  # because it's a oneshot and not a daemon?
  systemd.services.uwsgi.restartTriggers = [
    config.environment.etc."mailman3/settings.py".source
  ];

  # Tweak permissions so nginx can read and serve the static assets
  # (/var/lib/mailman-web defaults to mode 0600)
  systemd.services.uwsgi.preStart = ''
    chmod o+x /var/lib/mailman-web
  '';

  services.uwsgi = {
    enable = true;
    plugins = ["python3"];
    instance = {
      type = "normal";
      pythonPackages = (
        # TODO: I hope there is a nicer way of doing this:
        self: with self.override {
          overrides = self: super: { django = self.django_1_11; };
        }; [ mailman-web ]
      );
      socket = "127.0.0.1:33140";
      wsgi-file = "${config.services.mailman.webRoot}/mailman_web/wsgi.py";
      chdir = "/var/lib/mailman-web";
      master = true;
      processes = 4;
      vacuum = true;
    };
  };

  security.acme.email = OWNER_EMAIL;
  security.acme.acceptTerms = true;

  services.nginx = {
    enable = true;
    recommendedProxySettings = true;
    virtualHosts.${MAILMAN_HOST} = {
      enableACME = true;
      forceSSL = true;
      locations."/static/".alias = "/var/lib/mailman-web/static/";
      locations."/".extraConfig = ''
        uwsgi_pass 127.0.0.1:33140;
        include ${config.services.nginx.package}/conf/uwsgi_params;
      '';
    };
  };

  networking.firewall.allowedTCPPorts = [ 80 443 ];
}