zaphyra's git: nixfiles

zaphyra and void's nixfiles

commit 0692663ee842e266a24ff97830ef33efe77bb4c0
parent 25ac1cfd0cce6266a85f61118db044c50d3cc935
Author: Katja (zaphyra) <git@ctu.cx>
Date: Tue, 27 May 2025 00:05:35 +0200

config/nixos/modules/websites: add `fedi.ctu.cx` (and `ctu.cx`) (and enable on host `novus`)
4 files changed, 286 insertions(+), 16 deletions(-)
A
config/nixos/modules/websites/ctu.cx.nix
|
42
++++++++++++++++++++++++++++++++++++++++++
A
config/nixos/modules/websites/fedi.ctu.cx.nix
|
204
+++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++
M
hosts/novus/default.nix
|
42
+++++++++++++++++++++++++++++++++---------
M
secrets/novus.yaml
|
14
+++++++-------
diff --git a/config/nixos/modules/websites/ctu.cx.nix b/config/nixos/modules/websites/ctu.cx.nix
@@ -0,0 +1,42 @@
+{
+  povSelf,
+  hostConfig,
+  config,
+  lib,
+  dnsNix,
+  ...
+}:
+
+let
+  inherit (lib) types;
+  cfg = lib.getAttrFromPath povSelf config;
+
+in
+{
+
+  options = {
+    enable = {
+      type = types.bool;
+      default = false;
+    };
+    domain = {
+      type = types.str;
+      default = "ctu.cx";
+    };
+  };
+
+  config = lib.mkIf cfg.enable {
+    dns.zones."${cfg.domain}" =
+      dnsNix.combinators.host hostConfig.networking.ip4Address hostConfig.networking.ip6Address;
+
+    services.nginx = {
+      enable = true;
+      virtualHosts."${cfg.domain}" = {
+        useACMEHost = "${config.networking.fqdn}";
+        forceSSL = true;
+        kTLS = true;
+      };
+    };
+  };
+
+}
diff --git a/config/nixos/modules/websites/fedi.ctu.cx.nix b/config/nixos/modules/websites/fedi.ctu.cx.nix
@@ -0,0 +1,204 @@
+{
+  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 = "ctu.cx";
+    };
+    subdomain = {
+      type = types.str;
+      default = "fedi";
+    };
+  };
+
+  config = lib.mkIf cfg.enable {
+    assertions = [
+      {
+        assertion = cfgWebsites."${cfg.domain}".enable == true;
+        message = "The option 'modules.websites.\"${cfg.domain}\"' must be enabled in order to use this module.";
+      }
+    ];
+
+    dns.zones."${cfg.domain}".subdomains."${cfg.subdomain}".CNAME = [ "${config.networking.fqdn}." ];
+
+    sops.secrets = {
+      "resticPasswords/gotosocial" = { };
+      "environments/gotosocial" = {
+        restartUnits = [ "gotosocial.service" ];
+      };
+    };
+
+    systemd.tmpfiles.settings.gotosocial = {
+      "/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."environments/gotosocial".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";
+        };
+      };
+    };
+
+    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/novus/default.nix b/hosts/novus/default.nix
@@ -13,26 +13,37 @@
   };
 
   networking = {
-    ip4IsPrivate    = false;
-    ip4Address      = "194.36.145.49";
+    ip4IsPrivate = false;
+    ip4Address = "194.36.145.49";
     ip4PrefixLength = 22;
     defaultGateway4 = "194.36.144.1";
 
-    ip6IsPrivate    = false;
-    ip6Address      = "2a03:4000:4d:5e::1";
+    ip6IsPrivate = false;
+    ip6Address = "2a03:4000:4d:5e::1";
     ip6PrefixLength = 64;
     defaultGateway6 = "fe80::1";
   };
 
   configuration =
-    { config, pkgs, ... }:
     {
+      inputs,
+      config,
+      pkgs,
+      ...
+    }:
+    {
+
+      boot.initrd.systemd.emergencyAccess = true;
+      boot.kernelPackages = pkgs.linuxPackages_latest;
 
-        boot.initrd.systemd.emergencyAccess = true;
-        boot.kernelPackages = pkgs.linuxPackages_latest;
+      sops.secrets = {
+        "resticEnv/novus" = {
+          sopsFile = inputs.self.sopsSecrets.common;
+        };
+      };
 
-        modules = {
-          filesystem.rootDisk = {
+      modules = {
+        filesystem.rootDisk = {
           enable = true;
           encrypt = true;
           type = "ext4";

@@ -53,10 +64,23 @@
           };
         };
 
+        services = {
+          resticBackup.targets = {
+            novus = {
+              repository = "rest:https://restic.novus.infra.zaphyra.eu";
+              environmentFile = config.sops.secrets."resticEnv/novus".path;
+            };
+          };
+        };
+
         websites = {
           "restic.novus.infra.zaphyra.eu".enable = true;
           "flauschehorn.zaphyra.eu".enable = true;
           "ip.zaphyra.eu".enable = true;
+
+          #old fedi-instance
+          "ctu.cx".enable = true;
+          "fedi.ctu.cx".enable = true;
         };
 
         users.katja.enable = true;
diff --git a/secrets/novus.yaml b/secrets/novus.yaml
@@ -1,11 +1,11 @@
 acmeTSIGKey: ENC[AES256_GCM,data:a34wyBRoW3Mo6Mep66wi99xfuZLecCrDgpH4EFy4T8PpHYnhR/pLubXVzZpwouKrC+g0E+3hyBR6Bmc/1arKmQ==,iv:938iHOR2NwCjZEBQpjhnCEG11DcxtfeBLGmRh06LaRg=,tag:uhMkBrc9G7inEBg7ddWvZg==,type:str]
 resticServerHtpasswd: ENC[AES256_GCM,data:cjva4AXQw37feKs1wFl5o0pLJjfkW5sh5U8jZ2gWUYBlMQgBmdhYAuUwcR8jvismBafL6gSW4esvxPnBpcZC5yTP7TwQh/f18pouaTVH,iv:LJkvhOgTNt065K5kQNlP6zQUTK0bqd9smTIt7meUA4c=,tag:CkzAqsoKOXIdtTgqdOxORA==,type:str]
 rcloneConfig: ENC[AES256_GCM,data:ELWBEt1akcyQkL+bZN6HfkSvaARMEVKqwN0gZuzJv7zrdnd35nLJu/aAU2tSqsuPK8T7B+J3VqpLYuKZALHTOwm6dzOLnM8tBuBEO/Qy0Fb2wzj/U4/LHo1XBwAZC4pO4seyWi07IxfiafcPQ2YdZyoJcGzLXnmpOCTOn3C09C6foaIaOGBlh8weBIyKpCNM9YhjljyID9MoWFAc3+PCuASrHssSapTSX8gIgylgD37YiFY2s6ICZKCsa+TxXF6DD2qfnnf3zGNpozTMcH4bThaGB2BcqUPspylApAEIbig4jxFb/jb7PLy63E5WGpsskGYF5CT3zbzaNgYzaFZZdlZcBUcX3BUU37qXPAaRZg2f7NJopAdFlG0u8SPqetIrOikwSdL157+0WuixhPqHFC0S0erQ3fSSrXyhbhrt5kG+MO1LK34CS1aB/UZEnd2LYIJtGscH9QQMd6J7I1pW3Lgq6onS5/hE77G5mGXAKiVdLKu9E65C6X1PnUl2PwkvnioAPtMJ6bfzELEdfuD79kPq9P4HnDG1geP7Sv+BUCKzdZ+mTct7LNqXlA7hd18tAgYvt1LFumq7KV0lX3JqUGZdqSrhDJU6SYudN/BYRaPrvWCabCxJ1HzjM6lKynEuXuq41Y9RrEaekJv4/yJA33x5G+rq2CPnQEHjMu05rwXRGiCrOHCiPtPioxPFvAn5nZsZruPCZII8hKhC8Bno/aAgnVA3Ud29Ddvl9a3Rh8XCTKXpeg==,iv:Zq7DGFKxBw5tmEXXK8W7Aun1Gk78iwgju6NJJZcwBe0=,tag:3a0hn76gMiEX1imuQT0qaQ==,type:str]
+resticPasswords:
+    gotosocial: ENC[AES256_GCM,data:e2r/4Ok5XIZgHy+vGkNYVDxidRGCt8ZuwkNZsPTvta4=,iv:yQnBoEXPQ9XxrohIFCZgQo7gG6m/20lTMQBiGmR94rw=,tag:MSvgOsNs1X5Ij1rwf+xsZA==,type:str]
+environments:
+    gotosocial: ""
 sops:
-    kms: []
-    gcp_kms: []
-    azure_kv: []
-    hc_vault: []
     age:
         - recipient: age1tud4lvpmpx5nqceyp09ls9ej8l80zlh29d8cpjxcajfnnyy85fvqs63snm
           enc: |

@@ -16,8 +16,8 @@ sops:
             N0dBZExjdWpSVDJmYlFmOHluZEJUWkUKhkWONhK0LiVhAY+pdemXOBHtBALV65ZP
             EClQs/bns2HUF4E5Lc6mv8WvogFNhm/TLGYX/sOWSvAYExRNiHtssQ==
             -----END AGE ENCRYPTED FILE-----
-    lastmodified: "2025-05-22T07:59:22Z"
-    mac: ENC[AES256_GCM,data:KVDR3eVJJM8y/aD3+EFGkyiM4T1W06PQeufmk8j1TMp71KuZVw/xqxCKiIUiDN9OC4fQ5EI7+WXfVgsPrcSQXnjx8J9CRlSyzNMa+99bMt4jms98c5QU1Jf4PFfqQ9FxBy+AIEyEjcPHKs458oMVaoOROjkIpWMc0hSGfZZha/A=,iv:XoiYFlCoqEiTmhkwLJ3bVjO2xnhukea3AzRXZJ8dkUY=,tag:oyb538WsxNAy/DxThJ4leQ==,type:str]
+    lastmodified: "2025-05-26T18:01:04Z"
+    mac: ENC[AES256_GCM,data:3lgJQkz7IFQdPNnPvjBc10/DoUVjulGLgqzZC2M90WpNWcJfM2I84CCRzPNHGhmPK7EtIJWYnYIFiXiCNhQuPVQnSRo6rabVpfy3XgAwJhVNKtFg6nyoA0kCnnqsj8bAm0KBh5Okb1rz00YbA13CmNWJnDFAhI980qOhQ37GiPk=,iv:FaJvZ6QPryry1zX5jCbe171+CNj3/+rLNZZoZ3TAK8I=,tag:BVFUrFuOwY6sBAJ3TUCjsQ==,type:str]
     pgp:
         - created_at: "2025-05-21T10:26:58Z"
           enc: |-

@@ -40,4 +40,4 @@ sops:
             -----END PGP MESSAGE-----
           fp: 9D7CACD7039E5AD616FD25879F935DB630A167E7
     unencrypted_suffix: _unencrypted
-    version: 3.9.4
+    version: 3.10.2