158 lines
5.7 KiB
Nix
158 lines
5.7 KiB
Nix
{
|
|
config,
|
|
pkgs,
|
|
lib,
|
|
...
|
|
}: let
|
|
choose = paths: lib.findFirst builtins.pathExists null paths;
|
|
# Read secrets from sops-managed files and trim trailing newlines so the
|
|
# generated stalwart config contains the actual secret values (not the
|
|
# literal "$FOO" placeholders). Using builtins.readFile here ensures the
|
|
# values are placed into the TOML at build time.
|
|
adminPassword = builtins.replaceStrings ["\n"] [""] (builtins.readFile config.sops.secrets."admin-password".path);
|
|
boardPassword = builtins.replaceStrings ["\n"] [""] (builtins.readFile config.sops.secrets."board-member-password".path);
|
|
cloudflareUsername = builtins.replaceStrings ["\n"] [""] (builtins.readFile config.sops.secrets."cloudflare-username".path);
|
|
cloudflareToken = builtins.replaceStrings ["\n"] [""] (builtins.readFile config.sops.secrets."cloudflare-dns-token".path);
|
|
in {
|
|
options.local = {
|
|
hostname = lib.mkOption {
|
|
type = lib.types.str;
|
|
default = "nixos-default";
|
|
description = "System hostname";
|
|
};
|
|
username = lib.mkOption {
|
|
type = lib.types.str;
|
|
default = "user";
|
|
description = "Primary user username";
|
|
};
|
|
userDescription = lib.mkOption {
|
|
type = lib.types.str;
|
|
default = "NixOS User";
|
|
description = "Primary user description";
|
|
};
|
|
address = lib.mkOption {
|
|
type = lib.types.str;
|
|
default = "10.1.1.100";
|
|
description = "Static IP address";
|
|
};
|
|
};
|
|
|
|
imports = lib.filter (x: x != null) [
|
|
(choose [./modules/desktop-manager/sway_greetd_homemanager.nix ../desktop-manager/sway_greetd_homemanager.nix])
|
|
(choose [./modules/local/hostname_username.nix ../local/hostname_username.nix])
|
|
(choose [./modules/local/networking_local.nix ../local/networking_local.nix])
|
|
(choose [./modules/bootloader/seabios-assigned-proxmox-at-birth.nix ../bootloader/seabios-assigned-proxmox-at-birth.nix])
|
|
(choose [./modules/lix-default.nix ../lix-default.nix])
|
|
(choose [./modules/secrets-config/sops-the-blank-system.nix ../secrets-config/sops-the-blank-system.nix])
|
|
(choose [./modules/toolsets/grafana_metric.nix ../toolsets/grafana_metric.nix])
|
|
(choose [./modules/secrets-config/sops-mail.nix ../secrets-config/sops-mail.nix])
|
|
];
|
|
|
|
config = {
|
|
# Create /etc/stalwart secret files so the generated TOML can reference them
|
|
environment.etc = {
|
|
"stalwart/mail-pw1".text = boardPassword; # principal password (board)
|
|
"stalwart/mail-pw1".mode = "0777";
|
|
"stalwart/admin-pw".text = adminPassword; # admin fallback password
|
|
"stalwart/admin-pw".mode = "0777";
|
|
"stalwart/acme-secret".text = cloudflareToken; # API token for ACME (Cloudflare)
|
|
"stalwart/acme-secret".mode = "0777";
|
|
"stalwart/cloudflare-username".text = cloudflareUsername; # contact email for ACME
|
|
"stalwart/cloudflare-username".mode = "0777";
|
|
};
|
|
|
|
systemd.tmpfiles.rules = [
|
|
# z = create/modify file or directory, set mode and owner
|
|
"z /etc/stalwart 0555 root root - -"
|
|
];
|
|
|
|
# Enable Tailscale for remote access to Traefik dashboard and configuration
|
|
services.tailscale.enable = true;
|
|
|
|
local.hostname = "nixos-mailserver";
|
|
local.username = "mailprg";
|
|
local.userDescription = "NixOS PRG Mailing Service";
|
|
local.address = "10.1.1.15";
|
|
system.stateVersion = "25.11";
|
|
|
|
services.stalwart-mail = {
|
|
enable = true;
|
|
openFirewall = true;
|
|
settings = {
|
|
server = {
|
|
hostname = "mail.prg-radio.org";
|
|
tls = {
|
|
enable = true;
|
|
implicit = true;
|
|
};
|
|
listener = {
|
|
smtp = {
|
|
protocol = "smtp";
|
|
bind = "[::]:25";
|
|
};
|
|
submissions = {
|
|
bind = "[::]:465";
|
|
protocol = "smtp";
|
|
tls.implicit = true;
|
|
};
|
|
imaps = {
|
|
bind = "[::]:993";
|
|
protocol = "imap";
|
|
tls.implicit = true;
|
|
};
|
|
jmap = {
|
|
bind = "[::]:8080";
|
|
url = "https://mail.prg-radio.org";
|
|
protocol = "http";
|
|
};
|
|
management = {
|
|
bind = ["127.0.0.1:8080" "[::]:8081"];
|
|
protocol = "http";
|
|
};
|
|
};
|
|
};
|
|
lookup.default = {
|
|
hostname = "mail.prg-radio.org";
|
|
domain = "prg-radio.org";
|
|
};
|
|
acme."letsencrypt" = {
|
|
directory = "https://acme-v02.api.letsencrypt.org/directory";
|
|
challenge = "dns-01";
|
|
# reference the contact and secret via files under /etc/stalwart
|
|
contact = "%{file:/etc/stalwart/cloudflare-username}%";
|
|
domains = ["prg-radio.org" "mail.prg-radio.org"];
|
|
provider = "cloudflare";
|
|
secret = "%{file:/etc/stalwart/acme-secret}%";
|
|
};
|
|
session.auth = {
|
|
mechanisms = ["plain"];
|
|
directory = "in-memory";
|
|
};
|
|
storage.directory = "in-memory";
|
|
session.rcpt.directory = "in-memory";
|
|
directory."imap".lookup.domains = ["prg-radio.org"];
|
|
directory."in-memory" = {
|
|
type = "memory";
|
|
principals = [
|
|
{
|
|
class = "individual";
|
|
name = "Polyteknisk Radiogruppe Board Member";
|
|
secret = "%{file:/etc/stalwart/mail-pw1}%";
|
|
email = ["board@prg-radio.org"];
|
|
}
|
|
{
|
|
class = "individual";
|
|
name = "postmaster";
|
|
secret = "%{file:/etc/stalwart/mail-pw1}%";
|
|
email = ["postmaster@prg-radio.org"];
|
|
}
|
|
];
|
|
};
|
|
authentication.fallback-admin = {
|
|
user = "admin";
|
|
secret = "%{file:/etc/stalwart/admin-pw}%";
|
|
};
|
|
};
|
|
};
|
|
};
|
|
}
|