zaphyra's git: nixfiles

zaphyra and void's nixfiles

commit b67733a3d04c41bf387cd0922cd95e389294104c
parent 461e8b1c1ba97a48a96592d89975867458031df5
Author: Katja (zaphyra) <git@ctu.cx>
Date: Sat, 24 May 2025 18:01:32 +0200

config/nixos/modules/websites: add `gts.zaphyra.eu` (and enable on host `morio`)
4 files changed, 218 insertions(+), 2 deletions(-)
M
config/nixos/modules/presets/katja/mailServer.nix
|
5
+++++
A
config/nixos/modules/websites/gts.zaphyra.eu.nix
|
207
+++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++
M
hosts/morio/default.nix
|
1
+
M
secrets/morio.yaml
|
7
+++++--
diff --git a/config/nixos/modules/presets/katja/mailServer.nix b/config/nixos/modules/presets/katja/mailServer.nix
@@ -118,6 +118,7 @@ in
 
       sops.secrets = {
         "mailPasswords/katja@zaphyra.eu" = { };
+        "mailPasswords/gts@zaphyra.eu" = { };
         "resticPasswords/mail" = { };
         "sieveScripts/katja@zaphyra.eu.sieve" = {
           sopsFile = inputs.self.sopsSecrets.zaphyra.sieve;

@@ -189,6 +190,10 @@ in
               "@zaphyra.eu"
             ];
           };
+          "gts@zaphyra.eu" = {
+            hashedPasswordFile = config.sops.secrets."mailPasswords/gts@zaphyra.eu".path;
+            sendOnly = true;
+          };
         };
       };
 
diff --git a/config/nixos/modules/websites/gts.zaphyra.eu.nix b/config/nixos/modules/websites/gts.zaphyra.eu.nix
@@ -0,0 +1,207 @@
+{
+  name,
+  povSelf,
+  hostConfig,
+  config,
+  pkgs,
+  lib,
+  ...
+}:
+
+let
+  inherit (lib) types;
+  cfg = lib.getAttrFromPath povSelf config;
+  cfgWebsites = lib.getAttrFromPath (lib.remove name povSelf) config;
+
+in
+{
+
+  options = {
+    enable = {
+      type = types.bool;
+      default = false;
+    };
+    domain = {
+      type = types.str;
+      default = "zaphyra.eu";
+    };
+    subdomain = {
+      type = types.str;
+      default = "gts";
+    };
+  };
+
+  config = lib.mkIf cfg.enable {
+    assertions = [
+      {
+        assertion = cfgWebsites."zaphyra.eu".enable == true;
+        message = "The option 'modules.websites.\"zaphyra.eu\"' must be enabled in order to use this module.";
+      }
+    ];
+
+    dns.zones."${cfg.domain}".subdomains."${cfg.subdomain}".CNAME = [ "${config.networking.fqdn}." ];
+
+    sops.secrets = {
+      "resticPasswords/gotosocial" = { };
+      gotosocialEnv = { };
+    };
+
+    systemd.tmpfiles.settings.stagit = {
+      "/var/lib/gotosocial/storage".d = {
+        user = config.modules.services.gotosocial.user;
+        group = config.modules.services.gotosocial.group;
+        mode = "750";
+        age = "-";
+      };
+    };
+
+    modules.services = {
+      resticBackup.paths = {
+        gotosocial = {
+          enable = true;
+          user = config.modules.services.gotosocial.user;
+          passwordFile = config.sops.secrets."resticPasswords/gotosocial".path;
+          sqliteDatabases = [
+            (lib.mkIf (
+              config.modules.services.gotosocial.settings.db-type == "sqlite"
+            ) config.modules.services.gotosocial.settings.db-address)
+          ];
+          paths = [
+            (lib.mkIf (
+              config.modules.services.gotosocial.settings.storage-backend == "local"
+            ) config.modules.services.gotosocial.settings.storage-local-base-path)
+            "${config.modules.services.gotosocial.stateDir}/backup.json"
+          ];
+          runBeforeBackup = ''${pkgs.gotosocial}/bin/gotosocial --config-path /etc/gotosocial.yaml admin export --path ${config.modules.services.gotosocial.stateDir}/backup.json'';
+        };
+      };
+      gotosocial = {
+        enable = true;
+        group = config.services.nginx.group;
+        environmentFile = config.sops.secrets.gotosocialEnv.path;
+        settings = {
+          protocol = lib.mkDefault "https";
+
+          bind-address = lib.mkDefault "[::1]";
+          port = lib.mkDefault 8085;
+
+          trusted-proxies = lib.mkDefault [
+            "::1/128"
+            "172.17.0.0/24"
+          ];
+
+          db-type = lib.mkDefault "sqlite";
+          db-address = lib.mkDefault "${config.modules.services.gotosocial.stateDir}/db.sqlite";
+
+          storage-backend = lib.mkDefault "local";
+          storage-local-base-path = "${config.modules.services.gotosocial.stateDir}/storage";
+
+          host = "${cfg.subdomain}.${cfg.domain}";
+          account-domain = cfg.domain;
+
+          landing-page-user = "katja";
+
+          accounts-allow-custom-css = true;
+          accounts-registration-open = false;
+
+          instance-expose-peers = true;
+          instance-expose-suspended = true;
+          instance-expose-suspended-web = true;
+
+          instance-languages = [
+            "de"
+            "en-us"
+          ];
+
+          media-local-max-size = "50MiB";
+          media-remote-max-size = "50MiB";
+
+          media-remote-cache-days = 3;
+          media-cleanup-from = "01:00";
+
+          smtp-host = "morio.infra.zaphyra.eu";
+          smtp-port = 587;
+          smtp-username = "gts@zaphyra.eu";
+          smtp-from = "gts@zaphyra.eu";
+        };
+      };
+    };
+
+    services.nginx = {
+      appendHttpConfig = ''
+        proxy_cache_path /var/cache/nginx keys_zone=gotosocial_ap_public_responses:10m inactive=1w;
+      '';
+      virtualHosts =
+        {
+          "${config.modules.services.gotosocial.settings.host}" = {
+            useACMEHost = lib.mkDefault "${config.networking.fqdn}";
+            forceSSL = lib.mkDefault true;
+            kTLS = lib.mkDefault true;
+            locations = {
+              "/" = {
+                proxyPass = "http://${toString config.modules.services.gotosocial.settings.bind-address}:${toString config.modules.services.gotosocial.settings.port}";
+                proxyWebsockets = true;
+              };
+
+              "~ /.well-known/(webfinger|host-meta)$" = {
+                proxyPass = "http://${toString config.modules.services.gotosocial.settings.bind-address}:${toString config.modules.services.gotosocial.settings.port}";
+                extraConfig = ''
+                  proxy_cache gotosocial_ap_public_responses;
+                  proxy_cache_background_update on;
+                  proxy_cache_key $scheme://$host$uri$is_args$query_string;
+                  proxy_cache_valid 200 10m;
+                  proxy_cache_use_stale error timeout updating http_500 http_502 http_503 http_504 http_429;
+                  proxy_cache_lock on;
+                  add_header X-Cache-Status $upstream_cache_status;
+                '';
+              };
+
+              "~ ^\/users\/(?:[a-z0-9_\.]+)\/main-key$" = {
+                proxyPass = "http://${toString config.modules.services.gotosocial.settings.bind-address}:${toString config.modules.services.gotosocial.settings.port}";
+                extraConfig = ''
+                  proxy_cache gotosocial_ap_public_responses;
+                  proxy_cache_background_update on;
+                  proxy_cache_key $scheme://$host$uri;
+                  proxy_cache_valid 200 604800s;
+                  proxy_cache_use_stale error timeout updating http_500 http_502 http_503 http_504 http_429;
+                  proxy_cache_lock on;
+
+                  add_header X-Cache-Status $upstream_cache_status;
+                '';
+              };
+
+              "/assets/".extraConfig = ''
+                alias ${config.modules.services.gotosocial.package}/share/web/assets/;
+                autoindex off;
+                expires max;
+                add_header Cache-Control "public, immutable";
+              '';
+            };
+          };
+        }
+        // (
+          if
+            (
+              config.modules.services.gotosocial.settings.account-domain
+              != config.modules.services.gotosocial.settings.host
+            )
+          then
+            {
+              "${config.modules.services.gotosocial.settings.account-domain}" = {
+                locations = {
+                  "= /.well-known/host-meta".extraConfig =
+                    "return 301 https://${config.modules.services.gotosocial.settings.host}$request_uri;";
+                  "= /.well-known/webfinger".extraConfig =
+                    "return 301 https://${config.modules.services.gotosocial.settings.host}$request_uri;";
+                  "= /.well-known/nodeinfo".extraConfig =
+                    "return 301 https://${config.modules.services.gotosocial.settings.host}$request_uri;";
+                };
+              };
+            }
+          else
+            { }
+        );
+    };
+  };
+
+}
diff --git a/hosts/morio/default.nix b/hosts/morio/default.nix
@@ -82,6 +82,7 @@
           "git.zaphyra.eu".enable = true;
           "bikemap.zaphyra.eu".enable = true;
           "dav.zaphyra.eu".enable = true;
+          "gts.zaphyra.eu".enable = true;
         };
 
         users.katja.enable = true;
diff --git a/secrets/morio.yaml b/secrets/morio.yaml
@@ -1,12 +1,15 @@
 acmeTSIGKey: ENC[AES256_GCM,data:XbTSbHisL5ZszYY4hvKplyWG98eK4DUeiSpA24Am/QPjEw8ofHWzU2WmV9hzj8Jd29Z0Yf0u/m5T/FESS2Gt9w==,iv:liySg99CmJ9RePJ84pD2+2mNsvZ4SbEXt3d58kDsHgI=,tag:zNwYe1ZfhFGmfP2s+OLj3Q==,type:str]
 mailPasswords:
     katja@zaphyra.eu: ENC[AES256_GCM,data:BSNsU+TBqGcprevSiTRvtzCxi8FbsBrLItrgwwYZAvJ8HhDXW9xgL9AX9mDi59Z8gcPhSWGhdOOfYGfp,iv:nSDOguVcatHJzAFim+bpiy9SV024MuTYcUHqgSNdkhA=,tag:kJ622f4I5pGhBltj466qIw==,type:str]
+    gts@zaphyra.eu: ENC[AES256_GCM,data:z+4Ha58AHS6q8n9ke77LoocEmNbASL+EBTptUZNrpUDRq8ypM8wHGl+J4uMhrJIQzpGYGQBxO+x4vCMp,iv:3wvvmJ1+Ui3xT4SSYw9blJ/1tjc7KKYhc26nP3IdlwY=,tag:9SAGK4c1n5f65bP7CxPF8A==,type:str]
 resticPasswords:
     gitolite: ENC[AES256_GCM,data:g28//NtKEYL+Dh0+Ws73ZKySl1L0avxqNXVn5lKaj1U=,iv:mGQ7pYjeMEGTCS1l6H/h043M2oAhgMOAlUHkgDir03E=,tag:E/ps0EZmlMEm+ziWzXzQPQ==,type:str]
     mail: ENC[AES256_GCM,data:wag5v/l0kQrhStO9P3ibtRtkReslszu4IfTEL8Ls4Pc=,iv:QCSveMAylefSBeb8Eaw6Av+1cA6lAvhtv1jNT8QUvIM=,tag:Y+HKURnEXPxKUSvGwaJAjA==,type:str]
     radicale: ENC[AES256_GCM,data:GsAXncF4JRHaNe0Tkv6PucJpwFFu9cfHo3INIBjc24I=,iv:XVvx9UOGIcC94uh3LnwOFs6g8Zy2YHjodCp0RNWcFrQ=,tag:ekUjoM/fbsmST2KDPNf/VA==,type:str]
+    gotosocial: ENC[AES256_GCM,data:8zc4JZVTyPZQADDUrobjAOuRr/3CpfNROO8edY63nk4=,iv:nxfSNSw+aypsTKXJO68B6SkqFfBbfWFARfcNTPODSBA=,tag:ozsw8R6xbpS8E+fNzCosUQ==,type:str]
 knotKeys: ENC[AES256_GCM,data:rlTFDvonfEQFST1eSHHcaG3e1CSt5paDUTvfoYmInBV7mjqe7PwT5dtg01W2ANZJYl+SN/cdI3eEvAdJvwYR6FK+7g1LPwn6G1coE68a/XwzsWM5WpSemmDfTykoUiguEUfRCZ0Q3M7YqV0/jDWrKMaH0iKqKqvlv7nEy6VXB5SZBX+aN18KvPVygw5FixQ/kD3XFI2HTTST4vqlMma3CTsjnK6Uwf1421JOIe3JR32qd0V7IfhFvL0mErMIRhLnITO9uJ//t1HJoeaOV7FEY4K6Ohacng1c68fkUjVX5wYBTd6X657nFqevvLiMRDiQnASOJrAJUAeq4Kwf5R7C/I/MeVh+1Hq/U+z4ZQKh/DViEE8+TkJwDMBAWarzlyOz7xDF8O+fj4iH5jTX8H3FmJLU/TVU0QXqnwjcAAVs/YNARNVt0wGdWTb9iyvD7vEIZE57wIp+TIGE8XFjOO11/DRC/0kC8HFkvoXke9IRrTIj1pCP1VIrv31v7aIyphWa5hBuBHfVb0f8g5eaqyKumM03Rge+Fo+jtM/NP7H2gao6uaZM/K4a625nVx+M1lUpW+1c0sIAME2SlDjSyuhTkMknOPGAAYXMwVQGazoOJna6sEBl6jYcgn31w3dHtJXGKyAB0eqELxjt5b0tzcBfJ4pXi7HO7w2yhKrqyL7GuE5LtLp5mkguC5eZbiX+VlGTLX6V2z1kDRUdYDDZMMh3cYGBIrGVoJhWx8xLWrLGm7TrvifiwYJq5Mq13tt2hS7HpY8T8YGBD2x3IdPAHtikZUYgv5cQxs7drSJi8zFQAwDUKofxhJQUvqrnmvNf+eiGkfgI7lQ0//NLg9o4t+5g+T3mV8IUkW4nbJsP46k6azQGBt3udYAVhgrFy/jTE++KrA==,iv:+5NBUUC1QhPjN+6E8nWhzd2SNuH9mLbhsFwDTm8Hy+U=,tag:RtSO5Rmb0wNR9ovtpwJIIg==,type:str]
 radicaleUsers: ENC[AES256_GCM,data:kH5XW/Gr2xMJWm68unKtZ+L19S74gOf1YXw5QtPcBnp8jJrQsc3mHX5GPOJafuNa23Tnt9BHTFmuO3e5bEzhBcVm8GdoMR/Wz4B0y0W5,iv:Frc4ukXwdWZuWNgauLUyz4ErFKFUvoYoTMN9eZNWAGg=,tag:PLVaetT3syVGR4Ox3AYhUA==,type:str]
+gotosocialEnv: ENC[AES256_GCM,data:5hvURqX+EqN8zpjirBmh5TIWWgaCga9QxnAfyW1rwOXELnM9ZBJAmqwLdxUa2j2DGrXsqw==,iv:nhVyiAoOJY0HtjB13FnmnQyLB+BWSRwDVrwUiFHBrE4=,tag:P207zPou7yXJKJBf+pxlHg==,type:str]
 sops:
     kms: []
     gcp_kms: []

@@ -22,8 +25,8 @@ sops:
             bDRhUEtDdmlZa0ZENFhSVnNqVjFCR1UKEIkSg3tKFkwlnNXFFqCBtdZBGz1bEmWl
             wghkTtqTl++759zZAAmjdnFFQWs/AoCZ5g/GUidz6HHcFdxMpGVmiA==
             -----END AGE ENCRYPTED FILE-----
-    lastmodified: "2025-05-24T12:56:49Z"
-    mac: ENC[AES256_GCM,data:OkOahTYk7bSyJqXJh3WDON5RCNp7vyzkU1joni/gmBs9iz0SPu4dIOnip0Vuosf1OERnFVpI8/jW/kUG5J+EJ9U1AmB8ygs2eR1XLTPNTZcV2JRwS1p9GZ3EU/1FY6xBv50RxkLVf9cu/aDBjPEXUleN+3c7DQ6X02NVe9YO0Zo=,iv:yQ8KcIOFPgCLeFAo8z3YKoH6Og8hxWxu0aljSi8J4xA=,tag:GxM0Nm/HzC8kjourFZ7+Zg==,type:str]
+    lastmodified: "2025-05-24T14:45:42Z"
+    mac: ENC[AES256_GCM,data:Rh1e8u7KonZAkknJO+2qBknwJk9yayrr1Bae06jT6Fn6+YoMfnXx2IxsVe9fcxtaJchM/SW8JlddYQJftbeKBXzA2sMpiBd569SAIyoXr6hMxC9EwrcExinzECe8dN3sDT1BCZPeFOaJpYQQM8ZcwXYVB2V3iHIM97eMO7peXLg=,iv:0lBIogIHTWrrEPOcljg5Dc6+3zW4mGbj6RtL8cArHGk=,tag:gV77gQ/3/ws4Z+7zAptL2A==,type:str]
     pgp:
         - created_at: "2025-05-21T08:09:28Z"
           enc: |-