diff --git a/default.nix b/default.nix new file mode 100644 index 0000000..ecdf6b8 --- /dev/null +++ b/default.nix @@ -0,0 +1,260 @@ + +# nixos-mailserver: a simple mail server +# Copyright (C) 2016-2017 Robin Raymond +# +# This program is free software: you can redistribute it and/or modify +# it under the terms of the GNU General Public License as published by +# the Free Software Foundation, either version 3 of the License, or +# (at your option) any later version. +# +# This program is distributed in the hope that it will be useful, +# but WITHOUT ANY WARRANTY; without even the implied warranty of +# MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the +# GNU General Public License for more details. +# +# You should have received a copy of the GNU General Public License +# along with this program. If not, see + +{ config, lib, pkgs, ... }: + +with lib; + +let + cfg = config.mailserver; +in +{ + options.mailserver = { + enable = mkEnableOption "nixos-mailserver"; + + domain = mkOption { + type = types.str; + example = "example.com"; + description = "The domain that this mail server serves. So far only one domain is supported"; + }; + + hostPrefix = mkOption { + type = types.str; + default = "mail"; + description = '' + The prefix of the FQDN of the server. In this example the FQDN of the server + is given by 'mail.example.com' + ''; + }; + + loginAccounts = mkOption { + type = types.loaOf (types.submodule ({ name, ... }: { + options = { + name = mkOption { + type = types.str; + example = "user1"; + description = "Username"; + }; + + hashedPassword = mkOption { + type = types.str; + example = "$6$evQJs5CFQyPAW09S$Cn99Y8.QjZ2IBnSu4qf1vBxDRWkaIZWOtmu1Ddsm3.H3CFpeVc0JU4llIq8HQXgeatvYhh5O33eWG3TSpjzu6/"; + description = '' + Hashed password. Use `mkpasswd` as follows + + ``` + mkpasswd -m sha-512 "super secret password" + ``` + ''; + }; + }; + + config.name = mkDefault name; + })); + example = { + user1 = { + hashedPassword = "$6$evQJs5CFQyPAW09S$Cn99Y8.QjZ2IBnSu4qf1vBxDRWkaIZWOtmu1Ddsm3.H3CFpeVc0JU4llIq8HQXgeatvYhh5O33eWG3TSpjzu6/"; + }; + user2 = { + hashedPassword = "$6$oE0ZNv2n7Vk9gOf$9xcZWCCLGdMflIfuA0vR1Q1Xblw6RZqPrP94mEit2/81/7AKj2bqUai5yPyWE.QYPyv6wLMHZvjw3Rlg7yTCD/"; + }; + }; + description = '' + The login account of the domain. Every account is mapped to a unix user, + e.g. `user1@example.com`. To generate the passwords use `mkpasswd` as + follows + + ``` + mkpasswd -m sha-512 "super secret password" + ``` + ''; + default = {}; + }; + + virtualAliases = mkOption { + type = types.attrsOf (types.enum (builtins.attrNames cfg.loginAccounts)); + example = { + info = "user1"; + postmaster = "user1"; + abuse = "user1"; + }; + description = '' + Virtual Aliases. A virtual alias `info = "user1"` means that + all mail to `info@example.com` is forwarded to `user1@example.com`. Note + that it is expected that `postmaster@example.com` and `abuse@example.com` is + forwarded to some valid email address. (Alternatively you can create login + accounts for `postmaster` and (or) `abuse`). + ''; + default = {}; + }; + + vmailUIDStart = mkOption { + type = types.int; + default = 5000; + description = '' + The unix UID where the loginAccounts are created. 5000 means that the first + user will get 5000, the second 5001, ... + ''; + }; + + vmailUserName = mkOption { + type = types.str; + default = "vmail"; + description = '' + The user name and group name of the user that owns the directory where all + the mail is stored. + ''; + }; + + vmailGroupName = mkOption { + type = types.str; + default = "vmail"; + description = '' + The user name and group name of the user that owns the directory where all + the mail is stored. + ''; + }; + + mailDirectory = mkOption { + type = types.string; + default = "/var/vmail"; + description = '' + Where to store the mail. + ''; + }; + + certificateScheme = mkOption { + type = types.enum [ 1 2 ]; + default = 2; + description = '' + Certificate Files. There are three options for these. + + 1) You specify locations and manually copy certificates there. + 2) You let the server create new (self signed) certificates on the fly. + 3) You let the server create a certificate via `Let's Encrypt`. Note that + this implies that a stripped down webserver has to be started. This also + implies that the FQDN must be set as an `A` record to point to the IP of + the server. TODO: Explain more details + + TODO: Only certificate scheme 1) and 2) work as of yet. + ''; + }; + + certificateFile = mkOption { + type = types.path; + example = "/root/mail-server.crt"; + description = '' + Scheme 1) + Location of the certificate + ''; + }; + + keyFile = mkOption { + type = types.path; + example = "/root/mail-server.key"; + description = '' + Scheme 1) + Location of the key file + ''; + }; + + certificateDirectory = mkOption { + type = types.path; + default = "/var/certs"; + description = '' + Sceme 2) + This is the folder where the certificate will be created. The name is + hardcoded to "cert-.pem" and "key-.pem" and the + certificate is valid for 10 years. + ''; + }; + + enableImap = mkOption { + type = types.bool; + default = true; + description = '' + Whether to enable imap / pop3. Both variants are only supported in the + (sane) startTLS configuration. (TODO: Allow SSL ports). The ports are + + 110 - Pop3 + 143 - IMAP + 587 - SMTP with login + ''; + }; + + enablePop3 = mkOption { + type = types.bool; + default = false; + description = '' + Whether to enable POP3. Both variants are only supported in the + (sane) startTLS configuration. (TODO: Allow SSL ports). The ports are + + 110 - Pop3 + 143 - IMAP + 587 - SMTP with login + ''; + }; + + # imapSsl = mkOption {} #< TODO + # pop3Ssl = mkOption {} #< TODO + + virusScanning = mkOption { + type = types.bool; + default = false; + description = '' + Whether to activate virus scanning. Note that virus scanning is _very_ + expensive memory wise. + ''; + }; + + dkimSigning = mkOption { + type = types.bool; + default = true; + description = '' + Whether to activate dkim signing. + TODO: Explain how to put signature into domain record + ''; + }; + + dkimSelector = mkOption { + type = types.string; + default = "mail"; + description = '' + + ''; + }; + + dkimKeyDirectory = mkOption { + type = types.path; + default = "/var/dkim"; + description = '' + + ''; + }; + }; + + imports = [ + ./mail-server/clamav.nix + ./mail-server/users.nix + ./mail-server/environment.nix + ./mail-server/networking.nix + ./mail-server/systemd.nix + ./mail-server/dovecot.nix + ./mail-server/postfix.nix + ./mail-server/rmilter.nix + ]; +} diff --git a/mail-config.nix b/mail-config.nix deleted file mode 100644 index a8e3203..0000000 --- a/mail-config.nix +++ /dev/null @@ -1,161 +0,0 @@ -# nixos-mailserver: a simple mail server -# Copyright (C) 2016-2017 Robin Raymond -# -# This program is free software: you can redistribute it and/or modify -# it under the terms of the GNU General Public License as published by -# the Free Software Foundation, either version 3 of the License, or -# (at your option) any later version. -# -# This program is distributed in the hope that it will be useful, -# but WITHOUT ANY WARRANTY; without even the implied warranty of -# MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the -# GNU General Public License for more details. -# -# You should have received a copy of the GNU General Public License -# along with this program. If not, see - -{ config, pkgs, ... }: - -let - - # - # The domain that this mail server serves. So far only one domain is supported - # - domain = "example.com"; - - # - # The prefix of the FQDN of the server. In this example the FQDN of the server - # is given by 'mail.example.com' - # - host_prefix = "mail"; - - # - # The login account of the domain. Every account is mapped to a unix user, - # e.g. `user1@example.com`. To generate the passwords use `mkpasswd` as - # follows - # - # ``` - # mkpasswd -m sha-512 "super secret password" - # ``` - # - login_accounts = [ - { name = "user1"; - password = "$6$evQJs5CFQyPAW09S$Cn99Y8.QjZ2IBnSu4qf1vBxDRWkaIZWOtmu1Ddsm3.H3CFpeVc0JU4llIq8HQXgeatvYhh5O33eWG3TSpjzu6/"; - } - { name = "user2"; - password = "$6$oE0ZNv2n7Vk9gOf$9xcZWCCLGdMflIfuA0vR1Q1Xblw6RZqPrP94mEit2/81/7AKj2bqUai5yPyWE.QYPyv6wLMHZvjw3Rlg7yTCD/"; - } - ]; - - # - # Virtual Aliases. A virtual alias { from = "info"; to = "user1"; } means that - # all mail to `info@example.com` is forwarded to `user1@example.com`. Note - # that it is expected that `postmaster@example.com` and `abuse@example.com` is - # forwarded to some valid email address. (Alternatively you can create login - # accounts for `postmaster` and (or) `abuse`). - # - valiases = [ - { from = "info"; - to = "user1"; - } - { from = "postmaster"; - to = "user1"; - } - { from = "abuse"; - to = "user1"; - } - ]; - - # - # The unix UID where the login_accounts are created. 5000 means that the first - # user will get 5000, the second 5001, ... - # - vmail_id_start = 5000; - - # - # The user name and group name of the user that owns the directory where all - # the mail is stored. - # - vmail_user_name = "vmail"; - vmail_group_name = "vmail"; - - # - # Where to store the mail. - # - mail_dir = "/var/vmail"; - - # - # Certificate Files. There are three options for these. - # - # 1) You specify locations and manually copy certificates there. - # 2) You let the server create new (self signed) certificates on the fly. - # 3) You let the server create a certificate via `Let's Encrypt`. Note that - # this implies that a stripped down webserver has to be started. This also - # implies that the FQDN must be set as an `A` record to point to the IP of - # the server. TODO: Explain more details - # - # TODO: Only certificate scheme 1) and 2) work as of yet. - certificate_scheme = 2; - - # Sceme 1) - cert_file = "/root/mail-server.crt"; - key_file = "/root/mail-server.key"; - - # Sceme 2) - # This is the folder where the certificate will be created. The name is - # hardcoded to "cert-${domain}.pem" and "key-${domain}.pem" and the - # certificate is valid for 10 years. - cert_dir = "/var/certs"; - - # - # Whether to enable imap / pop3. Both variants are only supported in the - # (sane) startTLS configuration. (TODO: Allow SSL ports). The ports are - # - # 110 - Pop3 - # 143 - IMAP - # 587 - SMTP with login - # - enable_imap = true; - enable_pop3 = false; - # imap_ssl = false; #< TODO - # pop3_ssl = false; #< TODO - - # - # Whether to activate virus scanning. Note that virus scanning is _very_ - # expensive memory wise. - # - virus_scanning = false; - - # - # Whether to activate dkim signing. - # TODO: Explain how to put signature into domain record - # - dkim_signing = true; - dkim_selector = "mail"; - dkim_dir = "/var/dkim"; -in -{ - services = import ./mail-server/services.nix { - inherit mail_dir vmail_user_name vmail_group_name valiases domain - enable_imap enable_pop3 virus_scanning dkim_signing dkim_selector - dkim_dir certificate_scheme cert_file key_file cert_dir; - }; - - environment = import ./mail-server/environment.nix { - inherit pkgs certificate_scheme; - }; - - networking = import ./mail-server/networking.nix { - inherit domain host_prefix enable_imap enable_pop3; - }; - - systemd = import ./mail-server/systemd.nix { - inherit mail_dir vmail_group_name certificate_scheme cert_dir host_prefix - domain pkgs dkim_selector dkim_dir; - }; - - users = import ./mail-server/users.nix { - inherit vmail_id_start vmail_user_name vmail_group_name domain mail_dir - login_accounts; - }; -} diff --git a/mail-server/clamav.nix b/mail-server/clamav.nix index acea48f..5542a95 100644 --- a/mail-server/clamav.nix +++ b/mail-server/clamav.nix @@ -14,10 +14,15 @@ # You should have received a copy of the GNU General Public License # along with this program. If not, see -{ virus_scanning }: +{ config, pkgs, lib, ... }: +let + cfg = config.mailserver; +in { - daemon.enable = virus_scanning; - updater.enable = virus_scanning; + config = lib.mkIf cfg.virusScanning { + services.clamav.daemon.enable = true; + services.clamav.updater.enable = true; + }; } diff --git a/mail-server/common.nix b/mail-server/common.nix new file mode 100644 index 0000000..f32d898 --- /dev/null +++ b/mail-server/common.nix @@ -0,0 +1,36 @@ +# nixos-mailserver: a simple mail server +# Copyright (C) 2016-2017 Robin Raymond +# +# This program is free software: you can redistribute it and/or modify +# it under the terms of the GNU General Public License as published by +# the Free Software Foundation, either version 3 of the License, or +# (at your option) any later version. +# +# This program is distributed in the hope that it will be useful, +# but WITHOUT ANY WARRANTY; without even the implied warranty of +# MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the +# GNU General Public License for more details. +# +# You should have received a copy of the GNU General Public License +# along with this program. If not, see + +{ config }: + +let + cfg = config.mailserver; +in +{ + # cert :: PATH + certificatePath = if cfg.certificateScheme == 1 + then cfg.certificateFile + else if cfg.certificateScheme == 2 + then "${cfg.certificateDirectory}/cert-${cfg.domain}.pem" + else ""; + + # key :: PATH + keyPath = if cfg.certificateScheme == 1 + then cfg.keyFile + else if cfg.certificateScheme == 2 + then "${cfg.certificateDirectory}/key-${cfg.domain}.pem" + else ""; +} diff --git a/mail-server/dovecot.nix b/mail-server/dovecot.nix index b294ac1..3caca10 100644 --- a/mail-server/dovecot.nix +++ b/mail-server/dovecot.nix @@ -14,73 +14,80 @@ # You should have received a copy of the GNU General Public License # along with this program. If not, see -{ vmail_group_name, vmail_user_name, mail_dir, enable_imap, enable_pop3, cert, -key }: +{ config, pkgs, lib, ... }: + +with (import ./common.nix { inherit config; }); let + cfg = config.mailserver; + # maildir in format "/${domain}/${user}/" - dovecot_maildir = "maildir:${mail_dir}/%d/%n/"; + dovecot_maildir = "maildir:${cfg.mailDirectory}/%d/%n/"; in { - enable = true; - enableImap = enable_imap; - enablePop3 = enable_pop3; - mailGroup = vmail_group_name; - mailUser = vmail_user_name; - mailLocation = dovecot_maildir; - sslServerCert = cert; - sslServerKey = key; - enableLmtp = true; - extraConfig = '' - #Extra Config - mail_access_groups = ${vmail_group_name} - ssl = required + config = with cfg; lib.mkIf enable { + services.dovecot2 = { + enable = true; + enableImap = enableImap; + enablePop3 = enablePop3; + mailGroup = vmailGroupName; + mailUser = vmailUserName; + mailLocation = dovecot_maildir; + sslServerCert = certificatePath; + sslServerKey = keyPath; + enableLmtp = true; + extraConfig = '' + #Extra Config + mail_access_groups = ${vmailGroupName} + ssl = required - service lmtp { - unix_listener /var/lib/postfix/queue/private/dovecot-lmtp { + service lmtp { + unix_listener /var/lib/postfix/queue/private/dovecot-lmtp { group = postfix mode = 0600 user = postfix # TODO: < make variable - } - } + } + } - service auth { - unix_listener /var/lib/postfix/queue/private/auth { + service auth { + unix_listener /var/lib/postfix/queue/private/auth { mode = 0660 user = postfix # TODO: < make variable group = postfix # TODO: < make variable - } - } + } + } - auth_mechanisms = plain login + auth_mechanisms = plain login - namespace inbox { + namespace inbox { - #prefix = INBOX. - # the namespace prefix isn't added again to the mailbox names. - inbox = yes - # ... + #prefix = INBOX. + # the namespace prefix isn't added again to the mailbox names. + inbox = yes + # ... - mailbox "Trash" { - auto = no - special_use = \Trash - } + mailbox "Trash" { + auto = no + special_use = \Trash + } - mailbox "Junk" { - auto = subscribe - special_use = \Junk - } + mailbox "Junk" { + auto = subscribe + special_use = \Junk + } - mailbox "Drafts" { - auto = subscribe - special_use = \Drafts - } + mailbox "Drafts" { + auto = subscribe + special_use = \Drafts + } - mailbox "Sent" { - auto = subscribe - special_use = \Sent - } - } - ''; + mailbox "Sent" { + auto = subscribe + special_use = \Sent + } + } + ''; + }; + }; } diff --git a/mail-server/environment.nix b/mail-server/environment.nix index 3b61430..48e68c7 100644 --- a/mail-server/environment.nix +++ b/mail-server/environment.nix @@ -14,10 +14,15 @@ # You should have received a copy of the GNU General Public License # along with this program. If not, see -{ pkgs, certificate_scheme }: +{ config, pkgs, lib, ... }: +let + cfg = config.mailserver; +in { - systemPackages = with pkgs; [ - dovecot opendkim openssh postfix clamav rspamd rmilter - ] ++ (if certificate_scheme == 2 then [ openssl ] else []); + config = with cfg; lib.mkIf enable { + environment.systemPackages = with pkgs; [ + dovecot opendkim openssh postfix clamav rspamd rmilter + ] ++ (if certificateScheme == 2 then [ openssl ] else []); + }; } diff --git a/mail-server/networking.nix b/mail-server/networking.nix index fa3ff7e..62b2f3b 100644 --- a/mail-server/networking.nix +++ b/mail-server/networking.nix @@ -14,14 +14,20 @@ # You should have received a copy of the GNU General Public License # along with this program. If not, see -{ domain, host_prefix, enable_imap, enable_pop3 }: +{ config, pkgs, lib, ... }: +let + cfg = config.mailserver; +in { - hostName = "${host_prefix}.${domain}"; + config = with cfg; lib.mkIf enable { - firewall = { - allowedTCPPorts = [ 25 587 ] - ++ (if enable_imap then [ 143 ] else []) - ++ (if enable_pop3 then [ 110 ] else []); + networking.hostName = "${hostPrefix}.${domain}"; + + networking.firewall = { + allowedTCPPorts = [ 25 587 ] + ++ (if enableImap then [ 143 ] else []) + ++ (if enablePop3 then [ 110 ] else []); + }; }; } diff --git a/mail-server/postfix.nix b/mail-server/postfix.nix index d9ff629..b914ad5 100644 --- a/mail-server/postfix.nix +++ b/mail-server/postfix.nix @@ -14,25 +14,25 @@ # You should have received a copy of the GNU General Public License # along with this program. If not, see -{ mail_dir, domain, valiases, cert, key }: +{ config, pkgs, lib, ... }: + +with (import ./common.nix { inherit config; }); let - # valiasToString :: { from = "..."; to = "..." } -> String - valiasToString = x: "${x.from}@${domain} ${x.to}@${domain}\n"; + cfg = config.mailserver; # valiases_postfix :: [ String ] - valiases_postfix = map valiasToString valiases; - - # concatString :: [ String ] -> String - concatString = l: if l == [] - then "" - else (builtins.head l) + (concatString (builtins.tail l)); + valiases_postfix = map + (from: + let to = cfg.virtualAliases.${from}; + in "${from}@${cfg.domain} ${to}@${cfg.domain}") + (builtins.attrNames cfg.virtualAliases); # valiases_file :: Path - valiases_file = builtins.toFile "valias" (concatString valiases_postfix); + valiases_file = builtins.toFile "valias" (lib.concatStringsSep "\n" valiases_postfix); # vhosts_file :: Path - vhosts_file = builtins.toFile "vhosts" domain; + vhosts_file = builtins.toFile "vhosts" cfg.domain; # vaccounts_file :: Path # see @@ -43,50 +43,54 @@ let in { - enable = true; - networksStyle = "host"; - mapFiles."valias" = valiases_file; - mapFiles."vaccounts" = vaccounts_file; - sslCert = cert; - sslKey = key; - enableSubmission = true; + config = with cfg; lib.mkIf enable { - extraConfig = - '' + services.postfix = { + enable = true; + networksStyle = "host"; + mapFiles."valias" = valiases_file; + mapFiles."vaccounts" = vaccounts_file; + sslCert = certificatePath; + sslKey = keyPath; + enableSubmission = true; - # Extra Config + extraConfig = + '' + # Extra Config - smtpd_banner = $myhostname ESMTP NO UCE - smtpd_tls_auth_only = yes - disable_vrfy_command = yes - message_size_limit = 20971520 + smtpd_banner = $myhostname ESMTP NO UCE + smtpd_tls_auth_only = yes + disable_vrfy_command = yes + message_size_limit = 20971520 - # virtual mail system - virtual_uid_maps = static:5000 - virtual_gid_maps = static:5000 - virtual_mailbox_base = ${mail_dir} - virtual_mailbox_domains = ${vhosts_file} - virtual_alias_maps = hash:/var/lib/postfix/conf/valias - virtual_transport = lmtp:unix:private/dovecot-lmtp + # virtual mail system + virtual_uid_maps = static:5000 + virtual_gid_maps = static:5000 + virtual_mailbox_base = ${mailDirectory} + virtual_mailbox_domains = ${vhosts_file} + virtual_alias_maps = hash:/var/lib/postfix/conf/valias + virtual_transport = lmtp:unix:private/dovecot-lmtp - # sasl with dovecot - smtpd_sasl_type = dovecot - smtpd_sasl_path = private/auth - smtpd_sasl_auth_enable = yes - smtpd_relay_restrictions = permit_mynetworks, permit_sasl_authenticated, reject_unauth_destination - ''; + # sasl with dovecot + smtpd_sasl_type = dovecot + smtpd_sasl_path = private/auth + smtpd_sasl_auth_enable = yes + smtpd_relay_restrictions = permit_mynetworks, permit_sasl_authenticated, reject_unauth_destination + ''; - submissionOptions = - { - smtpd_tls_security_level = "encrypt"; - smtpd_sasl_auth_enable = "yes"; - smtpd_sasl_type = "dovecot"; - smtpd_sasl_path = "private/auth"; - smtpd_sasl_security_options = "noanonymous"; - smtpd_sasl_local_domain = "$myhostname"; - smtpd_client_restrictions = "permit_sasl_authenticated,reject"; - smtpd_sender_login_maps = "hash:/etc/postfix/vaccounts"; - smtpd_sender_restrictions = "reject_sender_login_mismatch"; - smtpd_recipient_restrictions = "reject_non_fqdn_recipient,reject_unknown_recipient_domain,permit_sasl_authenticated,reject"; + submissionOptions = + { + smtpd_tls_security_level = "encrypt"; + smtpd_sasl_auth_enable = "yes"; + smtpd_sasl_type = "dovecot"; + smtpd_sasl_path = "private/auth"; + smtpd_sasl_security_options = "noanonymous"; + smtpd_sasl_local_domain = "$myhostname"; + smtpd_client_restrictions = "permit_sasl_authenticated,reject"; + smtpd_sender_login_maps = "hash:/etc/postfix/vaccounts"; + smtpd_sender_restrictions = "reject_sender_login_mismatch"; + smtpd_recipient_restrictions = "reject_non_fqdn_recipient,reject_unknown_recipient_domain,permit_sasl_authenticated,reject"; + }; + }; }; } diff --git a/mail-server/rmilter.nix b/mail-server/rmilter.nix index 911eaf8..1f30ede 100644 --- a/mail-server/rmilter.nix +++ b/mail-server/rmilter.nix @@ -14,10 +14,12 @@ # You should have received a copy of the GNU General Public License # along with this program. If not, see -{ domain, virus_scanning, dkim_signing, dkim_dir, dkim_selector }: +{ config, pkgs, lib, ... }: let - clamav = if virus_scanning + cfg = config.mailserver; + + clamav = if cfg.virusScanning then '' clamav { @@ -25,14 +27,14 @@ let }; '' else ""; - dkim = if dkim_signing + dkim = if cfg.dkimSigning then '' dkim { domain { - key = "${dkim_dir}"; + key = "${cfg.dkimKeyDirectory}"; domain = "*"; - selector = "${dkim_selector}"; + selector = "${cfg.dkimSelector}"; }; sign_alg = sha256; auth_only = yes; @@ -41,15 +43,19 @@ let else ""; in { - enable = true; - # debug = true; - postfix.enable = true; - rspamd.enable = true; - extraConfig = - '' - ${clamav} + config = with cfg; lib.mkIf enable { + services.rmilter = { + enable = true; + #debug = true; + postfix.enable = true; + rspamd.enable = true; + extraConfig = + '' + ${clamav} - ${dkim} - ''; + ${dkim} + ''; + }; + }; } diff --git a/mail-server/services.nix b/mail-server/services.nix index ae007fe..2cebdaf 100644 --- a/mail-server/services.nix +++ b/mail-server/services.nix @@ -14,45 +14,31 @@ # You should have received a copy of the GNU General Public License # along with this program. If not, see -{ mail_dir, vmail_user_name, vmail_group_name, valiases, domain, enable_imap, -enable_pop3, virus_scanning, dkim_signing, dkim_selector, dkim_dir, -certificate_scheme, cert_file, key_file, cert_dir }: + +{ config, pkgs, lib, ... }: let + cfg = config.mailserver; + # cert :: PATH - cert = if certificate_scheme == 1 - then cert_file - else if certificate_scheme == 2 - then "${cert_dir}/cert-${domain}.pem" + cert = if cfg.certificateScheme == 1 + then cfg.certificateFile + else if cfg.certificateScheme == 2 + then "${cfg.certificateDirectory}/cert-${cfg.domain}.pem" else ""; # key :: PATH - key = if certificate_scheme == 1 - then key_file - else if certificate_scheme == 2 - then "${cert_dir}/key-${domain}.pem" + key = if cfg.certificateScheme == 1 + then cfg.keyFile + else if cfg.certificateScheme == 2 + then "${cfg.certificateDirectory}/key-${cfg.domain}.pem" else ""; in { - # rspamd - rspamd = { - enable = true; - }; - - rmilter = import ./rmilter.nix { - inherit domain virus_scanning dkim_signing dkim_selector dkim_dir; - }; - - postfix = import ./postfix.nix { - inherit mail_dir domain valiases cert key; - }; - - dovecot2 = import ./dovecot.nix { - inherit vmail_group_name vmail_user_name mail_dir enable_imap - enable_pop3 cert key; - }; - - clamav = import ./clamav.nix { - inherit virus_scanning; - }; + + imports = [ + ./rmilter.nix + ./postfix.nix key + ./dovecot.nix + ]; } diff --git a/mail-server/systemd.nix b/mail-server/systemd.nix index c862b9e..9cae899 100644 --- a/mail-server/systemd.nix +++ b/mail-server/systemd.nix @@ -14,22 +14,23 @@ # You should have received a copy of the GNU General Public License # along with this program. If not, see -{ pkgs, mail_dir, vmail_group_name, certificate_scheme, cert_dir, host_prefix, -domain, dkim_selector, dkim_dir}: +{ config, pkgs, lib, ... }: let - create_certificate = if certificate_scheme == 2 then + cfg = config.mailserver; + + create_certificate = if cfg.certificateScheme == 2 then '' # Create certificates if they do not exist yet - dir="${cert_dir}" - fqdn="${host_prefix}.${domain}" + dir="${cfg.certificateDirectory}" + fqdn="${cfg.hostPrefix}.${cfg.domain}" case $fqdn in /*) fqdn=$(cat "$fqdn");; esac - key="''${dir}/key-${domain}.pem"; - cert="''${dir}/cert-${domain}.pem"; + key="''${dir}/key-${cfg.domain}.pem"; + cert="''${dir}/cert-${cfg.domain}.pem"; if [ ! -f "''${key}" ] || [ ! -f "''${cert}" ] then - mkdir -p "${cert_dir}" + mkdir -p "${cfg.certificateDirectory}" (umask 077; "${pkgs.openssl}/bin/openssl" genrsa -out "''${key}" 2048) && "${pkgs.openssl}/bin/openssl" req -new -key "''${key}" -x509 -subj "/CN=''${fqdn}" \ -days 3650 -out "''${cert}" @@ -37,47 +38,50 @@ let '' else ""; - dkim_key = "${dkim_dir}/${dkim_selector}.private"; - dkim_txt = "${dkim_dir}/${dkim_selector}.txt"; + dkim_key = "${cfg.dkimKeyDirectory}/${cfg.dkimSelector}.private"; + dkim_txt = "${cfg.dkimKeyDirectory}/${cfg.dkimSelector}.txt"; create_dkim_cert = '' # Create dkim dir - mkdir -p "${dkim_dir}" - chown rmilter:rmilter "${dkim_dir}" + mkdir -p "${cfg.dkimKeyDirectory}" + chown rmilter:rmilter "${cfg.dkimKeyDirectory}" if [ ! -f "${dkim_key}" ] || [ ! -f "${dkim_txt}" ] then - ${pkgs.opendkim}/bin/opendkim-genkey -s "${dkim_selector}" \ - -d ${domain} \ - --directory="${dkim_dir}" + ${pkgs.opendkim}/bin/opendkim-genkey -s "${cfg.dkimSelector}" \ + -d ${cfg.domain} \ + --directory="${cfg.dkimKeyDirectory}" chown rmilter:rmilter "${dkim_key}" fi ''; in { - # Make sure postfix gets started first, so that the certificates are in place - services.dovecot2.after = [ "postfix.service" ]; + config = with cfg; lib.mkIf enable { + # Make sure postfix gets started first, so that the certificates are in place + systemd.services.dovecot2.after = [ "postfix.service" ]; - # Create certificates and maildir folder - services.postfix = { - preStart = - '' + # Create certificates and maildir folder + systemd.services.postfix = { + preStart = + '' # Create mail directory and set permissions. See # . mkdir -p "${mail_dir}" chgrp "${vmail_group_name}" "${mail_dir}" chmod 02770 "${mail_dir}" - ${create_certificate} - ''; - }; + ${create_certificate} + ''; + }; + + # Create dkim certificates + systemd.services.rmilter = { + preStart = + '' + ${create_dkim_cert} + ''; + }; - # Create dkim certificates - services.rmilter = { - preStart = - '' - ${create_dkim_cert} - ''; }; } diff --git a/mail-server/users.nix b/mail-server/users.nix index e84de1b..a8cbcc9 100644 --- a/mail-server/users.nix +++ b/mail-server/users.nix @@ -14,37 +14,41 @@ # You should have received a copy of the GNU General Public License # along with this program. If not, see -{ vmail_id_start, vmail_user_name, vmail_group_name, domain, mail_dir, -login_accounts }: +{ config, pkgs, lib, ... }: + +with config.mailserver; let vmail_user = [{ - name = vmail_user_name; + name = vmailUserName; isNormalUser = false; - uid = vmail_id_start; - home = mail_dir; + uid = vmailUIDStart; + home = mailDirectory; createHome = true; - group = vmail_group_name; + group = vmailGroupName; }]; # accountsToUser :: String -> UserRecord - accountsToUser = x: { - name = x.name + "@" + domain; + accountsToUser = account: { + name = account.name + "@" + domain; isNormalUser = false; - group = vmail_group_name; - hashedPassword = x.password; + group = vmailGroupName; + inherit (account) hashedPassword; }; # mail_user :: [ UserRecord ] - mail_user = map accountsToUser login_accounts; + mail_user = map accountsToUser (lib.attrValues loginAccounts); in { - # set the vmail gid to a specific value - groups = { - vmail = { gid = vmail_id_start; }; - }; - # define all users - extraUsers = vmail_user ++ mail_user; + config = lib.mkIf enable { + # set the vmail gid to a specific value + users.groups = { + vmail = { gid = vmailUIDStart; }; + }; + + # define all users + users.extraUsers = vmail_user ++ mail_user; + }; } diff --git a/nixops/single-server.nix b/nixops/single-server.nix index a6aa831..a96da0b 100644 --- a/nixops/single-server.nix +++ b/nixops/single-server.nix @@ -5,7 +5,12 @@ { config, pkgs, ... }: { imports = [ - ./../mail-config.nix + ./../default.nix ]; + + mailserver = { + enable = true; + domain = "example.com"; + }; }; }