8 cfg = config.services.cyrus-imap;
9 cyrus-imapdPkg = pkgs.cyrus-imapd;
19 inherit (lib.strings) concatStringsSep;
40 if builtins.isInt q then
41 "${p}=${builtins.toString q}"
43 "${p}=\"${if builtins.isList q then (concatStringsSep " " q) else q}\""
47 mkCyrusOptionsString = v: concatStringsSep " " (mkCyrusOptionsList v);
49 concatStringsSep "\n " (mapAttrsToList (n: v: n + " " + (mkCyrusOptionsString v)) settings);
51 cyrusConfig = lib.concatStringsSep "\n" (
52 lib.mapAttrsToList (n: v: ''
62 mkKeyValue = mkKeyValueDefault {
65 if builtins.isBool v then
66 if v then "yes" else "no"
67 else if builtins.isList v then
68 concatStringsSep " " v
70 mkValueStringDefault { } v;
75 options.services.cyrus-imap = {
76 enable = mkEnableOption "Cyrus IMAP, an email, contacts and calendar server";
77 debug = mkEnableOption "debugging messages for the Cyrus master process";
79 listenQueue = mkOption {
83 Socket listen queue backlog size. See {manpage}`listen(2)` for more information about a backlog.
84 Default is 32, which may be increased if you have a very high connection rate.
89 default = "/run/cyrus/db";
91 Location where DB files are stored.
92 Databases in this directory are recreated upon startup, so ideally they should live in ephemeral storage for best performance.
95 cyrusSettings = mkOption {
97 freeformType = attrsOf (
115 This section lists the processes to run before any SERVICES are spawned.
116 This section is typically used to initialize databases.
117 Master itself will not startup until all tasks in START have completed, so put no blocking commands here.
120 SERVICES = mkOption {
134 listen = "/run/cyrus/lmtp";
139 listen = "/run/cyrus/notify";
145 This section is the heart of the cyrus.conf file. It lists the processes that should be spawned to handle client connections made on certain Internet/UNIX sockets.
151 cmd = [ "tls_prune" ];
191 This section lists processes that should be run at specific intervals, similar to cron jobs. This section is typically used to perform scheduled cleanup/maintenance.
197 This section lists long running daemons to start before any SERVICES are spawned. {manpage}`master(8)` will ensure that these processes are running, restarting any process which dies or forks. All listed processes will be shutdown when {manpage}`master(8)` is exiting.
202 description = "Cyrus configuration settings. See [cyrus.conf(5)](https://www.cyrusimap.org/imap/reference/manpages/configs/cyrus.conf.html)";
204 imapdSettings = mkOption {
206 freeformType = attrsOf (oneOf [
213 configdirectory = mkOption {
215 default = "/var/lib/cyrus";
217 The pathname of the IMAP configuration directory.
220 lmtpsocket = mkOption {
222 default = "/run/cyrus/lmtp";
224 Unix socket that lmtpd listens on, used by {manpage}`deliver(8)`. This should match the path specified in {manpage}`cyrus.conf(5)`.
227 idlesocket = mkOption {
229 default = "/run/cyrus/idle";
231 Unix socket that idled listens on.
234 notifysocket = mkOption {
236 default = "/run/cyrus/notify";
238 Unix domain socket that the mail notification daemon listens on.
244 admins = [ "cyrus" ];
245 allowplaintext = true;
246 defaultdomain = "localhost";
247 defaultpartition = "default";
248 duplicate_db_path = "/run/cyrus/db/deliver.db";
249 hashimapspool = true;
254 mboxname_lockpath = "/run/cyrus/lock";
255 partition-default = "/var/lib/cyrus/storage";
257 proc_path = "/run/cyrus/proc";
258 ptscache_db_path = "/run/cyrus/db/ptscache.db";
259 sasl_auto_transition = true;
260 sasl_pwcheck_method = [ "saslauthd" ];
261 sievedir = "/var/lib/cyrus/sieve";
262 statuscache_db_path = "/run/cyrus/db/statuscache.db";
263 syslog_prefix = "cyrus";
264 tls_client_ca_dir = "/etc/ssl/certs";
265 tls_session_timeout = 1440;
266 tls_sessions_db_path = "/run/cyrus/db/tls_sessions.db";
269 description = "IMAP configuration settings. See [imapd.conf(5)](https://www.cyrusimap.org/imap/reference/manpages/configs/imapd.conf.html)";
275 description = "Cyrus IMAP user name. If this is not set, a user named `cyrus` will be created.";
281 description = "Cyrus IMAP group name. If this is not set, a group named `cyrus` will be created.";
284 imapdConfigFile = mkOption {
287 description = "Path to the configuration file used for cyrus-imap.";
288 apply = v: if v != null then v else pkgs.writeText "imapd.conf" imapdConfig;
291 cyrusConfigFile = mkOption {
294 description = "Path to the configuration file used for Cyrus.";
295 apply = v: if v != null then v else pkgs.writeText "cyrus.conf" cyrusConfig;
298 sslCACert = mkOption {
301 description = "File path which containing one or more CA certificates to use.";
304 sslServerCert = mkOption {
307 description = "File containing the global certificate used for all services (IMAP, POP3, LMTP, Sieve)";
310 sslServerKey = mkOption {
313 description = "File containing the private key belonging to the global server certificate.";
317 config = mkIf cfg.enable {
318 users.users.cyrus = optionalAttrs (cfg.user == null) {
319 description = "Cyrus IMAP user";
321 group = optionalString (cfg.group == null) "cyrus";
324 users.groups.cyrus = optionalAttrs (cfg.group == null) { };
326 environment.etc."imapd.conf".source = cfg.imapdConfigFile;
327 environment.etc."cyrus.conf".source = cfg.cyrusConfigFile;
329 systemd.services.cyrus-imap = {
330 description = "Cyrus IMAP server";
332 after = [ "network.target" ];
333 wantedBy = [ "multi-user.target" ];
339 startLimitIntervalSec = 60;
341 CYRUS_VERBOSE = mkIf cfg.debug "1";
342 LISTENQUEUE = builtins.toString cfg.listenQueue;
345 User = if (cfg.user == null) then "cyrus" else cfg.user;
346 Group = if (cfg.group == null) then "cyrus" else cfg.group;
348 ExecStart = "${cyrus-imapdPkg}/libexec/master -l $LISTENQUEUE -C /etc/imapd.conf -M /etc/cyrus.conf -p /run/cyrus/master.pid -D";
349 Restart = "on-failure";
351 RuntimeDirectory = "cyrus";
352 StateDirectory = "cyrus";
355 AmbientCapabilities = [ "CAP_NET_BIND_SERVICE" ];
357 PrivateDevices = true;
358 ProtectSystem = "full";
359 CapabilityBoundingSet = [ "~CAP_NET_ADMIN CAP_SYS_ADMIN CAP_SYS_BOOT CAP_SYS_MODULE" ];
360 MemoryDenyWriteExecute = true;
361 ProtectKernelModules = true;
362 ProtectKernelTunables = true;
363 ProtectControlGroups = true;
364 RestrictAddressFamilies = [
370 RestrictNamespaces = true;
371 RestrictRealtime = true;
374 mkdir -p '${cfg.imapdSettings.configdirectory}/socket' '${cfg.tmpDBDir}' /run/cyrus/proc /run/cyrus/lock
377 environment.systemPackages = [ cyrus-imapdPkg ];