Stalwart

From NixOS Wiki
Revision as of 10:01, 13 September 2024 by Onny (talk | contribs) (→‎Setup)

Stalwart is an open-source, all-in-one mail server solution that supports JMAP, IMAP4, and SMTP protocols. It's designed to be secure, fast, robust, and scalable, with features like built-in DMARC, DKIM, SPF, and ARC support for message authentication. It also provides strong transport security through DANE, MTA-STS, and SMTP TLS reporting. Stalwart is written in Rust, ensuring high performance and memory safety.

Setup

The following example enables the Stalwart mail server for the domain example.org, listening on mail delivery SMTP/Submission ports (25, 465) and IMAPS port (993) for mail clients to connect to. Mailboxes for the accounts postmaster@example.org and user1@example.org get created if they don't exist yet.

/etc/nixos/configuration.nix
services.stalwart-mail = {
  enable = true;
  package = pkgs.stalwart-mail;
  openFirewall = true;
  settings = {
    server = {
      hostname = "example.org";
      tls = {
        enable = true;
        implicit = true;
      };
      listener = {
        smtp = {
          protocol = "smtp";
          bind = "[::]:25";
        };
        submissions = {
          bind = "[::]:465";
          protocol = "smtp";
        };
        imaps = {
          protocol = "imap";
          bind = "[::]:993";
        };
        management = {
          bind = [ "127.0.0.1:8080" ];
          protocol = "http";
        };
      };
    };
    lookup.default = {
      hostname = "mx1.example.org";
      domain = "example.org";
    };
    acme."letsencrypt" = {
      directory = "https://acme-v02.api.letsencrypt.org/directory";
      challenge = "dns-01";
      contact = "user1@example.org";
      domains = [ "example.org" ];
      provider = "cloudflare";
      secret = "****";
    };
    session.auth = {
      mechanisms = "[plain]";
      directory = "'in-memory'";
    };
    storage.directory = "in-memory";
    session.rcpt.directory = "'in-memory'";
    queue.outbound.next-hop = "'local'";
    directory."imap".lookup.domains = [ "example.org" ];
    directory."in-memory" = {
      type = "memory";
      principals = [
        {
          class = "admin";
          name = "User 1";
          secret = "foobar";
          email = [ "user1@example.org" ];
        }
        {
          class = "individual";
          name = "postmaster";
          secret = "foobar";
          email = [ "postmaster@example.org" ];
        }
      ];
    };
  };
};

services.caddy = {
  enable = true;
  virtualHosts = {
    "webadmin.tuxtux.com.co" = {
      extraConfig = ''
        reverse_proxy http://127.0.01:8080
      '';
      serverAliases = [
        "mta-sts.tuxtux.com.co"
        "autoconfig.tuxtux.com.co"
        "autodiscover.tuxtux.com.co"
      ];
    };
  };
};

TLS key generation is done using DNS-01 challenge through Cloudflare domain provider, see dns-update library for further providers or configure manual certificates.

Configuration

DNSSEC

Ensure that DNSSEC is enabled for your primary and mail server domain. It can be enabled by your domain provider.

For example, check if DNSSEC is working correctly for your new TLSA record

# nix shell nixpkgs#dnsutils --command delv _25._tcp.mx1.example.org TLSA @1.1.1.1
; fully validated
_25._tcp.mx1.example.org. 10800 IN TLSA 3 1 1 7f59d873a70e224b184c95a4eb54caa9621e47d48b4a25d312d83d96 e3498238
_25._tcp.mx1.example.org. 10800 IN RRSIG	TLSA 13 5 10800 20230601000000 20230511000000 39688 example.org. He9VYZ35xTC3fNo8GJa6swPrZodSnjjIWPG6Th2YbsOEKTV1E8eGtJ2A +eyBd9jgG+B3cA/jw8EJHmpvy/buCw==

Administrative web frontend

Note: The module is not yet part of the latest NixOS stable release and will be available with version 24.11.

Add following listener to enable the administrative web frontend.

/etc/nixos/configuration.nix
services.stalwart-mail = {
  enable = true;
  settings.server.listener = {
    "management" = {
      bind = [ "[::]:8080" ];
      protocol = "http";
    };
  };
};

It will be accessible on http://localhost:8080 and authentication is done with the one of the credentials specified above (normal inbox user or administrative role).

Please note that this example snippet is for testing purpose and without further configuration the management web interface will run unencrypted on all interfaces which is unsecure.

Tips and tricks

Unsecure setup for testing environments

The following minimal configuration example is unsecure and for testing purpose only. It will run the Stalwart mail server on localhost, listening on port 143 (IMAP) and 587 (Submission). Users alice and bob are configured with the password foobar.

/etc/nixos/configuration.nix
services.stalwart-mail = {
  enable = true;
  # Use newer, latest version in NixOS 24.05
  package = pkgs.stalwart-mail;
  settings = {
    server = {
      hostname = "localhost";
      tls.enable = false;
      listener = {
        "smtp-submission" = {
          bind = [ "[::]:587" ];
          protocol = "smtp";
        };
        "imap" = {
          bind = [ "[::]:143" ];
          protocol = "imap";
        };
      };
    };
    imap.auth.allow-plain-text = true;
    session.auth = {
      mechanisms = "[plain, auth]";
      directory = "'in-memory'";
    };
    storage.directory = "in-memory";
    session.rcpt.directory = "'in-memory'";
    queue.outbound.next-hop = "'local'";
    directory."in-memory" = {
      type = "memory";
      principals = [
        {
          class = "individual";
          name = "alice";
          secret = "foobar";
          email = [ "alice@localhost" ];
        }
        {
          class = "individual";
          name = "bob";
          secret = "foobar";
          email = [ "bob@$localhost" ];
        }
      ];
    };
  };
};

See also