diff --git a/flake.lock b/flake.lock index 7e8e0b4..214137e 100644 --- a/flake.lock +++ b/flake.lock @@ -33,6 +33,22 @@ "type": "github" } }, + "blobs": { + "flake": false, + "locked": { + "lastModified": 1604995301, + "narHash": "sha256-wcLzgLec6SGJA8fx1OEN1yV/Py5b+U5iyYpksUY/yLw=", + "owner": "simple-nixos-mailserver", + "repo": "blobs", + "rev": "2cccdf1ca48316f2cfd1c9a0017e8de5a7156265", + "type": "gitlab" + }, + "original": { + "owner": "simple-nixos-mailserver", + "repo": "blobs", + "type": "gitlab" + } + }, "deploy-rs": { "inputs": { "flake-compat": "flake-compat", @@ -145,6 +161,22 @@ "type": "github" } }, + "flake-compat_4": { + "flake": false, + "locked": { + "lastModified": 1767039857, + "narHash": "sha256-vNpUSpF5Nuw8xvDLj2KCwwksIbjua2LZCqhV1LNRDns=", + "owner": "edolstra", + "repo": "flake-compat", + "rev": "5edf11c44bc78a0d334f6334cdaf7d60d732daab", + "type": "github" + }, + "original": { + "owner": "edolstra", + "repo": "flake-compat", + "type": "github" + } + }, "flake-parts": { "inputs": { "nixpkgs-lib": [ @@ -223,6 +255,32 @@ "type": "github" } }, + "git-hooks": { + "inputs": { + "flake-compat": [ + "nixos-mailserver", + "flake-compat" + ], + "gitignore": "gitignore_2", + "nixpkgs": [ + "nixos-mailserver", + "nixpkgs" + ] + }, + "locked": { + "lastModified": 1775585728, + "narHash": "sha256-8Psjt+TWvE4thRKktJsXfR6PA/fWWsZ04DVaY6PUhr4=", + "owner": "cachix", + "repo": "git-hooks.nix", + "rev": "580633fa3fe5fc0379905986543fd7495481913d", + "type": "github" + }, + "original": { + "owner": "cachix", + "repo": "git-hooks.nix", + "type": "github" + } + }, "gitignore": { "inputs": { "nixpkgs": [ @@ -245,6 +303,28 @@ "type": "github" } }, + "gitignore_2": { + "inputs": { + "nixpkgs": [ + "nixos-mailserver", + "git-hooks", + "nixpkgs" + ] + }, + "locked": { + "lastModified": 1709087332, + "narHash": "sha256-HG2cCnktfHsKV0s4XW83gU3F57gaTljL9KNSuG6bnQs=", + "owner": "hercules-ci", + "repo": "gitignore.nix", + "rev": "637db329424fd7e46cf4185293b9cc8c88c95394", + "type": "github" + }, + "original": { + "owner": "hercules-ci", + "repo": "gitignore.nix", + "type": "github" + } + }, "home-manager": { "inputs": { "nixpkgs": [ @@ -677,6 +757,30 @@ "type": "github" } }, + "nixos-mailserver": { + "inputs": { + "blobs": "blobs", + "flake-compat": "flake-compat_4", + "git-hooks": "git-hooks", + "nixpkgs": [ + "nixpkgs" + ] + }, + "locked": { + "lastModified": 1764075412, + "narHash": "sha256-d1+H7z21NsXgk9vL/9LAPUuiKrq9iqFxxqAWNNk1gY0=", + "owner": "simple-nixos-mailserver", + "repo": "nixos-mailserver", + "rev": "8d35f004eeb47cfcfa5c4e1c8765f5c1bf64b9a0", + "type": "gitlab" + }, + "original": { + "owner": "simple-nixos-mailserver", + "ref": "snm-25.11", + "repo": "nixos-mailserver", + "type": "gitlab" + } + }, "nixos-stable": { "locked": { "lastModified": 1749086602, @@ -821,6 +925,7 @@ "nix-minecraft": "nix-minecraft", "nixos-anywhere": "nixos-anywhere", "nixos-hardware": "nixos-hardware", + "nixos-mailserver": "nixos-mailserver", "nixpkgs": "nixpkgs_2", "nixpkgs-fixed": "nixpkgs-fixed", "nixvim": "nixvim", diff --git a/flake.nix b/flake.nix index b5d03ba..1cef3cc 100644 --- a/flake.nix +++ b/flake.nix @@ -43,6 +43,10 @@ url = "github:Mic92/sops-nix"; inputs.nixpkgs.follows = "nixpkgs"; }; + nixos-mailserver = { + url = "gitlab:simple-nixos-mailserver/nixos-mailserver/snm-25.11"; + inputs.nixpkgs.follows = "nixpkgs"; + }; nix-minecraft.url = "github:Infinidoge/nix-minecraft"; }; diff --git a/nixos/module/hectic/archetype/base.nix b/nixos/module/hectic/archetype/base.nix index c77bd08..48b9aba 100644 --- a/nixos/module/hectic/archetype/base.nix +++ b/nixos/module/hectic/archetype/base.nix @@ -12,6 +12,7 @@ in { imports = [ inputs.disko.nixosModules.default + inputs.nixos-mailserver.nixosModules.mailserver ]; options.hectic.archetype.base.enable = lib.mkEnableOption "Enable archetupe.dev"; diff --git a/nixos/module/hectic/service/mailserver.nix b/nixos/module/hectic/service/mailserver.nix new file mode 100644 index 0000000..f75c019 --- /dev/null +++ b/nixos/module/hectic/service/mailserver.nix @@ -0,0 +1,62 @@ +{ + inputs, + flake, + self, +}: +{ + lib, + config, + ... +}: let + cfg = config.services.mailserver; + transformLoginAccounts = domain: input: + builtins.listToAttrs (map (key: { + name = key + "@" + domain; + value = input.${key}; + }) (builtins.attrNames input)); +in { + options = { + services.mailserver.enable = lib.mkEnableOption "Mail server"; + + services.mailserver.domain = lib.mkOption { + type = lib.types.str; + description = "The domain name of the mail server"; + }; + + services.mailserver.loginAccounts = lib.mkOption { + type = lib.types.attrsOf (lib.types.submodule { + options = { + hashedPassword = lib.mkOption { + type = lib.types.nullOr lib.types.str; + default = null; + }; + hashedPasswordFile = lib.mkOption { + type = lib.types.nullOr lib.types.str; + default = null; + description = '' + Full path to a file containing the hashed password suitable + for use with `chpasswd -e`. + ''; + }; + }; + }); + default = {}; + description = "Login accounts for the mail server"; + }; + }; + + config = lib.mkIf cfg.enable { + mailserver = { + enable = true; + fqdn = "mail." + cfg.domain; + domains = [ cfg.domain ]; + + loginAccounts = transformLoginAccounts cfg.domain cfg.loginAccounts; + + certificateScheme = "acme-nginx"; + }; + + security.acme.acceptTerms = true; + security.acme.defaults.email = "security@" + cfg.domain; + }; +} diff --git a/nixos/system/hectic-lab/hectic-lab.nix b/nixos/system/hectic-lab/hectic-lab.nix index e2f6f77..7cf9988 100644 --- a/nixos/system/hectic-lab/hectic-lab.nix +++ b/nixos/system/hectic-lab/hectic-lab.nix @@ -41,6 +41,19 @@ in { }; }; + # NOTE(yukkop): disk was provisioned by Hetzner rescue image, disko was never + # run, so partition labels don't exist. Override fileSystems with actual UUIDs. + fileSystems."/" = lib.mkForce { + device = "/dev/disk/by-uuid/48ba7286-d019-4cdc-9784-459767979b07"; + fsType = "ext4"; + }; + + fileSystems."/boot" = lib.mkForce { + device = "/dev/disk/by-uuid/71F2-4E98"; + fsType = "vfat"; + options = [ "umask=0077" ]; + }; + programs.zsh.enable = true; programs.zsh.interactiveShellInit = '' setopt vi @@ -89,27 +102,33 @@ in { sops.secrets."mailserver/security/hashedPassword" = {}; sops.secrets."mailserver/yukkop/hashedPassword" = {}; + sops.secrets."mailserver/founders/hashedPassword" = {}; sops.secrets."mailserver/snuff/hashedPassword" = {}; sops.secrets."mailserver/antoshka/hashedPassword" = {}; - # services.mailserver = { - # enable = false; - # domain = domain; - # loginAccounts = { - # "security" = { - # hashedPasswordFile = config.sops.secrets."mailserver/security/hashedPassword".path; - # }; - # "yukkop" = { - # hashedPasswordFile = config.sops.secrets."mailserver/yukkop/hashedPassword".path; - # }; - # "snuff" = { - # hashedPasswordFile = config.sops.secrets."mailserver/snuff/hashedPassword".path; - # }; - # "antoshka" = { - # hashedPasswordFile = config.sops.secrets."mailserver/antoshka/hashedPassword".path; - # }; - # }; - # }; + services.mailserver = { + enable = true; + domain = domain; + loginAccounts = { + "security" = { + hashedPasswordFile = config.sops.secrets."mailserver/security/hashedPassword".path; + }; + "founders" = { + hashedPasswordFile = config.sops.secrets."mailserver/founders/hashedPassword".path; + }; + "yukkop" = { + hashedPasswordFile = config.sops.secrets."mailserver/yukkop/hashedPassword".path; + }; + "snuff" = { + hashedPasswordFile = config.sops.secrets."mailserver/snuff/hashedPassword".path; + }; + "antoshka" = { + hashedPasswordFile = config.sops.secrets."mailserver/antoshka/hashedPassword".path; + }; + }; + }; + + mailserver.stateVersion = 3; services.redis.servers."vproxy-bot-test-state" = { enable = true; diff --git a/sus/hectic-lab.yaml b/sus/hectic-lab.yaml index 20ce63e..848e42e 100644 --- a/sus/hectic-lab.yaml +++ b/sus/hectic-lab.yaml @@ -2,7 +2,9 @@ mailserver: security: hashedPassword: ENC[AES256_GCM,data:Z03x7tWHIhlRPaRZSrukyYOKhs6LdasZhZdizHdhlaJp2bywQZXKBaDABj2ab4rhwAPCHWhSiBjz35zV,iv:Z3hLC/A4YLVQkflr4cg9/wkKzo/RUdnLTwYC7ZhS0Hk=,tag:mSF/mbzH7iG6PwzyEsmyGg==,type:str] yukkop: - hashedPassword: ENC[AES256_GCM,data:kwEki7VMcqKGN7MHJ3Ktcky+9w51v7XHsDzB1WGYkg228tEjY5xECokl0kWM7q5+wNK+Tob4lbq3BNkv,iv:ULaAjXXSrXAuoYF6PMlRhkMmmP29ce9FAxzDvTg1X20=,tag:3fba4FQFRSo/k8Ekp5w5qw==,type:str] + hashedPassword: ENC[AES256_GCM,data:zjhCFkmmMzQHn09uRz1S4NTNU8hVRY5ZSYRHn6Gd0u09Fc7inNVSPrO+Br41UagPmv526w9MMQoIbV3RiJq6E/mfhAouqybYbQ==,iv:aVjn+/X2ESgZU7p7jETONaqtsD2/NAFOd7IIbunTRaI=,tag:kueml9QdQYVBceFMCgWoGA==,type:str] + founders: + hashedPassword: ENC[AES256_GCM,data:E+Xu/Ul3rFLlYDD0LGGRnc6RADlWmXpOM2OfkZFSzAf5thm8leRi9x5sroP25cO8CcSyBcOiUCBv3RC5ooXklm4cmpOx8LA8ug==,iv:RLbU6SBHKOBRCNZ6naxQMaNjWZOlNui6OaaVM2QkdZs=,tag:sO7CD+PVkdtvPvlUrpzW+g==,type:str] snuff: hashedPassword: ENC[AES256_GCM,data:Dv0vhe5LEFbAi/hadztQUTrRbPENSTxxOSTM7iwosH5kO28FCK56ZkKD8p/CLva6v97Cp2sWAXwd0fS6,iv:nUF4deb/8iF1mS5h+Z6oDE16YVQZ6ArfSnXG9DzqzLE=,tag:rKKlkYOl5oABbnzEjTOSVQ==,type:str] antoshka: @@ -68,7 +70,7 @@ sops: Yk43ZmlTc09aNFV1VjdjN2RWQlFWTDQKcYSvA2lHP8GS0lkYY19Tm8RXmFHQX5Ck qV2Fn22Fic4M5FVKDEMfaO6WmeXgki9a8dGeO9LlC+Phf16SOq7eLw== -----END AGE ENCRYPTED FILE----- - lastmodified: "2025-08-12T11:42:59Z" - mac: ENC[AES256_GCM,data:gbZRWC1ruAJgynCbYknJCsuvrIiLQ/oq0wvbKTEU6PAii4ebUHhU4MzV7edu/YhHBM2Q4TGtRdbhk75k12cfdOoDmKigHgdZOq2ay1ZhN5lYK4DKyWmnJ8hy3d6SnXueceOexEgstohJjLO0fO59QCeh7RWSZPEbGzouxtKrtBg=,iv:SfjSG4id7+3D0CvWmMYZBxYGOFjJ3AsD5IBL/CSYMcU=,tag:A1nWtI0Ia9xRsPNps7h6Sg==,type:str] + lastmodified: "2026-04-26T10:30:18Z" + mac: ENC[AES256_GCM,data:D8O/NTSgI//jdDA8UX56t7EfqH+YKvGsDKCTopPPfg/o9uey+onhxDfiiHniUBWJf5lArgZVLR5KOoVwQQWY1fz3lp/2ZBzaDJnt+IiqVeXgImNuOmdWgmvJF6o2UmpjEISRGtC1ih8UHplaQw2e7YEiH/QUMHoz/TVRWDHaMas=,iv:UWJkyc6YYMush8ASgb0ntHXEBeo9u2eGJ93wBfQVm4g=,tag:nhaAeTvoObP9GT2iNNrAzA==,type:str] unencrypted_suffix: _unencrypted - version: 3.9.2 + version: 3.10.2