Skip to content
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
5 changes: 5 additions & 0 deletions nixos/doc/manual/release-notes/rl-2605.section.md
Original file line number Diff line number Diff line change
Expand Up @@ -162,8 +162,13 @@ of pulling the upstream container image from Docker Hub. If you want the old beh

- `services.stalwart-mail` has been renamed to `services.stalwart` to align with upstream re-brand as an e-mail and collaboration server. Other notable breaking changes to module:

- Addition of module-specific `stateVersion` option, which on existing installations of Stalwart must be set to the same as `system.stateVersion`.

This enables manually and carefully migrating Stalwart to a new `stateVersion` or newly enabling the Stalwart module with a newer `stateVersion` than `system.stateVersion`.

- `systemd.services.stalwart` owned by `stalwart:stalwart`. The `user` and `group` are configurable via `services.stalwart.user` and `services.stalwart.group`, respectively. By default, if `stateVersion` is older than `26.05`, will fallback to legacy value of `stalwart-mail` for both `user` and `group`.
- Default value for `services.stalwart.dataDir` has changed to `/var/lib/stalwart`. If `stateVersion` is older than `26.05`, will fallback to legacy value of `/var/lib/stalwart-mail`.
- Default tracer name and type have changed to `journal`. If `stateVersion` is older than `26.05`, will fallback to legacy value of `stdout`.

- `services.eintopf` has been renamed to `services.lauti` to align with upstream re-brand as a community online calendar.

Expand Down
61 changes: 43 additions & 18 deletions nixos/modules/services/mail/stalwart.nix
Original file line number Diff line number Diff line change
Expand Up @@ -8,9 +8,10 @@ let
cfg = config.services.stalwart;
configFormat = pkgs.formats.toml { };
configFile = configFormat.generate "stalwart.toml" cfg.settings;
useLegacyStorage = lib.versionOlder config.system.stateVersion "24.11";
useLegacyDefault = lib.versionOlder config.system.stateVersion "26.05";
default = if useLegacyDefault then "stalwart-mail" else "stalwart";
useLegacyStorage = lib.versionOlder cfg.stateVersion "24.11";
pre2605 = lib.versionOlder cfg.stateVersion "26.05";
stalwartIdentifier = if pre2605 then "stalwart-mail" else "stalwart";
stalwartIdentifierText = ''if lib.versionOlder config.services.stalwart.stateVersion "26.05" then "stalwart-mail" else "stalwart"'';

parsePorts =
listeners:
Expand All @@ -31,6 +32,15 @@ in
options.services.stalwart = {
enable = lib.mkEnableOption "the all-in-one collaboration and mail server, Stalwart";

stateVersion = lib.mkOption {
type = lib.types.str;
description = ''
The version of this module (=version of NixOS) when this module was first enabled on this particular machine, used to maintain compatibility with application data created on older versions of this module.

See {option}`system.stateVersion` for details on the NixOS-global equivalent to this option.
'';
Comment thread
axelkar marked this conversation as resolved.
};

package = lib.mkPackageOption pkgs "stalwart" { };

openFirewall = lib.mkOption {
Expand All @@ -55,23 +65,26 @@ in

dataDir = lib.mkOption {
type = lib.types.path;
default = if useLegacyDefault then "/var/lib/stalwart-mail" else "/var/lib/stalwart";
default = "/var/lib/${stalwartIdentifier}";
defaultText = lib.literalExpression "/var/lib/\${${stalwartIdentifierText}}";
description = ''
Data directory for stalwart
'';
};

user = lib.mkOption {
type = lib.types.str;
inherit default;
default = stalwartIdentifier;
defaultText = lib.literalExpression stalwartIdentifierText;
description = ''
User ownership of service
'';
};

group = lib.mkOption {
type = lib.types.str;
inherit default;
default = stalwartIdentifier;
defaultText = lib.literalExpression stalwartIdentifierText;
description = ''
Group ownership of service
'';
Expand Down Expand Up @@ -114,12 +127,24 @@ in

# Default config: all local
services.stalwart.settings = {
tracer.stdout = {
type = lib.mkDefault "stdout";
level = lib.mkDefault "info";
ansi = lib.mkDefault false; # no colour markers to journald
enable = lib.mkDefault true;
};
tracer =
if pre2605 then
{
stdout = {
type = lib.mkDefault "stdout";
level = lib.mkDefault "info";
ansi = lib.mkDefault false; # no colour markers to journald
enable = lib.mkDefault true;
};
}
else
{
journal = {
type = lib.mkDefault "journal";
level = lib.mkDefault "info";
enable = lib.mkDefault true;
};
};
store =
if useLegacyStorage then
{
Expand Down Expand Up @@ -155,7 +180,7 @@ in
);
in
{
path = "/var/cache/${default}";
path = "/var/cache/${stalwartIdentifier}";
resource = lib.mkIf hasHttpListener (lib.mkDefault "file://${cfg.package.webadmin}/webadmin.zip");
};
};
Expand All @@ -165,10 +190,10 @@ in
# service is restarted on a potentially large number of files.
# That would cause unnecessary and unwanted delays.
users = {
groups = lib.mkIf (cfg.group == default) {
groups = lib.mkIf (cfg.group == stalwartIdentifier) {
${cfg.group} = { };
};
users = lib.mkIf (cfg.user == default) {
users = lib.mkIf (cfg.user == stalwartIdentifier) {
${cfg.user} = {
isSystemUser = true;
inherit (cfg) group;
Expand Down Expand Up @@ -197,7 +222,7 @@ in
KillSignal = "SIGINT";
Restart = "on-failure";
RestartSec = 5;
SyslogIdentifier = default;
SyslogIdentifier = stalwartIdentifier;

ExecStartPre =
if useLegacyStorage then
Expand All @@ -217,8 +242,8 @@ in
ReadWritePaths = [
cfg.dataDir
];
CacheDirectory = default;
StateDirectory = default;
CacheDirectory = stalwartIdentifier;
StateDirectory = stalwartIdentifier;

# Upstream uses "stalwart" as the username since 0.12.0
User = cfg.user;
Expand Down
5 changes: 4 additions & 1 deletion nixos/tests/stalwart/stalwart-config.nix
Original file line number Diff line number Diff line change
@@ -1,4 +1,4 @@
{ pkgs, lib, ... }:
{ lib, ... }:

let
certs = import ../common/acme/server/snakeoil-certs.nix;
Expand All @@ -9,6 +9,9 @@ in

services.stalwart = {
enable = true;

stateVersion = lib.trivial.release; # Only for the test; please don't do in production
Comment thread
axelkar marked this conversation as resolved.

settings = {
server.hostname = domain;

Expand Down
Loading