From 9ccabedbb222223f32df6389fb0dc4463878c771 Mon Sep 17 00:00:00 2001 From: "Lennart J. Kurzweg (Nx2)" Date: Fri, 24 Apr 2026 19:58:21 +0200 Subject: [PATCH] nxcaldav --- configuration.nix | 9 ++- sops-secrets.yaml | 18 ++++- system-modules/networking.nix | 2 + system-modules/nx2site.nix | 24 +++--- system-modules/nx2site/dyn_dns.nix | 6 +- system-modules/nx2site/imap.nix | 68 ++++++++++++++++ system-modules/nx2site/maddy.nix | 45 +++++++++++ system-modules/nx2site/nxcaldav.nix | 118 +++++++++++++++++++++++++++- system-modules/nx2site/proxy.nix | 39 ++++++--- system-modules/nx2site/smtp.nix | 60 ++++++++++++++ system-modules/nx2site/vmail.nix | 17 ++++ system-modules/simple-postgres.nix | 2 +- 12 files changed, 376 insertions(+), 32 deletions(-) create mode 100644 system-modules/nx2site/imap.nix create mode 100644 system-modules/nx2site/maddy.nix create mode 100644 system-modules/nx2site/smtp.nix create mode 100644 system-modules/nx2site/vmail.nix diff --git a/configuration.nix b/configuration.nix index e8f1590..592a0b2 100644 --- a/configuration.nix +++ b/configuration.nix @@ -49,9 +49,15 @@ ./system-modules/hugo.nix ./system-modules/postgres.nix ./system-modules/nx2site/proxy.nix + + # ./system-modules/nx2site/smtp.nix + # ./system-modules/nx2site/imap.nix + # ./system-modules/nx2site/vmail.nix + ./system-modules/nx2site/maddy.nix + ./system-modules/nx2site/audiobookshelf.nix # ./system-modules/nx2site/baikal.nix - # ./system-modules/nx2site/nxcaldav.nix + ./system-modules/nx2site/nxcaldav.nix ./system-modules/nx2site/copyparty.nix ./system-modules/nx2site/gitea.nix ./system-modules/nx2site/open-web-calendar.nix @@ -61,7 +67,6 @@ ./system-modules/calendar/publish.nix ./system-modules/calendar/lec.nix # ./system-modules/calendar/lr.nix - ./system-modules/calendar/dicos.nix ] else [ ]); environment.systemPackages = import ./system-modules/base-packages.nix pkgs; diff --git a/sops-secrets.yaml b/sops-secrets.yaml index c814470..165b233 100644 --- a/sops-secrets.yaml +++ b/sops-secrets.yaml @@ -42,6 +42,18 @@ nx2site: copyparty: user-password: nx2: ENC[AES256_GCM,data:55yxXcN1eKvfpjWySw54r2dMlSg9,iv:w9rGUSUkumysj4ti6XqUm+sL0wwU6sgObfCefwfS5Mo=,tag:2TEDwHqU4RzOZ9+oiffGlg==,type:str] + dovecot: ENC[AES256_GCM,data:2pCvTWe4UZmyQNxPZpyfeII8+gezmXkNub0q5tMCzg==,iv:MTN1OU9jEtbl841YBcAGNptwu3kbyBeyIQwUme3/IOM=,tag:qYUsre28bhEDHxN1OLLBIQ==,type:str] + maddy: + nxcaldav_password: ENC[AES256_GCM,data:cpq6OJDPw2moea1LBfisVNIW9qmJeqc=,iv:h2EN4ButO+nIhx8oIATbtRFYrp6bj05vSQ2vJeqDp94=,tag:WEuC3bJ5pGp1VWfZrL7XUg==,type:str] + lennart_password: ENC[AES256_GCM,data:a2lTi3j24EowghFITkKd+6UMB/E=,iv:gja6miTo3bTg86nWNeaGwpMgNccX5+HJINI2tgHJBrg=,tag:ScEKrHAb3yeqg3ynLpHFkA==,type:str] + daniel_password: ENC[AES256_GCM,data:AdA+cN++Z1rAm8CbuP60k2/Gu2bJ,iv:yGMbo4s6oUkh5aWJDSiCTeey/tkjKkAbzYRDjMzEnYk=,tag:XjL01czFJ5AHqieVshlMPA==,type:str] + nxcaldav: + lennart_password: ENC[AES256_GCM,data:77nhdaJ32JnYY5xwAEQ4RinKFMo=,iv:xFXTxaIqazsLOTv+6rpNJf6+mrkG84hEFRCiT7CnZt4=,tag:DWb59tiXN+EFOJxbDdhoBw==,type:str] + daniel_password: ENC[AES256_GCM,data:BIvizxlUP/bOI/KluXKvXMjKHR3O,iv:GCcuhrCbEky1uzjLxcMEZ2kIrZQXpoAv2OhfOm+HMtk=,tag:iaesITsIsI3E7qrKDDzU+Q==,type:str] + diane_password: ENC[AES256_GCM,data:Po8J6QZx+6LMxFi4vJtDuIJERshfBw==,iv:mxROdTvfeQnzyS97KI+5aq9NcBloF1AwbKUDc/AU+kw=,tag:fZyQFIt9AG54yyDOaMK2TQ==,type:str] + georg_password: ENC[AES256_GCM,data:HD/DtGfrS2KqScF8My6q/lyucec=,iv:d99SO2/H/fSKu4G+xsFHbH5rAaG2AttBejM6Rlgx/D8=,tag:gxlQGttzVNLE/sBqf5nZpQ==,type:str] + tessa_password: ENC[AES256_GCM,data:qD4eivgDKG4Du892gr/83KPw8URgVw==,iv:TZTiXZzNmDmZ+jj5nvlr7Zs+Re0a53SxLjAypTsudIA=,tag:XclXS4ooziPRpl+0oehx+Q==,type:str] + shared_password: ENC[AES256_GCM,data:W8MUZdqJAzRtcIAZ7PFOs524AVU=,iv:n3hXLl5uByE5c2MEl81fd4LOO+jlUbapavQfq9uMxyQ=,tag:PDbTbnXrveLgUgddpKoEJQ==,type:str] USERTrust: ECC: ENC[AES256_GCM,data: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,iv:GS5GMpbxeweqwjUvOzqg59xBOzNZqrL5t7RjsFjpucM=,tag:j0MaMw71fnRHxeydlqAaww==,type:str] RSA: ENC[AES256_GCM,data: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,iv:NJkjWL5kMHET68oR5Xp22kvkThXIp7WxRVajmTfsB5M=,tag:NSXeRItMKlOQYP4QtzMKIg==,type:str] @@ -118,8 +130,8 @@ sops: MkZGai9DZ3ZzT0I2MmMwRzVkcFhXdlEKLbM/9kCpiXLW8Me4MDq+JFifG7FhwPZS 5t4zNtuLttY3NUwT9KK4g4P+Yl10oNsjcCbGNYTxlIARFEU+X6zwUQ== -----END AGE ENCRYPTED FILE----- - lastmodified: "2025-09-07T21:03:20Z" - mac: ENC[AES256_GCM,data:x8eIqQQGxtB5ukScesN1Lf4cFicTOi3VSOr/hFxKzccgwW7HLLEqwjai6e67KUFC2otaN9TR7ft0tUsTVwWRVRCHnpEoQ5KshLHy2zsk+CmPIpWTLCZJBpe154z3rRLlc10DCM7yhqArzepw0HgE4j1knADqLVwC7e0k+o/OmE8=,iv:uXeIv19J3LmYg7gtA2SGUSoMe9uccrvvztlDFSSs1V8=,tag:YTJpZdw1K+7//EARR+MviA==,type:str] + lastmodified: "2026-04-22T15:43:57Z" + mac: ENC[AES256_GCM,data:fgOVEf1z1vKNAyDO/dYpprwFoR4Z/DJkEW02O6mOcmGLa+ipCOjasrC9k8es6CXMqq6HRqSgKO7VLXeVUpKc+99PWEGuhgYzjfQ6sxUFwj6+YLJrkNoiDf6YIid/yY0+H/XirlYiybyg2bCZdN153T556uWR2Mke1C+UkSdmVq4=,iv:BEl/oijLXI7qyjq/H4rL5aQqtd3PmfimHMFS/dF0sxI=,tag:iGWE/CpcS56bFI7cgN86Hg==,type:str] pgp: - created_at: "2025-10-06T11:16:18Z" enc: |- @@ -133,4 +145,4 @@ sops: -----END PGP MESSAGE----- fp: 22FB2CC03DC5292AB81CF67D0AF27B383170E634 unencrypted_suffix: _unencrypted - version: 3.10.2 + version: 3.12.1 diff --git a/system-modules/networking.nix b/system-modules/networking.nix index c8afe68..96a3927 100644 --- a/system-modules/networking.nix +++ b/system-modules/networking.nix @@ -15,6 +15,8 @@ 443 8000 8080 + (pkgs.lib.mkIf config.services.postfix.enable 587) + (pkgs.lib.mkIf config.services.dovecot2.enable 993) ]; }; } diff --git a/system-modules/nx2site.nix b/system-modules/nx2site.nix index 795994b..8586e19 100644 --- a/system-modules/nx2site.nix +++ b/system-modules/nx2site.nix @@ -40,13 +40,15 @@ let dns-user = "cloudflare"; in sub = "fc861353142bc05d5dbad1799178e6a1"; sub6 = "b8082b7afe9e80971fc9f9dda16ec284"; ssh = "c0f14f17f32d6595c202f041dd836eb3"; - ssh6 = "f1ecb2d9d0522d4eec06437688ca76da"; + ssh6 = "0067f396b3efb21e12f63e0c50643161"; dev = "80e76834acc9243696d9763759b22147"; + mail = "d62a0dc01614b9f8f2b469219788fe0f"; + mail6 = "f1ecb2d9d0522d4eec06437688ca76da"; }; passord-file-path = config.sops.secrets."nx2site/cloudflare/global-api-key".path; in pkgs.writers.writePython3Bin "dyn_dns" { libraries = with pkgs.python3Packages; [ requests ]; - flakeIgnore = [ "E302" "E305" "E226" "E501" "E261" ]; + flakeIgnore = [ "E302" "E305" "E226" "E501" "E261" "E241" ]; } /* python */ '' import requests import subprocess @@ -55,7 +57,7 @@ from time import sleep def get_public_ip(ipv6: bool = False) -> str: return subprocess.run(['${pkgs.curl}/bin/curl', '-s', '-6' if ipv6 else '-4', 'https://ifconfig.me'], capture_output=True, text=True).stdout.strip() -def update_record(record_id: str, record_name: str, ip: str, type: str, proxied: bool, pw: str) -> None: +def update_record(record_id: str, record_name: str, ip: str, type: str, proxied: bool, pw: str) -> requests.Response: sleep(5) return requests.patch( f'https://api.cloudflare.com/client/v4/zones/${zone_id}/dns_records/{record_id}', @@ -85,14 +87,16 @@ def main(): # Perform DNS updates # https://developers.cloudflare.com/api/operations/dns-records-for-a-zone-update-dns-record - print(f"${hyper.domain}: {update_record(record_id="${record_id.base}", record_name="${hyper.domain}", ip=my_ip, type="A", proxied=True, pw=pw).status_code}", end=", ") - print(f"*.${hyper.domain}: {update_record(record_id="${record_id.sub}", record_name="*.${hyper.domain}", ip=my_ip, type="A", proxied=True, pw=pw).status_code}", end=", ") - print(f"ssh.${hyper.domain}: {update_record(record_id="${record_id.ssh}", record_name="ssh.${hyper.domain}", ip=my_ip, type="A", proxied=False, pw=pw).status_code}", end=", ") - print(f"dev.${hyper.domain}: {update_record(record_id="${record_id.dev}", record_name="dev.${hyper.domain}", ip=my_ip, type="A", proxied=False, pw=pw).status_code}", end=", ") + print(f"${hyper.domain}: {update_record(record_id="${record_id.base}", record_name="${hyper.domain}", ip=my_ip, type="A", proxied=True, pw=pw).status_code}") + print(f"*.${hyper.domain}: {update_record(record_id="${record_id.sub}", record_name="*.${hyper.domain}", ip=my_ip, type="A", proxied=True, pw=pw).status_code}") + print(f"ssh.${hyper.domain}: {update_record(record_id="${record_id.ssh}", record_name="ssh.${hyper.domain}", ip=my_ip, type="A", proxied=False, pw=pw).status_code}") + print(f"dev.${hyper.domain}: {update_record(record_id="${record_id.dev}", record_name="dev.${hyper.domain}", ip=my_ip, type="A", proxied=False, pw=pw).status_code}") + print(f"mail.${hyper.domain}: {update_record(record_id="${record_id.dev}", record_name="mail.${hyper.domain}", ip=my_ip, type="A", proxied=False, pw=pw).status_code}") - print(f"${hyper.domain}: {update_record(record_id="${record_id.base6}", record_name="${hyper.domain}", ip=my_ip6, type="AAAA", proxied=True, pw=pw).status_code}", end=", ") - print(f"*.${hyper.domain}: {update_record(record_id="${record_id.sub6}", record_name="*.${hyper.domain}", ip=my_ip6, type="AAAA", proxied=True, pw=pw).status_code}", end=", ") - print(f"ssh.${hyper.domain}: {update_record(record_id="${record_id.ssh6}", record_name="ssh.${hyper.domain}", ip=my_ip6, type="AAAA", proxied=False, pw=pw).status_code}", end="") + print(f"${hyper.domain}: {update_record(record_id="${record_id.base6}", record_name="${hyper.domain}", ip=my_ip6, type="AAAA", proxied=True, pw=pw).status_code}") + print(f"*.${hyper.domain}: {update_record(record_id="${record_id.sub6}", record_name="*.${hyper.domain}", ip=my_ip6, type="AAAA", proxied=True, pw=pw).status_code}") + print(f"ssh.${hyper.domain}: {update_record(record_id="${record_id.ssh6}", record_name="ssh.${hyper.domain}", ip=my_ip6, type="AAAA", proxied=False, pw=pw).status_code}") + print(f"mail.${hyper.domain}: {update_record(record_id="${record_id.ssh6}", record_name="mail.${hyper.domain}", ip=my_ip6, type="AAAA", proxied=False, pw=pw).status_code}") if __name__ == "__main__": main() diff --git a/system-modules/nx2site/dyn_dns.nix b/system-modules/nx2site/dyn_dns.nix index f245bab..1571a32 100644 --- a/system-modules/nx2site/dyn_dns.nix +++ b/system-modules/nx2site/dyn_dns.nix @@ -1,5 +1,5 @@ -{ pkgs, ... }@all: with all; -{ +# THIS IS NOT USED +{ pkgs, ... }@all: with all; { sops.secrets = { # "nx2site/namecheap.pw" = { }; # "nx2site/cloudflare/api-token-dns-edit" = { }; @@ -16,6 +16,8 @@ "${hyper.domain}" "*.${hyper.domain}" "ssh.${hyper.domain}" + "mail.${hyper.domain}" + "dev.${hyper.domain}" ]; proxied = true; apiTokenFile = config.sops.secrets."nx2site/cloudflare/global-api-key-env".path; diff --git a/system-modules/nx2site/imap.nix b/system-modules/nx2site/imap.nix new file mode 100644 index 0000000..fd1b95b --- /dev/null +++ b/system-modules/nx2site/imap.nix @@ -0,0 +1,68 @@ +{ config, pkgs, ... }@all: with all; { + sops.secrets = { + "nx2site/dovecot" = { + owner = "dovecot2"; + group = "dovecot2"; + mode = "600"; + }; + }; + services.dovecot2 = { + enable = true; + enablePAM = false; # independen from linux users + enableImap = true; + enableLmtp = true; + extraConfig = '' + # force to use full user name plus domain name + # for disambiguation + auth_username_format = %Lu + + # Authentication configuration: + auth_mechanisms = plain + passdb { + driver = passwd-file + args = ${config.sops.secrets."nx2site/dovecot".path} + } + + # for vitual users: + userdb { + driver = static + # the full e-mail address inside passwd-file is the username (%u) + # user@example.com + # %d for domain_name %n for user_name + args = uid=vmail gid=vmail username_format=%u home=/var/spool/mail/vmail/%d/%n + } + # for connecting with postfix + service lmtp { + unix_listener /var/spool/postfix/dovecot-lmtp { + mode = 0600 + user = postfix + group = postfix + } + } + service auth { + unix_listener /var/spool/postfix/auth { + mode = 0600 + user = postfix + group = postfix + } + } + ''; + createMailUser = true; + mailUser = "vmail"; + mailGroup = "vmail"; + mailLocation = "maildir:~/Maildir"; + mailboxes = { # RFC standart + All = { auto = "create"; autoexpunge = null; specialUse = "All"; }; + Archive = { auto = "create"; autoexpunge = null; specialUse = "Archive"; }; + Drafts = { auto = "create"; autoexpunge = null; specialUse = "Drafts"; }; + Flagged = { auto = "create"; autoexpunge = null; specialUse = "Flagged"; }; + Junk = { auto = "create"; autoexpunge = "60d"; specialUse = "Junk"; }; + Sent = { auto = "create"; autoexpunge = null; specialUse = "Sent"; }; + Trash = { auto = "create"; autoexpunge = "60d"; specialUse = "Trash"; }; + }; + + sslServerCert = "/var/lib/acme/${hyper.domain}/fullchain.pem"; + sslServerKey = "/var/lib/acme/${hyper.domain}/key.pem"; + sslCACert = "/var/lib/acme/${hyper.domain}/chain.pem"; + }; +} diff --git a/system-modules/nx2site/maddy.nix b/system-modules/nx2site/maddy.nix new file mode 100644 index 0000000..b69c3a6 --- /dev/null +++ b/system-modules/nx2site/maddy.nix @@ -0,0 +1,45 @@ +{ config, pkgs, ... }@all: with all; { + sops.secrets = { + "nx2site/maddy/nxcaldav_password" = { owner = "maddy"; group = "maddy"; mode = "600"; }; + "nx2site/maddy/lennart_password" = { owner = "maddy"; group = "maddy"; mode = "600"; }; + "nx2site/maddy/daniel_password" = { owner = "maddy"; group = "maddy"; mode = "600"; }; + }; + users.users."maddy" = { + extraGroups = [ "acme" "nginx" ]; + }; + services.maddy = { + enable = true; + primaryDomain = hyper.domain; + user = "maddy"; + group = "maddy"; + hostname = "mail.${hyper.domain}"; + ensureAccounts = [ + "nxcaldav@${hyper.domain}" + "lennart@${hyper.domain}" + "daniel@${hyper.domain}" + ]; + ensureCredentials = { + "nxcaldav@${hyper.domain}".passwordFile = config.sops.secrets."nx2site/maddy/nxcaldav_password".path; + "lennart@${hyper.domain}".passwordFile = config.sops.secrets."nx2site/maddy/lennart_password".path; + "daniel@${hyper.domain}".passwordFile = config.sops.secrets."nx2site/maddy/daniel_password".path; + }; + + openFirewall = true; + tls = { + loader = "file"; + certificates = [{ + keyPath = "/var/lib/acme/nx2.site/key.pem"; + certPath = "/var/lib/acme/nx2.site/cert.pem"; + }]; + }; + # Enable TLS listeners. Configuring this via the module is not yet + # implemented, see https://github.com/NixOS/nixpkgs/pull/153372 + config = builtins.replaceStrings [ + "imap tcp://0.0.0.0:143" + "submission tcp://0.0.0.0:587" + ] [ + "imap tls://0.0.0.0:993 tcp://0.0.0.0:143" + "submission tls://0.0.0.0:465 tcp://0.0.0.0:587" + ] options.services.maddy.config.default; + }; +} diff --git a/system-modules/nx2site/nxcaldav.nix b/system-modules/nx2site/nxcaldav.nix index 477cd83..676b96d 100644 --- a/system-modules/nx2site/nxcaldav.nix +++ b/system-modules/nx2site/nxcaldav.nix @@ -1 +1,117 @@ -{ pkgs, ... }@all: with all; { } +{ pkgs, ... }@all: with all; let + x = rec { version = "0.0.11"; + user = "nxcaldav"; + nxcsrc = pkgs.fetchFromGitea { + domain = "git.${hyper.domain}"; + owner = "nx2"; + repo = "NxCalDav"; + rev = version; + hash = "sha256-Hk27BQCBtdRQ1aSHVEQ1EVjPrsC2jOUPDT4yuU9OCXQ="; + }; + nxc = pkgs.buildGoModule { + pname = "NxCalDav"; + inherit version; + src = nxcsrc; + vendorHash = "sha256-prstYDJuwS5E5uRwUkX0M+QdnIaQ0QewKe8HaoZ0Db4="; + }; + nxc_helpers = pkgs.python3Packages.buildPythonApplication { + inherit version; + format = "other"; + pname = "nxc_helpers"; + src = nxcsrc; + propagatedBuildInputs = with pkgs.python313Packages; [ pyyaml psycopg2 ]; + installPhase = '' + sed -i "15s|.*| parser.add_argument('--config', default='${cfg}', help='Path to config.yaml')|" ./export_events.py + sed -i "17s|.*| parser.add_argument('--config', default='${cfg}', help='Path to config.yaml')|" ./import_events.py + install -Dm755 "./export_events.py" "$out/bin/nxc_export" + install -Dm755 "./import_events.py" "$out/bin/nxc_import" + ''; + }; + cfg = (pkgs.formats.yaml { }).generate "nxcaldav-config.yaml" { + server = { + bind_address = "0.0.0.0:14243"; + public_url = "http://nxc.${hyper.domain}/"; + redaction_text = "[-]"; + default_class = "CONFIDENTIAL"; + }; + database.url = "postgres://nxcaldav@localhost:5432/nxcaldav?sslmode=disable"; + users = let dfu = name: { + name = name; + password_cmd = ''cat ${config.sops.secrets."nx2site/nxcaldav/${name}_password".path}''; + groups = [ "family" ]; + }; in [ + (dfu "lennart") + (dfu "daniel") + (dfu "diane") + (dfu "georg") + (dfu "tessa") + (dfu "shared") + ]; + calendars = [ + { owner = "lennart"; color = "#dddddd"; id = "preservation"; } + { owner = "lennart"; color = "#dd2222"; id = "effort"; } + { owner = "lennart"; color = "#2222dd"; id = "experience"; } + { owner = "lennart"; color = "#22aa22"; id = "leisure"; } + { id = "family"; + owner = "shared"; + color = "#dddd22"; + access = [ + { group = "family"; mode = "read-write"; } + ]; + } + ]; + address_books = [ + { owner = "lennart"; id = "Others"; } + { owner = "lennart"; id = "TUDa"; } + { owner = "lennart"; id = "HSMW"; } + { owner = "lennart"; id = "CWG"; } + { owner = "lennart"; id = "Handball"; } + { id = "Family & Freinds"; + owner = "shared"; + access = [ + { group = "family"; mode = "read-write"; } + ]; + } + ]; + aggregates = [ + { id = "lennart-aggregate"; + owner = "shared"; + sources = [ "preservation" "effort" "experience" "leisure" ]; + access = [ + { group = "family" ; mode = "read-only"; } + { ics = "future-only"; } + ]; + } + ]; + }; +}; in with x; { + sops.secrets = let ss = { owner = user; group = user; mode = "600"; }; in { + "nx2site/nxcaldav/lennart_password" = ss; + "nx2site/nxcaldav/daniel_password" = ss; + "nx2site/nxcaldav/diane_password" = ss; + "nx2site/nxcaldav/georg_password" = ss; + "nx2site/nxcaldav/tessa_password" = ss; + "nx2site/nxcaldav/shared_password" = ss; + }; + users = { + groups."${user}" = {}; + users = { + "${hyper.user}".extraGroups = [ user ]; + "${user}" = { + isSystemUser = true; + isNormalUser = false; + group = user; + }; + }; + }; + environment.systemPackages = [ nxc_helpers ]; + systemd.services."nxcaldav" = { + enable = true; + path = [ pkgs.bash pkgs.coreutils ]; + serviceConfig = { + User = user; + Group = user; + ExecStart = ''${nxc}/bin/nxcaldav -c ${cfg}''; + }; + }; +} diff --git a/system-modules/nx2site/proxy.nix b/system-modules/nx2site/proxy.nix index a7516ab..38e2caa 100644 --- a/system-modules/nx2site/proxy.nix +++ b/system-modules/nx2site/proxy.nix @@ -1,5 +1,4 @@ -{ pkgs, ...}@all: with all; -{ +{ pkgs, ...}@all: with all; { sops.secrets = { "nx2site/sslCertificate.pem" = { owner = config.services.nginx.user; }; "nx2site/sslCertificateKey.pem" = { owner = config.services.nginx.user; }; @@ -14,19 +13,25 @@ }; certs = { "${hyper.domain}" = { - extraDomainNames = builtins.map (subd: "${subd}.${hyper.domain}") [ "sync" ]; + extraDomainNames = builtins.map (subd: "${subd}.${hyper.domain}") [ + "sync" + "mail" + ]; }; }; }; - users.users."nginx" = { - extraGroups = [ "nginx" "acme" "copyparty" ]; - useDefaultShell = false; - linger = true; - home = "/var/nginx/"; - homeMode = "770"; - createHome = true; - isSystemUser = true; - isNormalUser = false; + users.users = { + "nginx" = { + extraGroups = [ "nginx" "acme" "copyparty" ]; + useDefaultShell = false; + linger = true; + home = "/var/nginx/"; + homeMode = "770"; + createHome = true; + isSystemUser = true; + isNormalUser = false; + }; + "acme".extraGroups = [ "nginx" "acme" "hugo" ]; }; systemd.services.nginx.serviceConfig.ProtectHome = "read-only"; services.nginx = let @@ -101,8 +106,16 @@ "~ ^(/gpg)$".return = "301 /cards/gpg"; "~ ^(/contact)$".return = "301 /cards/contact"; "~ ^(/ba)$".return = "301 /BA.pdf"; + "~ ^(/schedule)$".return = "301 https://owc.${hyper.domain}/calendar.html?specification_url=https://${hyper.domain}/owc-schedule.json?"; }; }; + "mail.${hyper.domain}" = { + listen = [ + { addr = "0.0.0.0"; port = 80; } + { addr = "[::0]"; port = 80; } + ]; + locations."/.well-known/acme-challenge".root = "/var/lib/acme/acme-challenge"; + }; "matrix.${hyper.domain}" = { listen = dl; locations."~.*".return = "502"; @@ -156,7 +169,7 @@ listen = dl; locations = { "/" = { proxyPass = "http://127.0.0.1:5232"; }; }; }); - "nxc.${hyper.domain}" = lib.mkIf config.services.radicale.enable (vh // { + "nxc.${hyper.domain}" = (vh // { listen = dl; locations = { "/" = { proxyPass = "http://127.0.0.1:14243"; }; }; }); diff --git a/system-modules/nx2site/smtp.nix b/system-modules/nx2site/smtp.nix new file mode 100644 index 0000000..936334d --- /dev/null +++ b/system-modules/nx2site/smtp.nix @@ -0,0 +1,60 @@ +{ pkgs, ... }@all: with all; { + # Postfix: The SMTP server (MTA) + # Handles sending, receiving, and local delivery routing. + services.postfix = { + enable = true; + enableSubmission = true; + enableSubmissions = true; + + # main.cf configuration + settings.main = { + hostname = "mail.${hyper.domain}"; + domain = hyper.domain; + + # Allow local services (like CalDAV) to send mail without authentication + networks = [ "127.0.0.0/8" "[::1]/128" ]; + # TLS settings - using ACME certs from proxy.nix + smtpd_tls_security_level = "may"; + smtpd_tls_auth_only = "yes"; + smtpd_tls_cert_file = "/var/lib/acme/${hyper.domain}/fullchain.pem"; + smtpd_tls_key_file = "/var/lib/acme/${hyper.domain}/key.pem"; + + # Use Dovecot for authentication (SASL) + smtpd_sasl_type = "dovecot"; + smtpd_sasl_path = "/var/spool/postfix/auth"; + smtpd_sasl_auth_enable = "yes"; + smtpd_sasl_security_options = "noanonymous"; + + # Use Dovecot for delivery (LMTP) + virtual_transport = "lmtp:unix:/var/spool/postfix/dovecot-lmtp"; + virtual_mailbox_domains = [ hyper.domain ]; + mailbox_transport = "lmtp:unix:/var/spool/postfix/dovecot-lmtp"; + + + # Basic relay restrictions + smtpd_recipient_restrictions = [ + "permit_mynetworks" + "permit_sasl_authenticated" + "reject_unauth_destination" + ]; + + # master.cf configuration: Enable submission (port 587) for mail clients + # submission-options = { + # type = "inet"; + # private = false; + # command = "smtpd"; + # args = [ + # "-o smtpd_tls_security_level=encrypt" + # "-o smtpd_sasl_auth_enable=yes" + # "-o smtpd_recipient_restrictions=permit_sasl_authenticated,reject" + # "-o milter_macro_daemon_name=ORIGINATING" + # ]; + # }; + }; + }; + # create socket ala wiki + users.users."postfix" = { + createHome = true; + home = "/var/spool/postfix"; + }; +} diff --git a/system-modules/nx2site/vmail.nix b/system-modules/nx2site/vmail.nix new file mode 100644 index 0000000..eba5cda --- /dev/null +++ b/system-modules/nx2site/vmail.nix @@ -0,0 +1,17 @@ +{ ... }:{ + users = { + groups."vmail" = {}; + users = { + "vmail" = { + isSystemUser = true; + group = "vmail"; + home = "/var/spool/mail/vmail"; + createHome = true; + }; + # Permissions to allow Postfix and Dovecot to read ACME certificates + "postfix".extraGroups = [ "acme" ]; + "dovecot2".extraGroups = [ "acme" ]; + }; + }; +} + diff --git a/system-modules/simple-postgres.nix b/system-modules/simple-postgres.nix index 3eb4670..a70cdba 100644 --- a/system-modules/simple-postgres.nix +++ b/system-modules/simple-postgres.nix @@ -1,5 +1,5 @@ { pkgs, ... }@all: with all; { - services.postgresql = { + services.postgresql = lib.mkIf (!hyper.isServer) { enable = false; ensureUsers = [{ name = "nxcaldav";