From b721630485d7584373040331f8ae685cb113a26c Mon Sep 17 00:00:00 2001 From: Love Billenius Date: Tue, 7 Apr 2026 19:25:39 +0200 Subject: [PATCH] mail --- flake.lock | 221 ++++++++++++++++-- flake.nix | 120 +++++++--- hosts/hermes/default.nix | 57 +++++ hosts/hermes/disko.nix | 118 ++++++++++ .../mail-password-hash/love@billenius.com | 1 + hosts/hermes/mail.nix | 24 ++ hosts/hermes/roundcube.nix | 46 ++++ 7 files changed, 541 insertions(+), 46 deletions(-) create mode 100644 hosts/hermes/default.nix create mode 100644 hosts/hermes/disko.nix create mode 100644 hosts/hermes/mail-password-hash/love@billenius.com create mode 100644 hosts/hermes/mail.nix create mode 100644 hosts/hermes/roundcube.nix diff --git a/flake.lock b/flake.lock index 2e7cd61..d731597 100644 --- a/flake.lock +++ b/flake.lock @@ -1,9 +1,45 @@ { "nodes": { - "disko": { + "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" + } + }, + "disko-stable": { "inputs": { "nixpkgs": [ - "nixpkgs" + "nixpkgs-stable" + ] + }, + "locked": { + "lastModified": 1773889306, + "narHash": "sha256-PAqwnsBSI9SVC2QugvQ3xeYCB0otOwCacB1ueQj2tgw=", + "owner": "nix-community", + "repo": "disko", + "rev": "5ad85c82cc52264f4beddc934ba57f3789f28347", + "type": "github" + }, + "original": { + "owner": "nix-community", + "repo": "disko", + "type": "github" + } + }, + "disko-unstable": { + "inputs": { + "nixpkgs": [ + "nixpkgs-unstable" ] }, "locked": { @@ -23,15 +59,15 @@ "dotfiles": { "inputs": { "home-manager": [ - "home-manager" + "home-manager-unstable" ], "nixpkgs": [ - "nixpkgs" + "nixpkgs-unstable" ] }, "locked": { - "lastModified": 1774967561, - "narHash": "sha256-k+ODWq4WWoVz5eAmbWG1JME4X4ql1OdTcT8n3gBFxZg=", + "lastModified": 1775577131, + "narHash": "sha256-SIl8dRsVQy3tuCP6LbcIx9y/JtGpQLI6YCeNIVjW38Y=", "path": "/home/love/dotfiles", "type": "path" }, @@ -40,18 +76,82 @@ "type": "path" } }, - "home-manager": { + "flake-compat": { + "flake": false, + "locked": { + "lastModified": 1747046372, + "narHash": "sha256-CIVLLkVgvHYbgI2UpXvIIBJ12HWgX+fjA8Xf8PUmqCY=", + "owner": "edolstra", + "repo": "flake-compat", + "rev": "9100a0f413b0c601e0533d1d94ffd501ce2e7885", + "type": "github" + }, + "original": { + "owner": "edolstra", + "repo": "flake-compat", + "type": "github" + } + }, + "git-hooks": { "inputs": { + "flake-compat": [ + "mailserver", + "flake-compat" + ], + "gitignore": "gitignore", "nixpkgs": [ + "mailserver", "nixpkgs" ] }, "locked": { - "lastModified": 1775047159, - "narHash": "sha256-UWM4VZvfKaPwA9FMu7iZha5YAE8vsEtUazk+rFxmbTY=", + "lastModified": 1742649964, + "narHash": "sha256-DwOTp7nvfi8mRfuL1escHDXabVXFGT1VlPD1JHrtrco=", + "owner": "cachix", + "repo": "git-hooks.nix", + "rev": "dcf5072734cb576d2b0c59b2ac44f5050b5eac82", + "type": "github" + }, + "original": { + "owner": "cachix", + "repo": "git-hooks.nix", + "type": "github" + } + }, + "gitignore": { + "inputs": { + "nixpkgs": [ + "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-unstable": { + "inputs": { + "nixpkgs": [ + "nixpkgs-unstable" + ] + }, + "locked": { + "lastModified": 1775556024, + "narHash": "sha256-j1u/859OVS54rGlsvFqJdwKPEnFYCI+4pyfTiSfv1Xc=", "owner": "nix-community", "repo": "home-manager", - "rev": "1ce9e62690dfdd7e76bd266ccb9a887778410eb2", + "rev": "4bdfeff1d9b7473e6e58f73f5809576e8a69e406", "type": "github" }, "original": { @@ -60,10 +160,10 @@ "type": "github" } }, - "lolcat++": { + "lolcat++-stable": { "inputs": { "nixpkgs": [ - "nixpkgs" + "nixpkgs-stable" ] }, "locked": { @@ -80,13 +180,90 @@ "type": "github" } }, - "nixpkgs": { + "lolcat++-unstable": { + "inputs": { + "nixpkgs": [ + "nixpkgs-unstable" + ] + }, "locked": { - "lastModified": 1774709303, - "narHash": "sha256-D3Q07BbIA2KnTcSXIqqu9P586uWxN74zNoCH3h2ESHg=", + "lastModified": 1774436770, + "narHash": "sha256-l9geMRTQbPlnds+QFAPBywpZWRNH964zOvkeUMX3k9U=", + "owner": "lolcatpp", + "repo": "lolcatpp", + "rev": "619f2bb439bd28a6d77f31361b24c5f48832b067", + "type": "github" + }, + "original": { + "owner": "lolcatpp", + "repo": "lolcatpp", + "type": "github" + } + }, + "mailserver": { + "inputs": { + "blobs": "blobs", + "flake-compat": "flake-compat", + "git-hooks": "git-hooks", + "nixpkgs": [ + "nixpkgs-stable" + ], + "nixpkgs-25_05": "nixpkgs-25_05" + }, + "locked": { + "lastModified": 1763302796, + "narHash": "sha256-mEc3SBjRYfMcbNFLxmCc5tRtlu3j+1q7zRz+nRraSFE=", + "owner": "simple-nixos-mailserver", + "repo": "nixos-mailserver", + "rev": "5b38fb599f50e9d78325d1d2706e36303c166047", + "type": "gitlab" + }, + "original": { + "owner": "simple-nixos-mailserver", + "ref": "nixos-25.05", + "repo": "nixos-mailserver", + "type": "gitlab" + } + }, + "nixpkgs-25_05": { + "locked": { + "lastModified": 1747610100, + "narHash": "sha256-rpR5ZPMkWzcnCcYYo3lScqfuzEw5Uyfh+R0EKZfroAc=", "owner": "NixOS", "repo": "nixpkgs", - "rev": "8110df5ad7abf5d4c0f6fb0f8f978390e77f9685", + "rev": "ca49c4304acf0973078db0a9d200fd2bae75676d", + "type": "github" + }, + "original": { + "owner": "NixOS", + "ref": "nixos-25.05", + "repo": "nixpkgs", + "type": "github" + } + }, + "nixpkgs-stable": { + "locked": { + "lastModified": 1767313136, + "narHash": "sha256-16KkgfdYqjaeRGBaYsNrhPRRENs0qzkQVUooNHtoy2w=", + "owner": "NixOS", + "repo": "nixpkgs", + "rev": "ac62194c3917d5f474c1a844b6fd6da2db95077d", + "type": "github" + }, + "original": { + "owner": "NixOS", + "ref": "nixos-25.05", + "repo": "nixpkgs", + "type": "github" + } + }, + "nixpkgs-unstable": { + "locked": { + "lastModified": 1775423009, + "narHash": "sha256-vPKLpjhIVWdDrfiUM8atW6YkIggCEKdSAlJPzzhkQlw=", + "owner": "NixOS", + "repo": "nixpkgs", + "rev": "68d8aa3d661f0e6bd5862291b5bb263b2a6595c9", "type": "github" }, "original": { @@ -98,11 +275,15 @@ }, "root": { "inputs": { - "disko": "disko", + "disko-stable": "disko-stable", + "disko-unstable": "disko-unstable", "dotfiles": "dotfiles", - "home-manager": "home-manager", - "lolcat++": "lolcat++", - "nixpkgs": "nixpkgs" + "home-manager-unstable": "home-manager-unstable", + "lolcat++-stable": "lolcat++-stable", + "lolcat++-unstable": "lolcat++-unstable", + "mailserver": "mailserver", + "nixpkgs-stable": "nixpkgs-stable", + "nixpkgs-unstable": "nixpkgs-unstable" } } }, diff --git a/flake.nix b/flake.nix index 570207d..dfb62c2 100644 --- a/flake.nix +++ b/flake.nix @@ -2,53 +2,121 @@ description = "NixOS configuration"; inputs = { - nixpkgs.url = "github:NixOS/nixpkgs/nixos-unstable"; + nixpkgs-stable.url = "github:NixOS/nixpkgs/nixos-25.05"; + nixpkgs-unstable.url = "github:NixOS/nixpkgs/nixos-unstable"; - disko = { + disko-stable = { url = "github:nix-community/disko"; - inputs.nixpkgs.follows = "nixpkgs"; + inputs.nixpkgs.follows = "nixpkgs-stable"; + }; + disko-unstable = { + url = "github:nix-community/disko"; + inputs.nixpkgs.follows = "nixpkgs-unstable"; }; - home-manager = { + home-manager-unstable = { url = "github:nix-community/home-manager"; - inputs.nixpkgs.follows = "nixpkgs"; + inputs.nixpkgs.follows = "nixpkgs-unstable"; }; - "lolcat++" = { + mailserver = { + url = "gitlab:simple-nixos-mailserver/nixos-mailserver?ref=nixos-25.05"; + inputs.nixpkgs.follows = "nixpkgs-stable"; + }; + + "lolcat++-stable" = { url = "github:lolcatpp/lolcatpp"; - inputs.nixpkgs.follows = "nixpkgs"; + inputs.nixpkgs.follows = "nixpkgs-stable"; + }; + "lolcat++-unstable" = { + url = "github:lolcatpp/lolcatpp"; + inputs.nixpkgs.follows = "nixpkgs-unstable"; }; dotfiles = { url = "path:/home/love/dotfiles"; - inputs.nixpkgs.follows = "nixpkgs"; - inputs.home-manager.follows = "home-manager"; + inputs.nixpkgs.follows = "nixpkgs-unstable"; + inputs.home-manager.follows = "home-manager-unstable"; }; }; outputs = inputs@{ - nixpkgs, - disko, - home-manager, + nixpkgs-stable, + nixpkgs-unstable, + disko-stable, + disko-unstable, + home-manager-unstable, dotfiles, ... }: + let + mkHost = { + hostPath, + nixpkgs, + disko, + lolcat, + }: + nixpkgs.lib.nixosSystem { + system = "x86_64-linux"; + specialArgs = { + inputs = inputs // { "lolcat++" = lolcat; }; + }; + modules = [ + disko.nixosModules.disko + hostPath + ]; + }; + mkDesktopHost = { + hostPath, + nixpkgs, + disko, + lolcat, + }: + nixpkgs.lib.nixosSystem { + system = "x86_64-linux"; + specialArgs = { + inputs = inputs // { "lolcat++" = lolcat; }; + }; + modules = [ + disko.nixosModules.disko + home-manager-unstable.nixosModules.home-manager + { + home-manager.useGlobalPkgs = true; + home-manager.useUserPackages = true; + home-manager.backupFileExtension = "hm-backup"; + home-manager.users.love = import "${dotfiles}/home.nix"; + } + hostPath + ]; + }; + in { - nixosConfigurations.kronos = nixpkgs.lib.nixosSystem { - system = "x86_64-linux"; - specialArgs = { inherit inputs; }; - modules = [ - disko.nixosModules.disko - home-manager.nixosModules.home-manager - { - home-manager.useGlobalPkgs = true; - home-manager.useUserPackages = true; - home-manager.backupFileExtension = "hm-backup"; - home-manager.users.love = import "${dotfiles}/home.nix"; - } - ./hosts/kronos - ]; + nixosConfigurations = { + Kronos = mkDesktopHost { + hostPath = ./hosts/kronos; + nixpkgs = nixpkgs-unstable; + disko = disko-unstable; + lolcat = inputs."lolcat++-unstable"; + }; + kronos = mkDesktopHost { + hostPath = ./hosts/kronos; + nixpkgs = nixpkgs-unstable; + disko = disko-unstable; + lolcat = inputs."lolcat++-unstable"; + }; + Hermes = mkHost { + hostPath = ./hosts/hermes; + nixpkgs = nixpkgs-stable; + disko = disko-stable; + lolcat = inputs."lolcat++-stable"; + }; + hermes = mkHost { + hostPath = ./hosts/hermes; + nixpkgs = nixpkgs-stable; + disko = disko-stable; + lolcat = inputs."lolcat++-stable"; + }; }; }; } diff --git a/hosts/hermes/default.nix b/hosts/hermes/default.nix new file mode 100644 index 0000000..dcc45f8 --- /dev/null +++ b/hosts/hermes/default.nix @@ -0,0 +1,57 @@ +{ + inputs, + config, + pkgs, + ... +}: +let + userName = "love"; + fullName = "Love"; + hostName = "Hermes"; + homeDir = "/home/${userName}"; + installDisk = "/dev/disk/by-id/scsi-0QEMU_QEMU_HARDDISK_115386992"; +in +{ + _module.args = { + inherit + fullName + homeDir + hostName + installDisk + userName + ; + }; + + imports = [ + inputs.mailserver.nixosModules.default + ./hardware-configuration.nix + ./disko.nix + ./mail.nix + ./roundcube.nix + ../../modules/base.nix + ../../modules/zfs-root.nix + ../../modules/desktop-hyprland.nix + ../../modules/bin-bash-wrapper.nix + ]; + + my.binBashWrapper.enable = true; + + networking.hostName = hostName; + networking.hostId = "8d49a097f2"; + + users.mutableUsers = true; + users.users.${userName} = { + isNormalUser = true; + description = fullName; + extraGroups = [ "wheel" ]; + shell = pkgs.bash; + }; + + zramSwap = { + enable = true; + memoryPercent = 75; + algorithm = "zstd"; + }; + + system.stateVersion = "25.05"; +} diff --git a/hosts/hermes/disko.nix b/hosts/hermes/disko.nix new file mode 100644 index 0000000..df876ec --- /dev/null +++ b/hosts/hermes/disko.nix @@ -0,0 +1,118 @@ +{ installDisk, ... }: +{ + disko.devices = { + disk.main = { + type = "disk"; + device = installDisk; + content = { + type = "gpt"; + partitions = { + ESP = { + label = "EFI"; + size = "512MiB"; + type = "EF00"; + content = { + type = "filesystem"; + format = "vfat"; + mountpoint = "/boot"; + mountOptions = [ "umask=0077" ]; + }; + }; + + luks = { + label = "cryptroot"; + size = "100%"; + content = { + type = "luks"; + name = "cryptroot"; + settings = { + allowDiscards = true; + }; + content = { + type = "zfs"; + pool = "rpool"; + }; + }; + }; + + }; + }; + }; + + zpool.rpool = { + type = "zpool"; + + options = { + ashift = "12"; + autotrim = "on"; + }; + + rootFsOptions = { + acltype = "posixacl"; + atime = "off"; + compression = "zstd"; + dnodesize = "auto"; + mountpoint = "none"; + normalization = "formD"; + xattr = "sa"; + }; + + datasets = { + root = { + type = "zfs_fs"; + options.mountpoint = "none"; + }; + + "root/nixos" = { + type = "zfs_fs"; + mountpoint = "/"; + options = { + canmount = "noauto"; + mountpoint = "legacy"; + }; + postCreateHook = "zfs snapshot rpool/root/nixos@blank"; + }; + + home = { + type = "zfs_fs"; + mountpoint = "/home"; + options.mountpoint = "legacy"; + }; + + nix = { + type = "zfs_fs"; + mountpoint = "/nix"; + options.mountpoint = "legacy"; + }; + + persist = { + type = "zfs_fs"; + mountpoint = "/persist"; + options.mountpoint = "legacy"; + }; + + var = { + type = "zfs_fs"; + options.mountpoint = "none"; + }; + + "var/log" = { + type = "zfs_fs"; + mountpoint = "/var/log"; + options.mountpoint = "legacy"; + }; + + "var/lib" = { + type = "zfs_fs"; + mountpoint = "/var/lib"; + options.mountpoint = "legacy"; + }; + + reserved = { + type = "zfs_volume"; + size = "1G"; + }; + }; + }; + }; +} diff --git a/hosts/hermes/mail-password-hash/love@billenius.com b/hosts/hermes/mail-password-hash/love@billenius.com new file mode 100644 index 0000000..93cb115 --- /dev/null +++ b/hosts/hermes/mail-password-hash/love@billenius.com @@ -0,0 +1 @@ +$y$j9T$JkGgFVlME8sM9iB7piz95.$oRbUxpuVQBXUlTjDREJq2cNdUGR65ADUbZ7cbAje9/A diff --git a/hosts/hermes/mail.nix b/hosts/hermes/mail.nix new file mode 100644 index 0000000..b2b24ad --- /dev/null +++ b/hosts/hermes/mail.nix @@ -0,0 +1,24 @@ +{ config, ... }: +{ + security.acme.acceptTerms = true; + networking.firewall.allowedTCPPorts = [ 80 ]; + services.nginx.virtualHosts.${config.mailserver.fqdn}.enableACME = true; + + mailserver = { + enable = true; + stateVersion = 4; + fqdn = "mail.billenius.com"; + domains = [ "billenius.com" ]; + + x509.useACMEHost = config.mailserver.fqdn; + + # A list of all login accounts. To create the password hashes, use + # nix-shell -p mkpasswd --run 'mkpasswd -s' + accounts = { + "love@billenius.com" = { + hashedPasswordFile = ./mail-password-hash/love@billenius.com; + aliases = [ "postmaster@billenius.com" ]; + }; + }; + }; +} diff --git a/hosts/hermes/roundcube.nix b/hosts/hermes/roundcube.nix new file mode 100644 index 0000000..9ec9074 --- /dev/null +++ b/hosts/hermes/roundcube.nix @@ -0,0 +1,46 @@ +{ + config, + pkgs, + ... +}: +{ + services.roundcube = { + enable = true; + hostName = "mail.billenius.com"; + package = pkgs.roundcube.withPlugins ( + plugins: with plugins; [ + persistent_login + ] + ); + plugins = [ + "persistent_login" + "managesieve" # built-in + ]; + dicts = with pkgs.aspellDicts; [ + # https://search.nixos.org/packages?query=aspellDicts + en + sv + ]; + maxAttachmentSize = config.mailserver.messageSizeLimit / 1024 / 1024; + extraConfig = '' + $config['imap_host'] = "ssl://${config.mailserver.fqdn}"; + $config['smtp_host'] = "ssl://${config.mailserver.fqdn}"; + $config['smtp_user'] = "%u"; + $config['smtp_pass'] = "%p"; + + $config['managesieve_host'] = "tls://${config.mailserver.fqdn}"; + $config['managesieve_port'] = 4190; + $config['managesieve_usetls'] = true; + ''; + }; + + services.nginx.virtualHosts.${config.services.roundcube.hostName} = { + enableACME = true; + forceSSL = true; + }; + + networking.firewall.allowedTCPPorts = [ + 80 + 443 + ]; +}