5 files changed, 253 insertions, 0 deletions
diff --git a/host/Rory-ovh/services/email/autoconfig.nix b/host/Rory-ovh/services/email/autoconfig.nix
new file mode 100644
index 0000000..5f3bce2
--- /dev/null
+++ b/host/Rory-ovh/services/email/autoconfig.nix
@@ -0,0 +1,18 @@
+{ config, ... }:
+{
+ services.go-autoconfig = {
+ enable = !config.virtualisation.isVmVariant;
+ settings = {
+ service_addr = ":1323";
+ domain = "autoconfig.rory.gay";
+ imap = {
+ server = "rory.gay";
+ port = 993;
+ };
+ smtp = {
+ server = "rory.gay";
+ port = 587;
+ };
+ };
+ };
+}
diff --git a/host/Rory-ovh/services/email/maddy.conf b/host/Rory-ovh/services/email/maddy.conf
new file mode 100644
index 0000000..1d3eb2f
--- /dev/null
+++ b/host/Rory-ovh/services/email/maddy.conf
@@ -0,0 +1,124 @@
+
+# Minimal configuration with TLS disabled, adapted from upstream example
+# configuration here https://github.com/foxcpp/maddy/blob/master/maddy.conf
+# Do not use this in production!
+
+auth.pass_table local_authdb {
+ table sql_table {
+ driver sqlite3
+ dsn credentials.db
+ table_name passwords
+ }
+}
+
+storage.imapsql local_mailboxes {
+ driver sqlite3
+ dsn imapsql.db
+}
+
+table.chain local_rewrites {
+ optional_step regexp "(.+)\+(.+)@(.+)" "$1@$3"
+ optional_step static {
+ entry postmaster root@$(primary_domain)
+ }
+ optional_step file /etc/maddy/aliases
+}
+
+msgpipeline local_routing {
+ destination postmaster $(local_domains) {
+ modify {
+ replace_rcpt &local_rewrites
+ }
+ deliver_to &local_mailboxes
+ }
+ default_destination {
+ reject 550 5.1.1 "User doesn't exist"
+ }
+}
+
+smtp tcp://0.0.0.0:25 {
+ limits {
+ all rate 20 1s
+ all concurrency 10
+ }
+ dmarc yes
+ check {
+ require_mx_record
+ dkim
+ spf
+ }
+ source $(local_domains) {
+ reject 501 5.1.8 "Use Submission for outgoing SMTP"
+ }
+ default_source {
+ destination postmaster $(local_domains) {
+ deliver_to &local_routing
+ }
+ default_destination {
+ reject 550 5.1.1 "User doesn't exist"
+ }
+ }
+}
+
+submission tls://0.0.0.0:465 tcp://0.0.0.0:587 {
+ limits {
+ all rate 50 1s
+ }
+ auth &local_authdb
+ source $(local_domains) {
+ check {
+ authorize_sender {
+ prepare_email &local_rewrites
+ user_to_email identity
+ }
+ }
+ destination postmaster $(local_domains) {
+ deliver_to &local_routing
+ }
+ default_destination {
+ modify {
+ dkim $(primary_domain) $(local_domains) default
+ }
+ deliver_to &remote_queue
+ }
+ }
+ default_source {
+ reject 501 5.1.8 "Non-local sender domain"
+ }
+}
+
+target.remote outbound_delivery {
+ limits {
+ destination rate 20 1s
+ destination concurrency 10
+ }
+ mx_auth {
+ dane
+ mtasts {
+ cache fs
+ fs_dir mtasts_cache/
+ }
+ local_policy {
+ min_tls_level encrypted
+ min_mx_level none
+ }
+ }
+}
+
+target.queue remote_queue {
+ target &outbound_delivery
+ autogenerated_msg_domain $(primary_domain)
+ bounce {
+ destination postmaster $(local_domains) {
+ deliver_to &local_routing
+ }
+ default_destination {
+ reject 550 5.0.0 "Refusing to send DSNs to non-local addresses"
+ }
+ }
+}
+
+imap tls://0.0.0.0:993 tcp://0.0.0.0:143 {
+ auth &local_authdb
+ storage &local_mailboxes
+}
\ No newline at end of file
diff --git a/host/Rory-ovh/services/email/maddy.nix b/host/Rory-ovh/services/email/maddy.nix
new file mode 100644
index 0000000..3f1d427
--- /dev/null
+++ b/host/Rory-ovh/services/email/maddy.nix
@@ -0,0 +1,71 @@
+{
+ lib,
+ pkgs,
+ options,
+ config,
+ ...
+}:
+{
+ config = lib.mkIf (!config.virtualisation.isVmVariant) {
+ services.maddy = {
+ enable = true;
+ primaryDomain = "rory.gay";
+ hostname = "mail.rory.gay";
+ ensureAccounts = [
+ "root@rory.gay"
+ ];
+ ensureCredentials = {
+ "root@rory.gay".passwordFile = "/var/lib/maddy/passwd/root";
+ };
+ config = builtins.readFile ./maddy.conf;
+ # builtins.replaceStrings
+ # [
+ # "imap tcp://0.0.0.0:143"
+ # "submission tcp://0.0.0.0:587"
+ # "entry postmaster postmaster@$(primary_domain)"
+ # ]
+ # [
+ # "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"
+ # "entry postmaster root@$(primary_domain)"
+ # ]
+ # options.services.maddy.config.default;
+
+ tls = {
+ loader = "file";
+ certificates = [
+ {
+ # certPath = "/var/lib/acme/mail.rory.gay/fullchain.pem";
+ # keyPath = "/var/lib/acme/mail.rory.gay/key.pem";
+ certPath = "/run/credentials/maddy.service/acme-fullchain.pem";
+ keyPath = "/run/credentials/maddy.service/acme-key.pem";
+ }
+ ];
+ };
+ };
+
+ networking.firewall.allowedTCPPorts = [
+ 25
+ 143
+ 465
+ 587
+ 993
+ ];
+
+ users.users.maddy.extraGroups = [ "nginx" ];
+
+ fileSystems."/var/lib/maddy" = {
+ depends = [ "/" ];
+ device = "/data/maddy";
+ fsType = "none";
+ options = [ "bind" ];
+ };
+
+ systemd.services.maddy.serviceConfig = {
+ LoadCredential = [
+ "acme-fullchain.pem:/var/lib/acme/rory.gay/fullchain.pem"
+ "acme-key.pem:/var/lib/acme/rory.gay/key.pem"
+ ];
+ };
+ };
+}
diff --git a/host/Rory-ovh/services/email/nginx.nix b/host/Rory-ovh/services/email/nginx.nix
new file mode 100644
index 0000000..5b04612
--- /dev/null
+++ b/host/Rory-ovh/services/email/nginx.nix
@@ -0,0 +1,32 @@
+{ config, ... }:
+{
+ services.nginx.virtualHosts = {
+ "mta-sts.rory.gay" = {
+ enableACME = !config.virtualisation.isVmVariant;
+ forceSSL = !config.virtualisation.isVmVariant;
+ locations = {
+ "/.well-known/mta-sts.txt" = {
+ # age 604800
+ return = ''
+ 200 "version: STSv1
+ mode: enforce
+ max_age: 120
+ mx: mail.rory.gay
+ "'';
+ };
+ };
+ };
+ "mail.rory.gay" = {
+ enableACME = !config.virtualisation.isVmVariant;
+ forceSSL = !config.virtualisation.isVmVariant;
+ locations = {
+ "/".return = "200 'OK'";
+ };
+ };
+ "autoconfig.rory.gay" = {
+ enableACME = !config.virtualisation.isVmVariant;
+ forceSSL = !config.virtualisation.isVmVariant;
+ locations."/".proxyPass = "http://localhost:1323";
+ };
+ };
+}
diff --git a/host/Rory-ovh/services/email/root.nix b/host/Rory-ovh/services/email/root.nix
new file mode 100644
index 0000000..7db85d8
--- /dev/null
+++ b/host/Rory-ovh/services/email/root.nix
@@ -0,0 +1,8 @@
+{ ... }:
+{
+ imports = [
+ ./autoconfig.nix
+ ./maddy.nix
+ ./nginx.nix
+ ];
+}
|