about summary refs log tree commit diff
diff options
context:
space:
mode:
-rw-r--r--default.nix39
-rw-r--r--flake.lock129
-rw-r--r--flake.nix11
-rw-r--r--modules/README.md9
-rw-r--r--modules/cachix/caches/nix-community.nix12
-rw-r--r--modules/cachix/default.nix23
-rw-r--r--modules/flakes.nix36
-rw-r--r--modules/nix.nix34
-rw-r--r--modules/persistence.nix47
-rw-r--r--modules/security.nix69
-rw-r--r--modules/services/_template.nix13
-rw-r--r--modules/services/acme.nix52
-rw-r--r--modules/services/akkoma/blocklist.toml164
-rw-r--r--modules/services/akkoma/default.nix102
-rw-r--r--modules/services/akkoma/favicon-withbg.pngbin17371 -> 0 bytes
-rw-r--r--modules/services/akkoma/favicon.pngbin16693 -> 0 bytes
-rw-r--r--modules/services/akkoma/logo.pngbin1304 -> 0 bytes
-rw-r--r--modules/services/akkoma/logo.svg71
-rw-r--r--modules/services/akkoma/robots.txt2
-rw-r--r--modules/services/akkoma/terms-of-service.html26
-rw-r--r--modules/services/authentik.nix69
-rw-r--r--modules/services/backup.nix81
-rw-r--r--modules/services/cgit/cgit-exotic.css953
-rw-r--r--modules/services/cgit/default.nix129
-rw-r--r--modules/services/cinny-web.nix34
-rw-r--r--modules/services/coredns/_corefile.nix3
-rw-r--r--modules/services/coredns/default.nix18
-rw-r--r--modules/services/coturn.nix64
-rw-r--r--modules/services/dovecot.nix18
-rw-r--r--modules/services/element-web.nix47
-rw-r--r--modules/services/fail2ban.nix20
-rw-r--r--modules/services/git-daemon.nix29
-rw-r--r--modules/services/gitolite/default.nix110
-rw-r--r--modules/services/gitolite/fix-refs9
-rw-r--r--modules/services/gitolite/post-receive19
-rw-r--r--modules/services/gitolite/rename63
-rw-r--r--modules/services/jitsi.nix43
-rw-r--r--modules/services/ldap.nix76
-rw-r--r--modules/services/matrix-bridge.nix390
-rw-r--r--modules/services/matrix-homeserver.nix190
-rw-r--r--modules/services/matrix-moderation.nix58
-rw-r--r--modules/services/metrics.nix169
-rw-r--r--modules/services/nebula.nix18
-rw-r--r--modules/services/nginx.nix37
-rw-r--r--modules/services/nixos-mailserver.nix159
-rw-r--r--modules/services/obsidian-livesync.nix63
-rw-r--r--modules/services/postgresql.nix34
-rw-r--r--modules/services/rss.nix64
-rw-r--r--modules/services/searx.nix50
-rw-r--r--modules/services/sefidel-web.nix26
-rw-r--r--modules/services/soju.nix48
-rw-r--r--modules/services/tailscale.nix22
-rw-r--r--modules/services/vikunja.nix50
-rw-r--r--modules/sops.nix21
54 files changed, 164 insertions, 3859 deletions
diff --git a/default.nix b/default.nix
index 63f1796..e26e166 100644
--- a/default.nix
+++ b/default.nix
@@ -2,7 +2,44 @@
 with lib;
 with lib.my;
 {
-  imports = mapModulesRec' (toString ./modules) import;
+  imports = with inputs.infra-modules.nixosModules; [
+    nix
+    flakes
+    security
+    sops
+    flakes
+    cachix
+    services.acme
+    services.akkoma
+    services.authentik
+    services.backup
+    services.cgit
+    services.cinny-web
+    services.coredns
+    services.coturn
+    services.dovecot
+    services.element-web
+    services.fail2ban
+    services.git-daemon
+    services.gitolite
+    services.jitsi
+    services.ldap
+    services.matrix-bridge
+    services.matrix-homeserver
+    services.matrix-moderation
+    services.metrics
+    services.nebula
+    services.nginx
+    services.nixos-mailserver
+    services.obsidian-livesync
+    services.postgresql
+    services.rss
+    services.searx
+    services.sefidel-web
+    services.soju
+    services.tailscale
+    services.vikunja
+  ];
 
   networking.useDHCP = mkDefault false;
 }
diff --git a/flake.lock b/flake.lock
index abdd148..e61ed2b 100644
--- a/flake.lock
+++ b/flake.lock
@@ -8,6 +8,7 @@
         "flake-utils": "flake-utils",
         "napalm": "napalm",
         "nixpkgs": [
+          "infra-modules",
           "unstable"
         ],
         "nixpkgs-23-05": "nixpkgs-23-05",
@@ -143,6 +144,21 @@
         "type": "github"
       }
     },
+    "flake-utils_3": {
+      "locked": {
+        "lastModified": 1667395993,
+        "narHash": "sha256-nuEHfE/LcWyuSWnS8t12N1wc105Qtau+/OdUAjtQ0rA=",
+        "owner": "numtide",
+        "repo": "flake-utils",
+        "rev": "5aed5285a952e0b949eb3ba02c12fa4fcfef535f",
+        "type": "github"
+      },
+      "original": {
+        "owner": "numtide",
+        "repo": "flake-utils",
+        "type": "github"
+      }
+    },
     "impermanence": {
       "locked": {
         "lastModified": 1703656108,
@@ -158,13 +174,40 @@
         "type": "github"
       }
     },
+    "infra-modules": {
+      "inputs": {
+        "authentik-nix": "authentik-nix",
+        "impermanence": "impermanence",
+        "nixos-mailserver": "nixos-mailserver",
+        "sefidel-web": "sefidel-web",
+        "sops-nix": "sops-nix",
+        "unstable": [
+          "unstable"
+        ]
+      },
+      "locked": {
+        "lastModified": 1706090394,
+        "narHash": "sha256-vRBUWkZVMkkRb7Hk9BD+dgzvXB50Ip4rflT9P9iiY2A=",
+        "ref": "refs/heads/main",
+        "rev": "8e9b074467006c76768efe04cf1fb1ef9d652c67",
+        "revCount": 1,
+        "type": "git",
+        "url": "https://git.exotic.sh/infra-modules"
+      },
+      "original": {
+        "type": "git",
+        "url": "https://git.exotic.sh/infra-modules"
+      }
+    },
     "napalm": {
       "inputs": {
         "flake-utils": [
+          "infra-modules",
           "authentik-nix",
           "flake-utils"
         ],
         "nixpkgs": [
+          "infra-modules",
           "authentik-nix",
           "nixpkgs"
         ]
@@ -186,6 +229,7 @@
     "nix-github-actions": {
       "inputs": {
         "nixpkgs": [
+          "infra-modules",
           "authentik-nix",
           "poetry2nix",
           "nixpkgs"
@@ -210,6 +254,7 @@
         "blobs": "blobs",
         "flake-compat": "flake-compat_2",
         "nixpkgs": [
+          "infra-modules",
           "unstable"
         ],
         "nixpkgs-22_11": "nixpkgs-22_11",
@@ -342,14 +387,48 @@
         "type": "github"
       }
     },
+    "nixpkgs-stable_2": {
+      "locked": {
+        "lastModified": 1704290814,
+        "narHash": "sha256-LWvKHp7kGxk/GEtlrGYV68qIvPHkU9iToomNFGagixU=",
+        "owner": "NixOS",
+        "repo": "nixpkgs",
+        "rev": "70bdadeb94ffc8806c0570eb5c2695ad29f0e421",
+        "type": "github"
+      },
+      "original": {
+        "owner": "NixOS",
+        "ref": "release-23.05",
+        "repo": "nixpkgs",
+        "type": "github"
+      }
+    },
+    "nixpkgs_2": {
+      "locked": {
+        "lastModified": 1673606088,
+        "narHash": "sha256-wdYD41UwNwPhTdMaG0AIe7fE1bAdyHe6bB4HLUqUvck=",
+        "owner": "NixOS",
+        "repo": "nixpkgs",
+        "rev": "37b97ae3dd714de9a17923d004a2c5b5543dfa6d",
+        "type": "github"
+      },
+      "original": {
+        "owner": "NixOS",
+        "ref": "nixpkgs-unstable",
+        "repo": "nixpkgs",
+        "type": "github"
+      }
+    },
     "poetry2nix": {
       "inputs": {
         "flake-utils": [
+          "infra-modules",
           "authentik-nix",
           "flake-utils"
         ],
         "nix-github-actions": "nix-github-actions",
         "nixpkgs": [
+          "infra-modules",
           "authentik-nix",
           "nixpkgs"
         ],
@@ -372,12 +451,10 @@
     },
     "root": {
       "inputs": {
-        "authentik-nix": "authentik-nix",
-        "impermanence": "impermanence",
-        "nixos-mailserver": "nixos-mailserver",
+        "infra-modules": "infra-modules",
         "nixpkgs-2111": "nixpkgs-2111",
-        "sefidel-web": "sefidel-web",
-        "sops-nix": "sops-nix",
+        "sefidel-web": "sefidel-web_2",
+        "sops-nix": "sops-nix_2",
         "unstable": "unstable",
         "unstable-small": "unstable-small"
       }
@@ -401,9 +478,29 @@
         "url": "https://git.exotic.sh/pub/sefidel/sefidel-web"
       }
     },
+    "sefidel-web_2": {
+      "inputs": {
+        "flake-utils": "flake-utils_3",
+        "nixpkgs": "nixpkgs_2"
+      },
+      "locked": {
+        "lastModified": 1696069380,
+        "narHash": "sha256-KKTX1XKGnglV+vGbvKjduT2QjE2snbyy8R7nNuXvnMc=",
+        "ref": "refs/heads/main",
+        "rev": "305ee346ca81883de4fc6575460021a57cacefeb",
+        "revCount": 6,
+        "type": "git",
+        "url": "https://git.exotic.sh/pub/sefidel/sefidel-web"
+      },
+      "original": {
+        "type": "git",
+        "url": "https://git.exotic.sh/pub/sefidel/sefidel-web"
+      }
+    },
     "sops-nix": {
       "inputs": {
         "nixpkgs": [
+          "infra-modules",
           "unstable"
         ],
         "nixpkgs-stable": "nixpkgs-stable"
@@ -422,6 +519,27 @@
         "type": "github"
       }
     },
+    "sops-nix_2": {
+      "inputs": {
+        "nixpkgs": [
+          "unstable"
+        ],
+        "nixpkgs-stable": "nixpkgs-stable_2"
+      },
+      "locked": {
+        "lastModified": 1704908274,
+        "narHash": "sha256-74W9Yyomv3COGRmKi8zvyA5tL2KLiVkBeaYmYLjXyOw=",
+        "owner": "Mic92",
+        "repo": "sops-nix",
+        "rev": "c0b3a5af90fae3ba95645bbf85d2b64880addd76",
+        "type": "github"
+      },
+      "original": {
+        "owner": "Mic92",
+        "repo": "sops-nix",
+        "type": "github"
+      }
+    },
     "systems": {
       "locked": {
         "lastModified": 1681028828,
@@ -454,6 +572,7 @@
     "treefmt-nix": {
       "inputs": {
         "nixpkgs": [
+          "infra-modules",
           "authentik-nix",
           "poetry2nix",
           "nixpkgs"
diff --git a/flake.nix b/flake.nix
index c0da437..a28c4c3 100644
--- a/flake.nix
+++ b/flake.nix
@@ -6,16 +6,11 @@
     unstable-small.url = "github:nixos/nixpkgs/nixos-unstable-small";
     nixpkgs-2111.url = "github:nixos/nixpkgs/nixos-21.11";
 
-    impermanence.url = "github:nix-community/impermanence";
-
-    authentik-nix.url = "github:nix-community/authentik-nix";
-    authentik-nix.inputs.nixpkgs.follows = "unstable";
-
     sops-nix.url = "github:Mic92/sops-nix";
     sops-nix.inputs.nixpkgs.follows = "unstable";
 
-    nixos-mailserver.url = "gitlab:simple-nixos-mailserver/nixos-mailserver";
-    nixos-mailserver.inputs.nixpkgs.follows = "unstable";
+    infra-modules.url = "git+https://git.exotic.sh/infra-modules";
+    infra-modules.inputs.unstable.follows = "unstable";
 
     sefidel-web.url = "git+https://git.exotic.sh/pub/sefidel/sefidel-web";
   };
@@ -34,8 +29,6 @@
     {
       lib = lib.my;
 
-      nixosModules = mapModulesRec ./modules import;
-
       colmena = {
         meta = {
           nixpkgs = import unstable { inherit system; overlays = [ (import ./overlays) ]; };
diff --git a/modules/README.md b/modules/README.md
deleted file mode 100644
index 25031dc..0000000
--- a/modules/README.md
+++ /dev/null
@@ -1,9 +0,0 @@
-infra->modules
-==============
-
-This is all the modules used to configure our systems based on its purposes.
-
-As of now, it doesn't have any clear "naming convention", but generally it's
-`<servicename>` for a module configuring one thing, `<capability>` otherwise.
-
-e.g) `dendrite` -> `dendrite`, `prometheus`, `grafana` -> `metrics`
diff --git a/modules/cachix/caches/nix-community.nix b/modules/cachix/caches/nix-community.nix
deleted file mode 100644
index d323939..0000000
--- a/modules/cachix/caches/nix-community.nix
+++ /dev/null
@@ -1,12 +0,0 @@
-{ config, lib, ... }:
-
-{
-  nix.settings = {
-    substituters = [
-      "https://nix-community.cachix.org"
-    ];
-    trusted-public-keys = [
-      "nix-community.cachix.org-1:mB9FSh9qf2dCimDSUo8Zy7bkq5CX+/rkCWyvRCYg3Fs="
-    ];
-  };
-}
diff --git a/modules/cachix/default.nix b/modules/cachix/default.nix
deleted file mode 100644
index 5222457..0000000
--- a/modules/cachix/default.nix
+++ /dev/null
@@ -1,23 +0,0 @@
-{ config, pkgs, lib, ... }:
-
-with lib;
-let
-  cfg = config.modules.cachix;
-
-  folder = ./caches;
-  toImport = name: value: folder + ("/" + name);
-  filterCaches = key: value: value == "regular" && lib.hasSuffix ".nix" key;
-  imports = lib.mapAttrsToList toImport (lib.filterAttrs filterCaches (builtins.readDir folder));
-in
-{
-  inherit imports;
-
-  options.modules.cachix = {
-    enable = mkEnableOption "cachix";
-  };
-
-  config = mkIf cfg.enable {
-    nix.settings.substituters = [ "https://cache.nixos.org/" ];
-    environment.systemPackages = [ pkgs.cachix ];
-  };
-}
diff --git a/modules/flakes.nix b/modules/flakes.nix
deleted file mode 100644
index 4297fda..0000000
--- a/modules/flakes.nix
+++ /dev/null
@@ -1,36 +0,0 @@
-{ config, inputs, pkgs, lib, ... }:
-
-with lib;
-let
-  base = "/etc/nixpkgs/channels";
-  nixpkgsPath = "${base}/nixpkgs";
-  nixpkgsSmallPath = "${base}/nixpkgsSmall";
-  nixpkgs2111Path = "${base}/nixpkgs2111";
-in
-{
-  options.nix.flakes.enable = mkEnableOption "nix flakes";
-
-  config = lib.mkIf config.nix.flakes.enable {
-    nix = {
-      package = pkgs.nixUnstable;
-      experimentalFeatures = "nix-command flakes";
-
-      registry.nixpkgs.flake = inputs.unstable;
-      registry.nixpkgsSmall.flake = inputs.unstable-small;
-      registry.nixpkgs2111.flake = inputs.nixpkgs-2111;
-
-      nixPath = [
-        "nixpkgs=${nixpkgsPath}"
-        "nixpkgsSmall=${nixpkgsSmallPath}"
-        "nixpkgs2111=${nixpkgs2111Path}"
-        "/nix/var/nix/profiles/per-user/root/channels"
-      ];
-    };
-
-    systemd.tmpfiles.rules = [
-      "L+ ${nixpkgsPath}      - - - - ${inputs.unstable}"
-      "L+ ${nixpkgsSmallPath} - - - - ${inputs.unstable-small}"
-      "L+ ${nixpkgs2111Path}  - - - - ${inputs.nixpkgs-2111}"
-    ];
-  };
-}
diff --git a/modules/nix.nix b/modules/nix.nix
deleted file mode 100644
index 8396739..0000000
--- a/modules/nix.nix
+++ /dev/null
@@ -1,34 +0,0 @@
-{ config, lib, ... }:
-
-let
-  allowed = config.nix.allowedUnfree;
-in
-{
-  options.nix = {
-    experimentalFeatures = lib.mkOption {
-      type = lib.types.separatedString " ";
-      default = "";
-      description = ''
-        Enables experimental features
-      '';
-    };
-
-    allowedUnfree = lib.mkOption {
-      type = lib.types.listOf lib.types.str;
-      default = [ ];
-      description = ''
-        Allows for  unfree packages by their name.
-      '';
-    };
-  };
-
-  config = lib.mkMerge [
-    (lib.mkIf (config.nix.experimentalFeatures != "") { nix.extraOptions = "experimental-features = ${config.nix.experimentalFeatures}"; })
-    (lib.mkIf (allowed != [ ]) { nixpkgs.config.allowUnfreePredicate = (pkg: __elem (lib.getName pkg) allowed); })
-    { nix.settings.auto-optimise-store = lib.mkDefault true; }
-    {
-      nix.gc.automatic = lib.mkDefault true;
-      nix.gc.options = lib.mkDefault "--delete-older-than 10d";
-    }
-  ];
-}
diff --git a/modules/persistence.nix b/modules/persistence.nix
deleted file mode 100644
index e7a8e90..0000000
--- a/modules/persistence.nix
+++ /dev/null
@@ -1,47 +0,0 @@
-{ config, inputs, lib, ... }:
-
-
-with lib;
-let
-  cfg = config.modules.persistence;
-in
-{
-  imports = [
-    inputs.impermanence.nixosModules.impermanence
-  ];
-
-  options.modules.persistence = {
-    enable = mkEnableOption "impermanence persistence";
-
-    storagePath = lib.mkOption {
-      type = types.path;
-      description = ''
-        The path to persistent storage where the real
-        files and directories should be stored.
-      '';
-    };
-
-    directories = mkOption {
-      type = types.listOf types.str;
-      default = [ ];
-    };
-  };
-
-  config = mkIf cfg.enable {
-    fileSystems.${cfg.storagePath}.neededForBoot = true;
-
-    environment.persistence.${cfg.storagePath}.directories = cfg.directories;
-
-    services.openssh.hostKeys = [
-      {
-        path = "${cfg.storagePath}/ssh/ssh_host_ed25519_key";
-        type = "ed25519";
-      }
-      {
-        path = "${cfg.storagePath}/ssh/ssh_host_rsa_key";
-        type = "rsa";
-        bits = 4096;
-      }
-    ];
-  };
-}
diff --git a/modules/security.nix b/modules/security.nix
deleted file mode 100644
index d345757..0000000
--- a/modules/security.nix
+++ /dev/null
@@ -1,69 +0,0 @@
-{ config, lib, ... }:
-
-with lib;
-let
-  cfg = config.modules.security;
-in
-{
-  options.modules.security = {
-    enable = mkEnableOption "Security-related system tweaks";
-  };
-
-  config = mkIf cfg.enable {
-    # Security-related system tweaks
-
-    # Prevent replacing the running kernel without reboot.
-    security.protectKernelImage = true;
-
-    # mount /tmp in ram. This makes temp file management faster
-    # on ssd systems, and volatile! Because it's wiped on reboot.
-    boot.tmp.useTmpfs = false;
-    boot.tmp.tmpfsSize = "80%";
-
-    # Purge /tmp on boot. (fallback option)
-    boot.tmp.cleanOnBoot = lib.mkDefault (!config.boot.tmp.useTmpfs);
-
-    boot.kernel.sysctl = {
-      # The Magic SysRq key is a key combo that allows users connected to the
-      # system console of a Linux kernel to perform some low-level commands.
-      # Disable it, since we don't need it, and is a potential security concern.
-      "kernel.sysrq" = 0;
-
-      ## TCP hardening
-      # Prevent bogus ICMP errors from filling up logs.
-      "net.ipv4.icmp_ignore_bogus_error_responses" = 1;
-      # Reverse path filtering causes the kernel to do source validation of
-      # packets received from all interfaces. This can mitigate IP spoofing.
-      "net.ipv4.conf.default.rp_filter" = 1;
-      "net.ipv4.conf.all.rp_filter" = 1;
-      # Do not accept IP source route packets (we're not a router)
-      "net.ipv4.conf.all.accept_source_route" = 0;
-      "net.ipv6.conf.all.accept_source_route" = 0;
-      # Don't send ICMP redirects (again, we're on a router)
-      "net.ipv4.conf.all.send_redirects" = 0;
-      "net.ipv4.conf.default.send_redirects" = 0;
-      # Refuse ICMP redirects (MITM mitigations)
-      "net.ipv4.conf.all.accept_redirects" = 0;
-      "net.ipv4.conf.default.accept_redirects" = 0;
-      "net.ipv4.conf.all.secure_redirects" = 0;
-      "net.ipv4.conf.default.secure_redirects" = 0;
-      "net.ipv6.conf.all.accept_redirects" = 0;
-      "net.ipv6.conf.default.accept_redirects" = 0;
-      # Protects against SYN flood attacks
-      "net.ipv4.tcp_syncookies" = 1;
-      # Incomplete protection again TIME-WAIT assassination
-      "net.ipv4.tcp_rfc1337" = 1;
-
-      ## TCP optimization
-      # TCP Fast Open is a TCP extension that reduces network latency by packing
-      # data in the sender’s initial TCP SYN. Setting 3 = enable TCP Fast Open for
-      # both incoming and outgoing connections:
-      "net.ipv4.tcp_fastopen" = 3;
-      # Bufferbloat mitigations + slight improvement in throughput & latency
-      "net.ipv4.tcp_congestion_control" = "bbr";
-      "net.core.default_qdisc" = "cake";
-    };
-
-    boot.kernelModules = [ "tcp_bbr" ];
-  };
-}
diff --git a/modules/services/_template.nix b/modules/services/_template.nix
deleted file mode 100644
index 26634a4..0000000
--- a/modules/services/_template.nix
+++ /dev/null
@@ -1,13 +0,0 @@
-{ config, lib, ... }:
-
-with lib;
-let
-  cfg = config.modules.services._template;
-in
-{
-  options.modules.services._template = {
-    enable = mkEnableOption "";
-  };
-
-  config = mkIf cfg.enable { };
-}
diff --git a/modules/services/acme.nix b/modules/services/acme.nix
deleted file mode 100644
index b3ebb26..0000000
--- a/modules/services/acme.nix
+++ /dev/null
@@ -1,52 +0,0 @@
-{ config, lib, ... }:
-
-with lib;
-let
-  cfg = config.modules.services.acme;
-in
-{
-  options.modules.services.acme = {
-    enable = mkEnableOption "ACME certificate manager";
-    email = mkOption {
-      type = types.str;
-      description = mdDoc ''
-        The postmaster email address to use.
-      '';
-    };
-    certs = mkOption {
-      type = types.attrsOf
-        (types.submodule {
-          options = {
-            domain = mkOption {
-              type = types.nullOr types.str;
-              default = null;
-            };
-            subDomains = mkOption { type = types.listOf types.str; };
-          };
-        });
-    };
-    secrets.acme-credentials = mkOption { type = types.str; description = "path to the acme environment file"; };
-  };
-
-  config = mkIf cfg.enable {
-    security.acme = {
-      acceptTerms = true;
-      defaults.email = cfg.email;
-      certs = mapAttrs
-        (name: { domain, subDomains }: {
-          extraDomainNames = lists.forEach subDomains (elem: elem + ".${name}");
-        } // {
-          dnsProvider = "cloudflare";
-          dnsPropagationCheck = true;
-          credentialsFile = cfg.secrets.acme-credentials;
-        } // optionalAttrs (domain != null) {
-          domain = domain;
-        })
-        cfg.certs;
-    };
-
-    modules.persistence.directories = [
-      "/var/lib/acme"
-    ];
-  };
-}
diff --git a/modules/services/akkoma/blocklist.toml b/modules/services/akkoma/blocklist.toml
deleted file mode 100644
index d8f53af..0000000
--- a/modules/services/akkoma/blocklist.toml
+++ /dev/null
@@ -1,164 +0,0 @@
-[followers_only]
-
-[media_nsfw]
-
-[reject]
-"*.tk" = "Free TLD"
-"*.ml" = "Free TLD"
-"*.ga" = "Free TLD"
-"*.cf" = "Free TLD"
-"*.gq" = "Free TLD"
-# Reject list from chaos.social at 2023-02-06
-"activitypub-proxy.cf" = "Only exists to evade instance blocks, details"
-"activitypub-troll.cf" = "Spam"
-"aethy.com" = "Lolicon"
-"bae.st" = "Discrimination, racism, “free speech zone”"
-"baraag.net" = "Lolicon"
-"banepo.st" = "Homophobia"
-"beefyboys.club" = "Discrimination, racism, “free speech zone”"
-"beefyboys.win" = "Discrimination, racism, “free speech zone”"
-"beta.birdsite.live" = "Twitter crossposter"
-"birb.elfenban.de" = "Twitter crossposter"
-"bird.evilcyberhacker.net" = "Twitter crossposter"
-"bird.froth.zone" = "Twitter crossposter"
-"bird.geiger.ee" = "Twitter crossposter"
-"bird.im-in.space" = "Twitter crossposter"
-"bird.istheguy.com" = "Twitter crossposter"
-"bird.karatek.net" = "Twitter crossposter"
-"bird.makeup" = "Twitter crossposter"
-"bird.nzbr.de" = "Twitter crossposter"
-"bird.r669.live" = "Twitter crossposter"
-"bird.seafoam.space" = "Twitter crossposter"
-"birdbots.leptonics.com" = "Twitter crossposter"
-"birdsite.b93.dece.space" = "Twitter crossposter"
-"birdsite.blazelights.dev" = "Twitter crossposter"
-"birdsite.frog.fashion" = "Twitter crossposter"
-"birdsite.gabeappleton.me" = "Twitter crossposter"
-"birdsite.james.moody.name" = "Twitter crossposter"
-"birdsite.koyu.space" = "Twitter crossposter"
-"birdsite.lakedrops.com" = "Twitter crossposter"
-"birdsite.link" = "Twitter crossposter"
-"birdsite.monster" = "Twitter crossposter"
-"birdsite.oliviaappleton.com" = "Twitter crossposter"
-"birdsite.platypush.tech" = "Twitter crossposter"
-"birdsite.slashdev.space" = "Twitter crossposter"
-"birdsite.tcjc.uk" = "Twitter crossposter"
-"birdsite.thorlaksson.com" = "Twitter crossposter"
-"birdsite.toot.si" = "Twitter crossposter"
-"birdsite.wilde.cloud" = "Twitter crossposter"
-"birdsitelive.ffvo.dev" = "Twitter crossposter"
-"birdsitelive.kevinyank.com" = "Twitter crossposter"
-"birdsitelive.peanutlasko.com" = "Twitter crossposter"
-"birdsitelive.treffler.cloud" = "Twitter crossposter"
-"bridge.birb.space" = "Twitter crossposter"
-"brighteon.social" = "“free speech zone”"
-"cawfee.club" = "Discrimination, racism, “free speech zone”"
-"childpawn.shop" = "Pedophilia"
-"chudbuds.lol" = "Discrimination, racism, “free speech zone”"
-"club.darknight-coffee.eu" = "“free speech zone”"
-"clubcyberia.co" = "Homophobia"
-"clube.social" = "Harassment"
-"comfyboy.club" = "Discrimination, racism"
-"cum.camp" = "Harassment"
-"cum.salon" = "Misogynic, pedophilia"
-"daishouri.moe" = "Fascism, openly advertises with swastika"
-"detroitriotcity.com" = "Discrimination, racism, “free speech zone”"
-"eientei.org" = "Racism, antisemitism"
-"eveningzoo.club" = "Discrimination, racism, “free speech zone”"
-"f.haeder.net" = "Discrimination"
-"freak.university" = "Pedophilia"
-"freeatlantis.com" = "Conspiracy theory instance"
-"freecumextremist.com" = "Discrimination, racism, “free speech zone”"
-"freefedifollowers.ga" = "Follower spam"
-"freespeechextremist.com" = "Discrimination, racism, “free speech zone”"
-"frennet.link" = "Discrimination, racism, “free speech zone”"
-"froth.zone" = "Calls freespeechextremist their local bubble"
-"gab.com/.ai, develop.gab.com" = "Discrimination, racism, “free speech zone”"
-"gameliberty.club" = "“free speech zone”"
-"gegenstimme.tv" = "“free speech zone”"
-"genderheretics.xyz" = "Tagline “Now With 41% More Misgendering!”"
-"gitmo.life" = "“free speech zone”"
-"gleasonator.com" = "Transphobia, TERFs"
-"glindr.org" = "Discrimination"
-"glowers.club" = "Discrimination, racism, “free speech zone”"
-"honkwerx.tech" = "Racism"
-"iamterminally.online" = "Discrimination, racism, “free speech zone”"
-"iddqd.social" = "Discrimination, racism, “free speech zone”"
-"itmslaves.com" = "“free speech zone”, noagenda affiliated"
-"jaeger.website" = "Discrimination, racism, “free speech zone”"
-"kenfm.quadplay.tv" = "Conspiracy videos"
-"kiwifarms.cc" = "Discrimination"
-"lgbtfree.zone" = "Racism, transphobia, all that"
-"liberdon.com" = "Conspiracy theories, transphobia, racism"
-"libre.tube" = "Promotion of violence and murder, multiple other violations of our rules"
-"lolicon.rocks" = "Lolicon"
-"lolison.top" = "Lolicon, paedophilia"
-"mastinator.com" = "Block evasion, unwanted profile mirroring, and more"
-"mastodon.network" = "Instance went down, now porn spam"
-"mastodon.popps.org" = "Homophobia"
-"mastodong.lol" = "Admin maintains and runs activitypub-proxy.cf"
-"meta-tube.de" = "Conspiracy, CoVid19 denier videos https://fediblock.org/blocklist/#meta-tube.de"
-"midnightride.rs" = "Discrimination"
-"misskey-forkbomb.cf" = "Spam"
-"morale.ch" = "Antisemitism and more"
-"mstdn.foxfam.club" = "Right wing twitter mirror"
-"natehiggers.online" = "Racism"
-"newjack.city" = "Exclusive to unwanted follow bots"
-"nicecrew.digital" = "Discrimination, racism, “free speech zone”"
-"noagendasocial.com" = "“free speech zone”, harassment"
-"noagendasocial.nl" = "“free speech zone”, harassment"
-"noagendatube.com" = "“free speech zone”, harassment"
-"ns.auction" = "Racism etc"
-"ohai.su" = "Offline"
-"pawoo.net" = "Untagged nfsw content, unwanted follow bots, lolicon"
-"paypig.org" = "Racism"
-"pieville.net" = "Racism, antisemitism"
-"pl.serialmay.link" = "Racism, transphobia"
-"pl.tkammer.de" = "Transphobia"
-"play.xmr.101010.pl" = "Cryptomining"
-"pleroma.kitsunemimi.club" = "Discrimination"
-"pleroma.narrativerry.xyz" = "Discrimination, racism, “free speech zone”"
-"pleroma.nobodyhasthe.biz" = "Doxxing and discrimination"
-"pleroma.rareome.ga" = "Doesn’t respect blocks or status privacy, lolicons"
-"poa.st" = "Discrimination"
-"podcastindex.social" = "noagenda affiliated"
-"poster.place" = "Discrimination, racism, “free speech zone”, harassment in response to blocks"
-"qoto.org" = "“free speech zone”, harassment"
-"rapemeat.solutions" = "Lolicon and also, like, the domain name"
-"rdrama.cc" = "Discrimination, “free speech zone”, racism"
-"repl.co" = "Spam"
-"rojogato.com" = "Harassment, “free speech zone”"
-"ryona.agency" = "Alt-right trolls, harassment"
-"seal.cafe" = "Discrimination, racism, “free speech zone”"
-"shitpost.cloud" = "“Free speech zone”, antisemitism"
-"shitposter.club" = "“Free speech zone”"
-"shortstackran.ch" = "Racism, homophobia, “free speech zone”"
-"shota.house" = "Lolicon"
-"skippers-bin.com" = "Same admin as neckbeard.xyz, same behaviour"
-"sleepy.cafe" = "Racism, harassment"
-"sneak.berlin" = "privacy violation"
-"sneed.social" = "Discrimination, racism, “free speech zone”, nationalism, hate speech, completely unmoderated"
-"soc.ua-fediland.de" = "Spam"
-"social.ancreport.com" = "Discrimination, racism, “free speech zone”"
-"social.lovingexpressions.net" = "Transphobia"
-"social.teci.world" = "Discrimination, racism, “free speech zone”"
-"social.urspringer.de" = "Conspiracy, CoVid19 denier"
-"socnet.supes.com" = "Right wing “free speech zone”"
-"solagg.com" = "Scammers"
-"spinster.xyz" = "Discrimination, TERFs"
-"tastingtraffic.net" = "Homophobia"
-"truthsocial.co.in" = "Alt-right trolls"
-"tube.kenfm.de" = "Right-wing conspiracy videos"
-"tube.querdenken-711.de" = "Right-wing onspiracy videos"
-"tweet.pasture.moe" = "Twitter crossposter"
-"tweetbridge.kogasa.de" = "Twitter crossposter"
-"tweets.icu" = "Twitter crossposter"
-"twitter.activitypub.actor" = "Twitter crossposter"
-"twitter.doesnotexist.club" = "Twitter crossposter"
-"twitterbridge.jannis.rocks" = "Twitter crossposter"
-"twtr.plus" = "Twitter crossposter"
-"varishangout.net" = "Transphobia and racism go unmoderated, aggressive trolling, lolicon permitted in rules"
-"wiki-tube.de" = "Right-wing conspiracy videos (initial video welcomes Querdenken and KenFM)"
-"wolfgirl.bar" = "Discrimination, homophobia, unmoderated trolling"
-"yggdrasil.social" = "Instance rules: “No LGBTQ. Period. No homosexuality. No men who think they’re women or women who think they’re men. No made up genders.”"
-"hornyjail.pro" = "Obscene speech without content warning"
diff --git a/modules/services/akkoma/default.nix b/modules/services/akkoma/default.nix
deleted file mode 100644
index 91aa2e8..0000000
--- a/modules/services/akkoma/default.nix
+++ /dev/null
@@ -1,102 +0,0 @@
-{ config, lib, pkgs, ... }:
-
-with lib;
-let
-  cfg = config.modules.services.akkoma;
-
-  poorObfuscation = y: x: "${x}@${y}";
-  federation-blocklist = lib.importTOML ./blocklist.toml;
-
-  inherit (lib.my) wrapFile;
-in
-{
-  options.modules.services.akkoma = {
-    enable = mkEnableOption "Akkoma instance";
-    domain = mkOption { type = types.str; };
-    realHost = mkOption { type = types.str; };
-    instanceName = mkOption { type = types.str; default = "Akkoma on ${cfg.domain}"; };
-  };
-
-  config = mkIf cfg.enable {
-    modules.services.postgresql.enable = true;
-
-    services.akkoma = {
-      enable = true;
-      initDb.enable = true;
-
-      extraStatic = {
-        "static/terms-of-service.html" = wrapFile "terms-of-service.html" ./terms-of-service.html;
-        "static/logo.svg" = wrapFile "logo.svg" ./logo.svg;
-        "static/logo.png" = wrapFile "logo.png" ./logo.png;
-        "static/logo-512.png" = wrapFile "logo-512.png" ./favicon-withbg.png; # Intentional, for PWA favicon.
-        "static/icon.png" = wrapFile "icon.png" ./favicon.png;
-        "favicon.png" = wrapFile "favicon.png" ./favicon-withbg.png;
-      };
-      config =
-        let inherit ((pkgs.formats.elixirConf { }).lib) mkRaw mkMap;
-        in {
-          ":pleroma"."Pleroma.Web.Endpoint".url.host = cfg.realHost;
-          ":pleroma"."Pleroma.Web.WebFinger".domain = cfg.domain;
-          ":pleroma".":media_proxy".enabled = false;
-          ":pleroma".":instance" = {
-            name = cfg.instanceName;
-
-            description = "Private akkoma instance";
-            email = poorObfuscation cfg.domain "postmaster";
-            notify_email = poorObfuscation cfg.domain "postmaster";
-
-            registrations_open = false;
-            invites_enabled = true;
-
-            limit = 5000;
-          };
-          ":pleroma".":frontend_configurations" = {
-            pleroma_fe = mkMap {
-              logo = "/static/logo.png";
-            };
-          };
-          ":pleroma".":mrf" = {
-            policies = map mkRaw [ "Pleroma.Web.ActivityPub.MRF.SimplePolicy" ];
-          };
-          ":pleroma".":mrf_simple" = {
-            followers_only = mkMap federation-blocklist.followers_only;
-            media_nsfw = mkMap federation-blocklist.media_nsfw;
-            reject = mkMap federation-blocklist.reject;
-          };
-          ":pleroma"."Pleroma.Captcha" = {
-            enabled = true;
-            method = mkRaw "Pleroma.Captcha.Kocaptcha";
-          };
-        };
-
-      nginx = {
-        forceSSL = true;
-        useACMEHost = cfg.domain;
-
-        locations."~ \\.(js|css|woff|woff2?|png|jpe?g|svg)$" = {
-          extraConfig = ''
-            add_header Cache-Control "public, max-age=14400, must-revalidate";
-          '';
-
-          proxyPass = "http://unix:${config.services.akkoma.config.":pleroma"."Pleroma.Web.Endpoint".http.ip}";
-          proxyWebsockets = true;
-          recommendedProxySettings = true;
-        };
-      };
-    };
-
-    services.nginx.virtualHosts.${cfg.domain} = {
-      forceSSL = true;
-      useACMEHost = cfg.domain;
-
-      locations."/.well-known/host-meta" = {
-        extraConfig = ''
-          return 301 https://${cfg.realHost}$request_uri;
-        '';
-      };
-    };
-    modules.persistence.directories = [
-      "/var/lib/akkoma"
-    ];
-  };
-}
diff --git a/modules/services/akkoma/favicon-withbg.png b/modules/services/akkoma/favicon-withbg.png
deleted file mode 100644
index f9595ce..0000000
--- a/modules/services/akkoma/favicon-withbg.png
+++ /dev/null
Binary files differdiff --git a/modules/services/akkoma/favicon.png b/modules/services/akkoma/favicon.png
deleted file mode 100644
index d8cbce3..0000000
--- a/modules/services/akkoma/favicon.png
+++ /dev/null
Binary files differdiff --git a/modules/services/akkoma/logo.png b/modules/services/akkoma/logo.png
deleted file mode 100644
index 7744b1a..0000000
--- a/modules/services/akkoma/logo.png
+++ /dev/null
Binary files differdiff --git a/modules/services/akkoma/logo.svg b/modules/services/akkoma/logo.svg
deleted file mode 100644
index 68e647e..0000000
--- a/modules/services/akkoma/logo.svg
+++ /dev/null
@@ -1,71 +0,0 @@
-<?xml version="1.0" encoding="UTF-8" standalone="no"?>
-<svg
-   xmlns:dc="http://purl.org/dc/elements/1.1/"
-   xmlns:cc="http://creativecommons.org/ns#"
-   xmlns:rdf="http://www.w3.org/1999/02/22-rdf-syntax-ns#"
-   xmlns:svg="http://www.w3.org/2000/svg"
-   xmlns="http://www.w3.org/2000/svg"
-   xmlns:sodipodi="http://sodipodi.sourceforge.net/DTD/sodipodi-0.dtd"
-   xmlns:inkscape="http://www.inkscape.org/namespaces/inkscape"
-   version="1.1"
-   id="svg4485"
-   width="512"
-   height="512"
-   viewBox="0 0 512 512"
-   sodipodi:docname="logo.svg"
-   inkscape:version="1.0.1 (3bc2e813f5, 2020-09-07)">
-  <metadata
-     id="metadata4491">
-    <rdf:RDF>
-      <cc:Work
-         rdf:about="">
-        <dc:format>image/svg+xml</dc:format>
-        <dc:type
-           rdf:resource="http://purl.org/dc/dcmitype/StillImage" />
-        <dc:title />
-      </cc:Work>
-    </rdf:RDF>
-  </metadata>
-  <defs
-     id="defs4489" />
-  <sodipodi:namedview
-     pagecolor="#ffffff"
-     bordercolor="#666666"
-     borderopacity="1"
-     objecttolerance="10"
-     gridtolerance="10"
-     guidetolerance="10"
-     inkscape:pageopacity="0"
-     inkscape:pageshadow="2"
-     inkscape:window-width="1274"
-     inkscape:window-height="1410"
-     id="namedview4487"
-     showgrid="false"
-     inkscape:zoom="1.2636719"
-     inkscape:cx="305.99333"
-     inkscape:cy="304.30809"
-     inkscape:window-x="1280"
-     inkscape:window-y="22"
-     inkscape:window-maximized="0"
-     inkscape:current-layer="g4612"
-     inkscape:document-rotation="0" />
-  <g
-     id="g4612">
-    <g
-       id="g850"
-       transform="matrix(0.99659595,0,0,0.99659595,0.37313949,0.87143746)">
-      <path
-         style="opacity:1;fill:#fba457;fill-opacity:1;stroke:#009bff;stroke-width:0;stroke-linecap:round;stroke-miterlimit:4;stroke-dasharray:none;stroke-opacity:0.175879"
-         d="m 194.75841,124.65165 a 20.449443,20.449443 0 0 0 -20.44944,20.44945 v 242.24725 h 65.28091 v -262.6967 z"
-         id="path4497" />
-      <path
-         style="fill:#fba457;fill-opacity:1;stroke:#000000;stroke-width:0;stroke-linecap:butt;stroke-linejoin:miter;stroke-miterlimit:4;stroke-dasharray:none;stroke-opacity:1"
-         d="M 272.6236,124.65165 V 256 h 45.61799 a 20.449443,20.449443 0 0 0 20.44944,-20.44945 v -110.8989 z"
-         id="path4516" />
-      <path
-         style="opacity:1;fill:#fba457;fill-opacity:1;stroke:#000000;stroke-width:0;stroke-linecap:butt;stroke-linejoin:miter;stroke-miterlimit:4;stroke-dasharray:none;stroke-opacity:1"
-         d="m 272.6236,322.06744 v 65.28091 h 45.61799 a 20.449443,20.449443 0 0 0 20.44944,-20.44945 v -44.83146 z"
-         id="path4516-5" />
-    </g>
-  </g>
-</svg>
diff --git a/modules/services/akkoma/robots.txt b/modules/services/akkoma/robots.txt
deleted file mode 100644
index 1f53798..0000000
--- a/modules/services/akkoma/robots.txt
+++ /dev/null
@@ -1,2 +0,0 @@
-User-agent: *
-Disallow: /
diff --git a/modules/services/akkoma/terms-of-service.html b/modules/services/akkoma/terms-of-service.html
deleted file mode 100644
index 33c7ff3..0000000
--- a/modules/services/akkoma/terms-of-service.html
+++ /dev/null
@@ -1,26 +0,0 @@
-<!DOCTYPE html>
-<html>
-  <head></head>
-  <body>
-    <h2>Terms of Service</h2>
-    <p>This is a private instance with only me and my friends. Here's the rules:</p>
-    <ol>
-      <li>
-        <p>No discrimination based on race, gender, sexual orientation, disabilities, or any other characteristic.</p>
-      </li>
-      <li>
-        <p>No harassment or doxxing towards others.</p>
-      </li>
-      <li>
-        <p>No promotion of violence.</p>
-      </li>
-      <li>
-        <p>No content that is illegal in United Kingdom, Japan, Finland, Germany, and South Korea.</p>
-      </li>
-      <li>
-        <p>Use content warnings for explicit or controversial content.</p>
-      </li>
-    </ol>
-    <p>Any account that doesn't abide by the rules specified above will be terminated without prior notice.</p>
-  </body>
-</html>
diff --git a/modules/services/authentik.nix b/modules/services/authentik.nix
deleted file mode 100644
index 10241b9..0000000
--- a/modules/services/authentik.nix
+++ /dev/null
@@ -1,69 +0,0 @@
-{ inputs, config, lib, ... }:
-
-with lib;
-let
-  cfg = config.modules.services.authentik;
-in
-{
-  imports = [ inputs.authentik-nix.nixosModules.default ];
-
-  options.modules.services.authentik = {
-    enable = mkEnableOption "Authentik - Identity Provider";
-    domain = mkOption { type = types.str; };
-    realHost = mkOption { type = types.str; default = "authentik.${cfg.domain}"; };
-    email = {
-      host = mkOption { type = types.str; default = "smtp.${cfg.domain}"; };
-      username = mkOption { type = types.str; default = "authentik@${cfg.domain}"; };
-      from = mkOption { type = types.str; default = cfg.email.username; };
-    };
-    secrets = {
-       authentik-envs = mkOption { type = types.path; description = "path to the environment file"; };
-    };
-  };
-
-  config = mkIf cfg.enable {
-    services.authentik = {
-      enable = true;
-
-      environmentFile = cfg.secrets.authentik-envs;
-
-      settings = {
-        email = {
-          host = cfg.email.host;
-          port = 587;
-          username = cfg.email.username;
-          use_tls = true;
-          use_ssl = false;
-          from = cfg.email.from;
-        };
-
-        cert_discovery_dir = "env://CREDENTIALS_DIRECTORY";
-      };
-      nginx = {
-        # This is configured manually since authentik-nix doesn't support
-        # cases where cert domain != nginx host
-        enable = false;
-        enableACME = false;
-        # host = cfg.realHost;
-      };
-    };
-
-    modules.persistence.directories = [
-      "/var/lib/private/authentik"
-    ];
-
-    systemd.services.authentik-worker.serviceConfig.LoadCredential = [
-      "${cfg.domain}.pem:${config.security.acme.certs.${cfg.domain}.directory}/fullchain.pem"
-      "${cfg.domain}.key:${config.security.acme.certs.${cfg.domain}.directory}/key.pem"
-    ];
-
-    services.nginx.virtualHosts.${cfg.realHost} = {
-      useACMEHost = cfg.domain;
-      forceSSL = true;
-      locations."/" = {
-        proxyWebsockets = true;
-        proxyPass = "https://localhost:9443";
-      };
-    };
-  };
-}
diff --git a/modules/services/backup.nix b/modules/services/backup.nix
deleted file mode 100644
index 9770b43..0000000
--- a/modules/services/backup.nix
+++ /dev/null
@@ -1,81 +0,0 @@
-{ config, lib, ... }:
-
-with lib;
-let
-  cfg = config.modules.services.backup;
-in
-{
-  options.modules.services.backup = {
-    enable = mkEnableOption "borg-based backup solution";
-    name = lib.mkOption {
-      type = lib.types.str;
-      default = "${config.networking.hostName}-rolling";
-      description = ''
-        Name of the backup job
-      '';
-    };
-
-    paths = lib.mkOption {
-      type = lib.types.listOf lib.types.str;
-      description = ''
-        Paths to back up
-      '';
-    };
-    exclude = lib.mkOption {
-      type = lib.types.listOf lib.types.str;
-      default = [ ];
-      description = ''
-        Paths to exclude
-      '';
-    };
-    repo = lib.mkOption {
-      type = lib.types.str;
-      description = ''
-        Path to the repository to back up to
-      '';
-    };
-    repoKeyPath = lib.mkOption {
-      type = lib.types.str;
-      description = ''
-        Path to the repository key
-      '';
-    };
-    sshKeyPath = lib.mkOption {
-      type = lib.types.str;
-      description = ''
-        Path to the ssh key
-      '';
-    };
-    rsyncNet = lib.mkOption {
-      type = lib.types.bool;
-      default = false;
-      description = ''
-        Whether to enable rsync.net specific patches
-      '';
-    };
-  };
-
-  config = mkIf cfg.enable {
-    services.borgbackup.jobs.${cfg.name} = {
-      inherit (cfg) paths exclude repo;
-
-      prune.keep = {
-        within = "1d"; # Keep all archives from the last day
-        daily = 7;
-        weekly = 4;
-        monthly = 3;
-      };
-
-      encryption.mode = "repokey-blake2";
-      encryption.passCommand = "cat ${cfg.repoKeyPath}";
-
-      environment.BORG_RSH = "ssh -i ${cfg.sshKeyPath}";
-      environment.BORG_REMOTE_PATH = lib.mkIf cfg.rsyncNet "/usr/local/bin/borg1/borg1";
-      # use borg 1.0+ on rsync.net
-      extraCreateArgs = "--verbose --stats --checkpoint-interval 600";
-      compression = "auto,zstd";
-      startAt = "*-*-* 03:00:00"; # pgsql backup runs on 01:15:00
-      persistentTimer = true;
-    };
-  };
-}
diff --git a/modules/services/cgit/cgit-exotic.css b/modules/services/cgit/cgit-exotic.css
deleted file mode 100644
index 32117c7..0000000
--- a/modules/services/cgit/cgit-exotic.css
+++ /dev/null
@@ -1,953 +0,0 @@
-div#cgit {
-	padding: 0em;
-	margin: 0em;
-	font-family: sans-serif;
-	font-size: 10pt;
-	color: #333;
-	background: white;
-	padding: 4px;
-}
-
-div#cgit a {
-	color: blue;
-	text-decoration: none;
-}
-
-div#cgit a:hover {
-	text-decoration: underline;
-}
-
-div#cgit table {
-	border-collapse: collapse;
-}
-
-div#cgit table#header {
-	width: 100%;
-	margin-bottom: 1em;
-}
-
-div#cgit table#header td.logo {
-	width: 96px;
-	vertical-align: top;
-}
-
-div#cgit table#header td.main {
-	font-size: 250%;
-	padding-left: 10px;
-	white-space: nowrap;
-}
-
-div#cgit table#header td.main a {
-	color: #000;
-}
-
-div#cgit table#header td.form {
-	text-align: right;
-	vertical-align: bottom;
-	padding-right: 1em;
-	padding-bottom: 2px;
-	white-space: nowrap;
-}
-
-div#cgit table#header td.form form,
-div#cgit table#header td.form input,
-div#cgit table#header td.form select {
-	font-size: 90%;
-}
-
-div#cgit table#header td.sub {
-	color: #777;
-	border-top: solid 1px #ccc;
-	padding-left: 10px;
-}
-
-div#cgit table.tabs {
-	border-bottom: solid 3px #ccc;
-	border-collapse: collapse;
-	margin-top: 2em;
-	margin-bottom: 0px;
-	width: 100%;
-}
-
-div#cgit table.tabs td {
-	padding: 0px 1em;
-	vertical-align: bottom;
-}
-
-div#cgit table.tabs td a {
-	padding: 2px 0.25em;
-	color: #777;
-	font-size: 110%;
-}
-
-div#cgit table.tabs td a.active {
-	color: #000;
-	background-color: #ccc;
-}
-
-div#cgit table.tabs a[href^="http://"]:after, div#cgit table.tabs a[href^="https://"]:after {
-	content: url(data:image/png;base64,iVBORw0KGgoAAAANSUhEUgAAAAoAAAAKCAQAAAAnOwc2AAAAAmJLR0QA/4ePzL8AAAAJcEhZcwAACxMAAAsTAQCanBgAAAAHdElNRQfgAhcJDQY+gm2TAAAAHWlUWHRDb21tZW50AAAAAABDcmVhdGVkIHdpdGggR0lNUGQuZQcAAABbSURBVAhbY2BABs4MU4CwhYHBh2Erww4wrGFQZHjI8B8IgUIscJWyDHcggltQhI4zGDCcRwhChPggHIggP1QoAVmQkSETrGoHsiAEsACtBYN0oDAMbgU6EBcAAL2eHUt4XUU4AAAAAElFTkSuQmCC);
-	opacity: 0.5;
-	margin: 0 0 0 5px;
-}
-
-div#cgit table.tabs td.form {
-	text-align: right;
-}
-
-div#cgit table.tabs td.form form {
-	padding-bottom: 2px;
-	font-size: 90%;
-	white-space: nowrap;
-}
-
-div#cgit table.tabs td.form input,
-div#cgit table.tabs td.form select {
-	font-size: 90%;
-}
-
-div#cgit div.path {
-	margin: 0px;
-	padding: 5px 2em 2px 2em;
-	color: #000;
-	background-color: #eee;
-}
-
-div#cgit div.content {
-	margin: 0px;
-	padding: 2em;
-	border-bottom: solid 3px #ccc;
-}
-
-
-div#cgit table.list {
-	width: 100%;
-	border: none;
-	border-collapse: collapse;
-}
-
-div#cgit table.list tr {
-	background: white;
-}
-
-div#cgit table.list tr.logheader {
-	background: #eee;
-}
-
-div#cgit table.list tr:nth-child(even) {
-	background: #f7f7f7;
-}
-
-div#cgit table.list tr:nth-child(odd) {
-	background: white;
-}
-
-div#cgit table.list tr:hover {
-	background: #eee;
-}
-
-div#cgit table.list tr.nohover {
-	background: white;
-}
-
-div#cgit table.list tr.nohover:hover {
-	background: white;
-}
-
-div#cgit table.list tr.nohover-highlight:hover:nth-child(even) {
-	background: #f7f7f7;
-}
-
-div#cgit table.list tr.nohover-highlight:hover:nth-child(odd) {
-	background: white;
-}
-
-div#cgit table.list th {
-	font-weight: bold;
-	/* color: #888;
-	border-top: dashed 1px #888;
-	border-bottom: dashed 1px #888;
-	*/
-	padding: 0.1em 0.5em 0.05em 0.5em;
-	vertical-align: baseline;
-}
-
-div#cgit table.list td {
-	border: none;
-	padding: 0.1em 0.5em 0.1em 0.5em;
-}
-
-div#cgit table.list td.commitgraph {
-	font-family: monospace;
-	white-space: pre;
-}
-
-div#cgit table.list td.commitgraph .column1 {
-	color: #a00;
-}
-
-div#cgit table.list td.commitgraph .column2 {
-	color: #0a0;
-}
-
-div#cgit table.list td.commitgraph .column3 {
-	color: #aa0;
-}
-
-div#cgit table.list td.commitgraph .column4 {
-	color: #00a;
-}
-
-div#cgit table.list td.commitgraph .column5 {
-	color: #a0a;
-}
-
-div#cgit table.list td.commitgraph .column6 {
-	color: #0aa;
-}
-
-div#cgit table.list td.logsubject {
-	font-family: monospace;
-	font-weight: bold;
-}
-
-div#cgit table.list td.logmsg {
-	font-family: monospace;
-	white-space: pre;
-	padding: 0 0.5em;
-}
-
-div#cgit table.list td a {
-	color: black;
-}
-
-div#cgit table.list td a.ls-dir {
-	font-weight: bold;
-	color: #00f;
-}
-
-div#cgit table.list td a:hover {
-	color: #00f;
-}
-
-div#cgit img {
-	border: none;
-}
-
-div#cgit input#switch-btn {
-	margin: 2px 0px 0px 0px;
-}
-
-div#cgit td#sidebar input.txt {
-	width: 100%;
-	margin: 2px 0px 0px 0px;
-}
-
-div#cgit table#grid {
-	margin: 0px;
-}
-
-div#cgit td#content {
-	vertical-align: top;
-	padding: 1em 2em 1em 1em;
-	border: none;
-}
-
-div#cgit div#summary {
-	vertical-align: top;
-	margin-bottom: 1em;
-}
-
-div#cgit table#downloads {
-	float: right;
-	border-collapse: collapse;
-	border: solid 1px #777;
-	margin-left: 0.5em;
-	margin-bottom: 0.5em;
-}
-
-div#cgit table#downloads th {
-	background-color: #ccc;
-}
-
-div#cgit div#blob {
-	border: solid 1px black;
-}
-
-div#cgit div.error {
-	color: red;
-	font-weight: bold;
-	margin: 1em 2em;
-}
-
-div#cgit a.ls-blob, div#cgit a.ls-dir, div#cgit .ls-mod {
-	font-family: monospace;
-}
-
-div#cgit td.ls-size {
-	text-align: right;
-	font-family: monospace;
-	width: 10em;
-}
-
-div#cgit td.ls-mode {
-	font-family: monospace;
-	width: 10em;
-}
-
-div#cgit table.blob {
-	margin-top: 0.5em;
-	border-top: solid 1px black;
-}
-
-div#cgit table.blob td.hashes,
-div#cgit table.blob td.lines {
-	margin: 0; padding: 0 0 0 0.5em;
-	vertical-align: top;
-	color: black;
-}
-
-div#cgit table.blob td.linenumbers {
-	margin: 0; padding: 0 0.5em 0 0.5em;
-	vertical-align: top;
-	text-align: right;
-	border-right: 1px solid gray;
-}
-
-div#cgit table.blob pre {
-	padding: 0; margin: 0;
-}
-
-div#cgit table.blob td.linenumbers a,
-div#cgit table.ssdiff td.lineno a {
-	color: gray;
-	text-align: right;
-	text-decoration: none;
-}
-
-div#cgit table.blob td.linenumbers a:hover,
-div#cgit table.ssdiff td.lineno a:hover {
-	color: black;
-}
-
-div#cgit table.blame td.hashes,
-div#cgit table.blame td.lines,
-div#cgit table.blame td.linenumbers {
-	padding: 0;
-}
-
-div#cgit table.blame td.hashes div.alt,
-div#cgit table.blame td.lines div.alt {
-	padding: 0 0.5em 0 0.5em;
-}
-
-div#cgit table.blame td.linenumbers div.alt {
-	padding: 0 0.5em 0 0;
-}
-
-div#cgit table.blame div.alt:nth-child(even) {
-	background: #eee;
-}
-
-div#cgit table.blame div.alt:nth-child(odd) {
-	background: white;
-}
-
-div#cgit table.blame td.lines > div {
-	position: relative;
-}
-
-div#cgit table.blame td.lines > div > pre {
-	padding: 0 0 0 0.5em;
-	position: absolute;
-	top: 0;
-}
-
-div#cgit table.blame .oid {
-	font-size: 100%;
-}
-
-div#cgit table.bin-blob {
-	margin-top: 0.5em;
-	border: solid 1px black;
-}
-
-div#cgit table.bin-blob th {
-	font-family: monospace;
-	white-space: pre;
-	border: solid 1px #777;
-	padding: 0.5em 1em;
-}
-
-div#cgit table.bin-blob td {
-	font-family: monospace;
-	white-space: pre;
-	border-left: solid 1px #777;
-	padding: 0em 1em;
-}
-
-div#cgit table.nowrap td {
-	white-space: nowrap;
-}
-
-div#cgit table.commit-info {
-	border-collapse: collapse;
-	margin-top: 1.5em;
-}
-
-div#cgit div.cgit-panel {
-	float: right;
-	margin-top: 1.5em;
-}
-
-div#cgit div.cgit-panel table {
-	border-collapse: collapse;
-	border: solid 1px #aaa;
-	background-color: #eee;
-}
-
-div#cgit div.cgit-panel th {
-	text-align: center;
-}
-
-div#cgit div.cgit-panel td {
-	padding: 0.25em 0.5em;
-}
-
-div#cgit div.cgit-panel td.label {
-	padding-right: 0.5em;
-}
-
-div#cgit div.cgit-panel td.ctrl {
-	padding-left: 0.5em;
-}
-
-div#cgit table.commit-info th {
-	text-align: left;
-	font-weight: normal;
-	padding: 0.1em 1em 0.1em 0.1em;
-	vertical-align: top;
-}
-
-div#cgit table.commit-info td {
-	font-weight: normal;
-	padding: 0.1em 1em 0.1em 0.1em;
-}
-
-div#cgit div.commit-subject {
-	font-weight: bold;
-	font-size: 125%;
-	margin: 1.5em 0em 0.5em 0em;
-	padding: 0em;
-}
-
-div#cgit div.notes-header {
-	font-weight: bold;
-	padding-top: 1.5em;
-}
-
-div#cgit div.notes {
-	white-space: pre;
-	font-family: monospace;
-	border: solid 1px #ee9;
-	background-color: #ffd;
-	padding: 0.3em 2em 0.3em 1em;
-	float: left;
-}
-
-div#cgit div.notes-footer {
-	clear: left;
-}
-
-div#cgit div.diffstat-header {
-	font-weight: bold;
-	padding-top: 1.5em;
-}
-
-div#cgit table.diffstat {
-	border-collapse: collapse;
-	border: solid 1px #aaa;
-	background-color: #eee;
-}
-
-div#cgit table.diffstat th {
-	font-weight: normal;
-	text-align: left;
-	text-decoration: underline;
-	padding: 0.1em 1em 0.1em 0.1em;
-	font-size: 100%;
-}
-
-div#cgit table.diffstat td {
-	padding: 0.2em 0.2em 0.1em 0.1em;
-	font-size: 100%;
-	border: none;
-}
-
-div#cgit table.diffstat td.mode {
-	white-space: nowrap;
-}
-
-div#cgit table.diffstat td span.modechange {
-	padding-left: 1em;
-	color: red;
-}
-
-div#cgit table.diffstat td.add a {
-	color: green;
-}
-
-div#cgit table.diffstat td.del a {
-	color: red;
-}
-
-div#cgit table.diffstat td.upd a {
-	color: blue;
-}
-
-div#cgit table.diffstat td.graph {
-	width: 500px;
-	vertical-align: middle;
-}
-
-div#cgit table.diffstat td.graph table {
-	border: none;
-}
-
-div#cgit table.diffstat td.graph td {
-	padding: 0px;
-	border: 0px;
-	height: 7pt;
-}
-
-div#cgit table.diffstat td.graph td.add {
-	background-color: #5c5;
-}
-
-div#cgit table.diffstat td.graph td.rem {
-	background-color: #c55;
-}
-
-div#cgit div.diffstat-summary {
-	color: #888;
-	padding-top: 0.5em;
-}
-
-div#cgit table.diff {
-	width: 100%;
-}
-
-div#cgit table.diff td span.head {
-	font-weight: bold;
-	color: black;
-}
-
-div#cgit table.diff td span.hunk {
-	color: #009;
-}
-
-div#cgit table.diff td span.add {
-	color: green;
-}
-
-div#cgit table.diff td span.del {
-	color: red;
-}
-
-div#cgit .oid {
-	font-family: monospace;
-	font-size: 90%;
-}
-
-div#cgit .left {
-	text-align: left;
-}
-
-div#cgit .right {
-	text-align: right;
-}
-
-div#cgit table.list td.reposection {
-	font-style: italic;
-	color: #888;
-}
-
-div#cgit a.button {
-	font-size: 80%;
-}
-
-div#cgit a.primary {
-	font-size: 100%;
-}
-
-div#cgit a.secondary {
-	font-size: 90%;
-}
-
-div#cgit td.toplevel-repo {
-
-}
-
-div#cgit table.list td.sublevel-repo {
-	padding-left: 1.5em;
-}
-
-div#cgit ul.pager {
-	list-style-type: none;
-	text-align: center;
-	margin: 1em 0em 0em 0em;
-	padding: 0;
-}
-
-div#cgit ul.pager li {
-	display: inline-block;
-	margin: 0.25em 0.5em;
-}
-
-div#cgit ul.pager a {
-	color: #777;
-}
-
-div#cgit ul.pager .current {
-	font-weight: bold;
-}
-
-div#cgit span.age-mins {
-	font-weight: bold;
-	color: #080;
-}
-
-div#cgit span.age-hours {
-	color: #080;
-}
-
-div#cgit span.age-days {
-	color: #040;
-}
-
-div#cgit span.age-weeks {
-	color: #444;
-}
-
-div#cgit span.age-months {
-	color: #888;
-}
-
-div#cgit span.age-years {
-	color: #bbb;
-}
-
-div#cgit span.insertions {
-	color: #080;
-}
-
-div#cgit span.deletions {
-	color: #800;
-}
-
-div#cgit div.footer {
-	margin-top: 0.5em;
-	text-align: center;
-	font-size: 80%;
-	color: #ccc;
-}
-
-div#cgit div.footer a {
-	color: #ccc;
-	text-decoration: none;
-}
-
-div#cgit div.footer a:hover {
-	text-decoration: underline;
-}
-
-div#cgit a.branch-deco {
-	color: #000;
-	padding: 0px 0.25em;
-	background-color: #88ff88;
-	border: solid 1px #007700;
-}
-
-div#cgit a.tag-deco {
-	color: #000;
-	padding: 0px 0.25em;
-	background-color: #ffff88;
-	border: solid 1px #777700;
-}
-
-div#cgit a.tag-annotated-deco {
-	color: #000;
-	padding: 0px 0.25em;
-	background-color: #ffcc88;
-	border: solid 1px #777700;
-}
-
-div#cgit a.remote-deco {
-	color: #000;
-	padding: 0px 0.25em;
-	background-color: #ccccff;
-	border: solid 1px #000077;
-}
-
-div#cgit a.deco {
-	color: #000;
-	padding: 0px 0.25em;
-	background-color: #ff8888;
-	border: solid 1px #770000;
-}
-
-div#cgit div.commit-subject a.branch-deco,
-div#cgit div.commit-subject a.tag-deco,
-div#cgit div.commit-subject a.tag-annotated-deco,
-div#cgit div.commit-subject a.remote-deco,
-div#cgit div.commit-subject a.deco {
-	font-size: 75%;
-}
-
-div#cgit table.stats {
-	border: solid 1px black;
-	border-collapse: collapse;
-}
-
-div#cgit table.stats th {
-	text-align: left;
-	padding: 1px 0.5em;
-	background-color: #eee;
-	border: solid 1px black;
-}
-
-div#cgit table.stats td {
-	text-align: right;
-	padding: 1px 0.5em;
-	border: solid 1px black;
-}
-
-div#cgit table.stats td.total {
-	font-weight: bold;
-	text-align: left;
-}
-
-div#cgit table.stats td.sum {
-	color: #c00;
-	font-weight: bold;
-/*	background-color: #eee; */
-}
-
-div#cgit table.stats td.left {
-	text-align: left;
-}
-
-div#cgit table.vgraph {
-	border-collapse: separate;
-	border: solid 1px black;
-	height: 200px;
-}
-
-div#cgit table.vgraph th {
-	background-color: #eee;
-	font-weight: bold;
-	border: solid 1px white;
-	padding: 1px 0.5em;
-}
-
-div#cgit table.vgraph td {
-	vertical-align: bottom;
-	padding: 0px 10px;
-}
-
-div#cgit table.vgraph div.bar {
-	background-color: #eee;
-}
-
-div#cgit table.hgraph {
-	border: solid 1px black;
-	width: 800px;
-}
-
-div#cgit table.hgraph th {
-	background-color: #eee;
-	font-weight: bold;
-	border: solid 1px black;
-	padding: 1px 0.5em;
-}
-
-div#cgit table.hgraph td {
-	vertical-align: middle;
-	padding: 2px 2px;
-}
-
-div#cgit table.hgraph div.bar {
-	background-color: #eee;
-	height: 1em;
-}
-
-div#cgit table.ssdiff {
-	width: 100%;
-}
-
-div#cgit table.ssdiff td {
-	font-size: 75%;
-	font-family: monospace;
-	white-space: pre;
-	padding: 1px 4px 1px 4px;
-	border-left: solid 1px #aaa;
-	border-right: solid 1px #aaa;
-}
-
-div#cgit table.ssdiff td.add {
-	color: black;
-	background: #cfc;
-	min-width: 50%;
-}
-
-div#cgit table.ssdiff td.add_dark {
-	color: black;
-	background: #aca;
-	min-width: 50%;
-}
-
-div#cgit table.ssdiff span.add {
-	background: #cfc;
-	font-weight: bold;
-}
-
-div#cgit table.ssdiff td.del {
-	color: black;
-	background: #fcc;
-	min-width: 50%;
-}
-
-div#cgit table.ssdiff td.del_dark {
-	color: black;
-	background: #caa;
-	min-width: 50%;
-}
-
-div#cgit table.ssdiff span.del {
-	background: #fcc;
-	font-weight: bold;
-}
-
-div#cgit table.ssdiff td.changed {
-	color: black;
-	background: #ffc;
-	min-width: 50%;
-}
-
-div#cgit table.ssdiff td.changed_dark {
-	color: black;
-	background: #cca;
-	min-width: 50%;
-}
-
-div#cgit table.ssdiff td.lineno {
-	color: black;
-	background: #eee;
-	text-align: right;
-	width: 3em;
-	min-width: 3em;
-}
-
-div#cgit table.ssdiff td.hunk {
-	color: black;
-	background: #ccf;
-	border-top: solid 1px #aaa;
-	border-bottom: solid 1px #aaa;
-}
-
-div#cgit table.ssdiff td.head {
-	border-top: solid 1px #aaa;
-	border-bottom: solid 1px #aaa;
-}
-
-div#cgit table.ssdiff td.head div.head {
-	font-weight: bold;
-	color: black;
-}
-
-div#cgit table.ssdiff td.foot {
-	border-top: solid 1px #aaa;
-	border-left: none;
-	border-right: none;
-	border-bottom: none;
-}
-
-div#cgit table.ssdiff td.space {
-	border: none;
-}
-
-div#cgit table.ssdiff td.space div {
-	min-height: 3em;
-}
-
-/*
- * BEGIN exotic.sh MODIFICATIONS
- */
-
-* { line-height: 1.25em; }
-
-div#cgit {
-	margin: auto;
-	font-family: monospace;
-	display: table;
-}
-
-div#cgit table#header td.logo {
-	display: none;
-}
-
-div#cgit table#header td.main {
-	font-size: 1.2em;
-	font-weight: bold;
-	/*padding-left: 10px;*/
-}
-
-div#cgit table#header td.sub {
-	border-top: none;
-}
-
-
-div#cgit table.tabs {
-	border-bottom: none;
-}
-
-
-div#cgit table.list th a {
-	color: inherit;
-}
-
-div#cgit table.list tr:nth-child(even) {
-	background: inherit;
-}
-
-div#cgit table.list tr:hover {
-  background: inherit;
-}
-div#cgit table.list tr.nohover-highlight:hover:nth-child(even) {
-  background: inherit;
-}
-
-div#cgit table.blob td.linenumbers:nth-last-child(3) {
-  display: none;
-}
-
-div#cgit div.content {
-	min-width: 60em;
-	border-bottom: none;
-}
-
-div#cgit div.content div#summary {
-	display: table;
-	margin-left: auto;
-	margin-right: auto;
-}
-
-div#cgit table.blob td.linenumbers a:target {
-  color: goldenrod;
-  text-decoration: underline;
-  outline: none;
-}
-
-div#cgit div.footer {
-	font-size: 1em;
-}
diff --git a/modules/services/cgit/default.nix b/modules/services/cgit/default.nix
deleted file mode 100644
index 7ee279f..0000000
--- a/modules/services/cgit/default.nix
+++ /dev/null
@@ -1,129 +0,0 @@
-{ config, lib, pkgs, ... }:
-
-with lib;
-let
-  cfg = config.modules.services.cgit;
-in
-{
-  options.modules.services.cgit = {
-    enable = mkEnableOption "cgit with uwsgi";
-
-    domain = mkOption { type = types.str; };
-    realHost = mkOption { type = types.str; };
-    # TODO: use generators & submodules
-    settings = {
-      title = mkOption { type = types.str; default = "${cfg.domain} git"; };
-      description = mkOption { type = types.str; default = "cgit, hyperfast web frontend for Git"; };
-    };
-  };
-  config = mkIf cfg.enable {
-
-    modules.services.nginx.enable = true;
-
-    services.uwsgi = {
-      enable = true;
-      user = "nginx";
-      group = "nginx";
-      plugins = [ "cgi" ];
-
-      instance = {
-        type = "emperor";
-        vassals = {
-          cgit = {
-            type = "normal";
-            socket = "/run/uwsgi/cgit.sock";
-            procname-master = "uwsgi cgit";
-            plugins = [ "cgi" ];
-            cgi = "${pkgs.cgit-pink}/cgit/cgit.cgi";
-          };
-        };
-      };
-    };
-
-    users.extraUsers.nginx.extraGroups = [ "git" ];
-
-    services.nginx.virtualHosts.${cfg.realHost} = {
-      forceSSL = true;
-      useACMEHost = cfg.domain;
-      root = "${pkgs.cgit-pink}/cgit";
-      locations = {
-        "/" = {
-          extraConfig = ''
-            try_files $uri @cgit;
-          '';
-        };
-        "=/cgit-exotic.css" = {
-          alias = "${./cgit-exotic.css}";
-          extraConfig = ''
-            # add_header Cache-Control "public, max-age=14400, must-revalidate";
-          '';
-        };
-        "@cgit" = {
-          extraConfig = ''
-            uwsgi_pass unix:/run/uwsgi/cgit.sock;
-            include ${pkgs.nginx}/conf/uwsgi_params;
-            uwsgi_modifier1 9;
-          '';
-        };
-      };
-    };
-
-    networking.firewall.allowedTCPPorts = [ 80 443 ];
-
-    systemd.services.create-cgit-cache = {
-      description = "Create cache directory for cgit";
-      enable = true;
-
-      script = ''
-        mkdir -p /run/cgit
-        chown -R nginx:nginx /run/cgit
-      '';
-
-      wantedBy = [ "uwsgi.service" ];
-      serviceConfig = {
-        Type = "oneshot";
-      };
-    };
-
-    environment.etc."cgitrc".text = ''
-      virtual-root=/
-
-      cache-size=1000
-      cache-root=/run/cgit
-
-      root-title=${cfg.settings.title}
-      root-desc=${cfg.settings.description}
-
-      css=/cgit-exotic.css
-
-      snapshots=tar.gz zip
-
-      enable-git-config=1
-      remove-suffix=1
-
-      enable-index-links=1
-      enable-index-owner=0
-      enable-git-clone=1
-      enable-commit-graph=1
-      enable-log-filecount=1
-      enable-log-linecount=1
-
-      branch-sort=age
-
-      readme=:README
-      readme=:readme
-      readme=:README.md
-      readme=:readme.md
-      readme=:README.org
-      readme=:readme.org
-
-      source-filter=${pkgs.cgit-pink}/lib/cgit/filters/syntax-highlighting.py
-      about-filter=${pkgs.cgit-pink}/lib/cgit/filters/about-formatting.sh
-
-      section-from-path=2
-
-      project-list=${config.services.gitolite.dataDir}/projects.list
-      scan-path=${config.services.gitolite.dataDir}/repositories
-    '';
-  };
-}
diff --git a/modules/services/cinny-web.nix b/modules/services/cinny-web.nix
deleted file mode 100644
index e796ff8..0000000
--- a/modules/services/cinny-web.nix
+++ /dev/null
@@ -1,34 +0,0 @@
-{ config, lib, pkgs, ... }:
-
-with lib;
-let
-  cfg = config.modules.services.cinny-web;
-in
-{
-  options.modules.services.cinny-web = {
-    enable = mkEnableOption "cinny-web";
-    package = mkOption { type = types.package; default = pkgs.cinny; };
-    hostName = mkOption { type = types.str; default = config.networking.hostName; };
-    matrix.serverName = mkOption { type = types.str; default = config.networking.hostName; };
-    tls.acmeHost = mkOption { type = types.str; default = cfg.hostName; };
-  };
-
-  config = mkIf cfg.enable {
-    services.nginx.virtualHosts.${cfg.hostName} = {
-      useACMEHost = cfg.tls.acmeHost;
-      forceSSL = true;
-
-      root = cfg.package.override {
-        conf = {
-          # Index of the default homeserver from `homeserverList`
-          defaultHomeserver = 0;
-          homeserverList = [ cfg.matrix.serverName ];
-        };
-      };
-
-      locations."~ \\.(js|css|woff|woff2?|png|jpe?g|svg)$".extraConfig = ''
-        add_header Cache-Control "public, max-age=14400, must-revalidate";
-      '';
-    };
-  };
-}
diff --git a/modules/services/coredns/_corefile.nix b/modules/services/coredns/_corefile.nix
deleted file mode 100644
index 84e2165..0000000
--- a/modules/services/coredns/_corefile.nix
+++ /dev/null
@@ -1,3 +0,0 @@
-''
-  Add content here
-''
diff --git a/modules/services/coredns/default.nix b/modules/services/coredns/default.nix
deleted file mode 100644
index 52d8570..0000000
--- a/modules/services/coredns/default.nix
+++ /dev/null
@@ -1,18 +0,0 @@
-{ config, lib, ... }:
-
-with lib;
-let
-  cfg = config.modules.services.coredns;
-in
-{
-  options.modules.services.coredns = {
-    enable = mkEnableOption "coredns";
-  };
-
-  config = mkIf cfg.enable {
-    services.coredns = {
-      enable = true;
-      config = import ./_corefile.nix;
-    };
-  };
-}
diff --git a/modules/services/coturn.nix b/modules/services/coturn.nix
deleted file mode 100644
index 967ba60..0000000
--- a/modules/services/coturn.nix
+++ /dev/null
@@ -1,64 +0,0 @@
-{ config, lib, ... }:
-
-with lib;
-let
-  turnRange = with config.services.coturn; [{
-    from = min-port;
-    to = max-port;
-  }];
-
-  cfg = config.modules.services.coturn;
-in
-{
-  options.modules.services.coturn = {
-    enable = mkEnableOption "coturn";
-    domain = mkOption { type = types.str; default = config.networking.hostName; };
-    shared_secret = mkOption { type = types.str; };
-    tls.acmeHost = mkOption { type = types.str; default = cfg.domain; };
-  };
-
-  config = mkIf cfg.enable {
-    services.coturn = {
-      enable = true;
-      use-auth-secret = true;
-      static-auth-secret = cfg.shared_secret;
-      realm = cfg.domain;
-      cert = "${config.security.acme.certs.${cfg.tls.acmeHost}.directory}/fullchain.pem";
-      pkey = "${config.security.acme.certs.${cfg.tls.acmeHost}.directory}/key.pem";
-
-      no-tcp-relay = true;
-      no-cli = true;
-
-      extraConfig = ''
-        user-quota=12
-        total-quota=1200
-
-        no-loopback-peers
-        no-multicast-peers
-        denied-peer-ip=0.0.0.0-0.255.255.255
-        denied-peer-ip=10.0.0.0-10.255.255.255
-        denied-peer-ip=100.64.0.0-100.127.255.255
-        denied-peer-ip=127.0.0.0-127.255.255.255
-        denied-peer-ip=169.254.0.0-169.254.255.255
-        denied-peer-ip=172.16.0.0-172.31.255.255
-        denied-peer-ip=192.0.0.0-192.0.0.255
-        denied-peer-ip=192.0.2.0-192.0.2.255
-        denied-peer-ip=192.88.99.0-192.88.99.255
-        denied-peer-ip=192.168.0.0-192.168.255.255
-        denied-peer-ip=198.18.0.0-198.19.255.255
-        denied-peer-ip=198.51.100.0-198.51.100.255
-        denied-peer-ip=203.0.113.0-203.0.113.255
-        denied-peer-ip=240.0.0.0-255.255.255.255
-      '';
-    };
-
-    systemd.services.coturn = {
-      serviceConfig.SupplementaryGroups = [ "acme" ];
-    };
-
-    networking.firewall.allowedUDPPortRanges = turnRange;
-    networking.firewall.allowedTCPPortRanges = turnRange;
-    networking.firewall.allowedTCPPorts = [ 3478 3479 5349 5350 ];
-    networking.firewall.allowedUDPPorts = [ 3478 3479 5349 5350 ];
-  };
-}
diff --git a/modules/services/dovecot.nix b/modules/services/dovecot.nix
deleted file mode 100644
index a33b0d1..0000000
--- a/modules/services/dovecot.nix
+++ /dev/null
@@ -1,18 +0,0 @@
-{ config, lib, ... }:
-
-with lib;
-let
-  cfg = config.modules.services.dovecot;
-in
-{
-  options.modules.services.dovecot = {
-    enable = mkEnableOption "dovecot";
-  };
-
-  config = mkIf cfg.enable {
-    services.dovecot2 = {
-      enable = true;
-    };
-    networking.firewall.allowedTCPPorts = [ 587 465 ];
-  };
-}
diff --git a/modules/services/element-web.nix b/modules/services/element-web.nix
deleted file mode 100644
index 2b200bd..0000000
--- a/modules/services/element-web.nix
+++ /dev/null
@@ -1,47 +0,0 @@
-{ config, lib, pkgs, ... }:
-
-with lib;
-let
-  cfg = config.modules.services.element-web;
-in
-{
-  options.modules.services.element-web = {
-    enable = mkEnableOption "element-web";
-    package = mkOption { type = types.package; default = pkgs.element-web; };
-    hostName = mkOption { type = types.str; default = config.networking.hostName; };
-    matrix = {
-      baseUrl = mkOption { type = types.str; default = "https://matrix.${config.networking.hostName}"; };
-      serverName = mkOption { type = types.str; default = config.networking.hostName; };
-    };
-    tls.acmeHost = mkOption { type = types.str; default = cfg.hostName; };
-    jitsi.domain = mkOption { type = types.str; default = "jitsi.${cfg.hostName}"; };
-  };
-
-  config = mkIf cfg.enable {
-    services.nginx.virtualHosts.${cfg.hostName} = {
-      useACMEHost = cfg.tls.acmeHost;
-      forceSSL = true;
-
-      root = cfg.package.override {
-        conf = {
-          default_server_config = {
-            "m.homeserver" = {
-              "base_url" = cfg.matrix.baseUrl;
-              "server_name" = cfg.matrix.serverName;
-            };
-            "m.identity_server" = {
-              "base_url" = "https://vector.im";
-            };
-          };
-          showLabsSettings = true;
-        } // optionalAttrs (cfg.jitsi.domain != null) {
-          jitsi.preferredDomain = cfg.jitsi.domain;
-        };
-      };
-
-      locations."~ \\.(js|css|woff|woff2?|png|jpe?g|svg)$".extraConfig = ''
-        add_header Cache-Control "public, max-age=14400, must-revalidate";
-      '';
-    };
-  };
-}
diff --git a/modules/services/fail2ban.nix b/modules/services/fail2ban.nix
deleted file mode 100644
index 281ca11..0000000
--- a/modules/services/fail2ban.nix
+++ /dev/null
@@ -1,20 +0,0 @@
-{ config, lib, ... }:
-
-with lib;
-let
-  cfg = config.modules.services.fail2ban;
-in
-{
-  options.modules.services.fail2ban = {
-    enable = mkEnableOption "fail2ban";
-  };
-
-  config = mkIf cfg.enable {
-    services.fail2ban = {
-      enable = true;
-    };
-    modules.persistence.directories = [
-      "/var/lib/fail2ban"
-    ];
-  };
-}
diff --git a/modules/services/git-daemon.nix b/modules/services/git-daemon.nix
deleted file mode 100644
index 5d027de..0000000
--- a/modules/services/git-daemon.nix
+++ /dev/null
@@ -1,29 +0,0 @@
-{ config, lib, ... }:
-
-with lib;
-let
-  cfg = config.modules.services.gitDaemon;
-in
-{
-  disabledModules = [
-    "services/networking/git-daemon.nix"
-  ];
-
-  imports = [
-    ../../overlays/git-daemon-module.nix
-  ];
-
-  options.modules.services.gitDaemon = {
-    enable = mkEnableOption "git daemon";
-  };
-
-  config = mkIf cfg.enable {
-    services.gitDaemon = {
-      enable = true;
-      createUserAndGroup = false;
-      basePath = "/var/lib/gitolite/repositories";
-    };
-
-    networking.firewall.allowedTCPPorts = [ 9418 ];
-  };
-}
diff --git a/modules/services/gitolite/default.nix b/modules/services/gitolite/default.nix
deleted file mode 100644
index 31cf755..0000000
--- a/modules/services/gitolite/default.nix
+++ /dev/null
@@ -1,110 +0,0 @@
-{ config, lib, pkgs, ... }:
-
-with lib;
-let
-  cfg = config.modules.services.gitolite;
-in
-{
-  options.modules.services.gitolite = {
-    enable = mkEnableOption "gitolite server";
-    adminPubkey = mkOption { type = types.str; };
-  };
-  config = mkIf cfg.enable {
-    services.openssh.enable = true;
-
-    services.gitolite = {
-      enable = true;
-      user = "git";
-      group = "git";
-      adminPubkey = cfg.adminPubkey;
-      extraGitoliteRc = ''
-        $RC{UMASK} = 0027;
-        $RC{GIT_CONFIG_KEYS} = '.*';
-        $RC{ROLES}{OWNERS} = 1;
-        $RC{OWNER_ROLENAME} = 'OWNERS';
-        # For some unknown reasons, $ENV{HOME} doesn't get resolved to the correct
-        # directory.
-        # $RC{LOCAL_CODE} = '$ENV{HOME}/local';
-        $RC{LOCAL_CODE} = '/var/lib/gitolite/local';
-        push(@{$RC{ENABLE}}, 'D');
-        push(@{$RC{ENABLE}}, 'symbolic-ref');
-        push(@{$RC{ENABLE}}, 'rename');
-        push(@{$RC{POST_GIT}}, 'fix-refs');
-        # push(@{$RC{ENABLE}}, 'set-default-roles');
-        # push(@{$RC{ENABLE}}, 'create');
-        # push(@{$RC{ENABLE}}, 'fork');
-
-      '';
-    };
-
-    modules.persistence.directories = [
-      "/var/lib/gitolite"
-    ];
-
-    system.activationScripts.gitolite-create-local = ''
-      mkdir -p /var/lib/gitolite/local/triggers
-      mkdir -p /var/lib/gitolite/local/commands
-      mkdir -p /var/lib/gitolite/local/hooks/common
-      chown -R git:git /var/lib/gitolite/local
-    '';
-
-    systemd.tmpfiles.rules = [
-      # https://groups.google.com/g/gitolite/c/NwZ1-hq9-9E/m/mDbiKyAvDwAJ
-      "C /var/lib/gitolite/local/triggers/fix-refs 755 - - - ${./fix-refs}"
-      "C /var/lib/gitolite/local/commands/rename 755 - - - ${./rename}"
-      "C /var/lib/gitolite/local/hooks/common/post-receive 755 - - - ${./post-receive}"
-    ];
-
-
-    systemd.timers."gitolite-trash-cleanup" = {
-      wantedBy = [ "timers.target" ];
-      timerConfig = {
-        OnCalendar = "*-*-* 00:00:00";
-        Unit = "gitolite-trash-cleanup.service";
-      };
-    };
-
-    systemd.services."gitolite-trash-cleanup" = {
-      script = ''
-        set -euo pipefail
-        if [ ! -d "Trash" ] ; then
-          echo Trash directory is nonexistent!
-          echo No operations to perform. Exiting.
-          exit 0
-        fi
-
-        match=$(find Trash -type d -regextype posix-extended -regex ".*/[0-9]{4}-[0-9]{2}-[0-9]{2}_[0-9]{2}:[0-9]{2}:[0-9]{2}$")
-        processed_entry=0
-        removed_entry=0
-
-        for dir in $match
-        do
-          system_timestamp=$(date +%s)
-          trash_timestamp=$(basename $dir | sed -e "s/_/ /g" | date -f - +%s)
-          age=$(( $system_timestamp - $trash_timestamp ))
-          # Wipe trashes older than 2w
-          if [[ age -gt 1209600 ]] ; then
-            echo "Removing '$dir' (age $age)"
-            rm -rf $dir
-            ((removed_entry+=1))
-          fi
-          ((processed_entry+=1))
-        done
-
-        echo "Directories that needs cleanup:"
-        find Trash -type d -empty -print -delete
-        echo "Cleaned empty directories."
-
-        echo "Done! Removed $removed_entry/$processed_entry"
-      '';
-
-      path = with pkgs; [ bash util-linux coreutils ];
-
-      serviceConfig = {
-        Type = "oneshot";
-        User = "git";
-        WorkingDirectory = "/var/lib/gitolite/repositories";
-      };
-    };
-  };
-}
diff --git a/modules/services/gitolite/fix-refs b/modules/services/gitolite/fix-refs
deleted file mode 100644
index 8ffec9e..0000000
--- a/modules/services/gitolite/fix-refs
+++ /dev/null
@@ -1,9 +0,0 @@
-[[ $4 == W ]] || exit 0
-
-cd $GL_REPO_BASE/$2.git
-
-head=`git symbolic-ref HEAD`
-[[ -f $head ]] || {
-  set -- refs/heads/*
-  git symbolic-ref HEAD $1
-}
diff --git a/modules/services/gitolite/post-receive b/modules/services/gitolite/post-receive
deleted file mode 100644
index 2f72ae9..0000000
--- a/modules/services/gitolite/post-receive
+++ /dev/null
@@ -1,19 +0,0 @@
-#!/bin/sh
-#
-# An example hook to update the "agefile" for CGit's idle time calculation.
-#
-# This hook assumes that you are using the default agefile location of
-# "info/web/last-modified".  If you change the value in your cgitrc then you
-# must also change it here.
-#
-# To install the hook, copy (or link) it to the file "hooks/post-receive" in
-# each of your repositories.
-#
-
-agefile="$(git rev-parse --git-dir)"/info/web/last-modified
-
-mkdir -p "$(dirname "$agefile")" &&
-git for-each-ref \
-	--sort=-authordate --count=1 \
-	--format='%(authordate:iso8601)' \
-	>"$agefile"
diff --git a/modules/services/gitolite/rename b/modules/services/gitolite/rename
deleted file mode 100644
index 2b00c7a..0000000
--- a/modules/services/gitolite/rename
+++ /dev/null
@@ -1,63 +0,0 @@
-
-# Usage:    ssh git@host rename [-c] <repo1> <repo2>
-#
-# Renames repo1 to repo2. You must be the creator of repo1, and have
-# create ("C") permissions for repo2, which of course must not exist.
-# Alternatively you must be an account admin, that is, you must have
-# write access to the gitolite-admin repository. If you have "C"
-# permissions for repo2 then you can use the -c option to take over
-# as creator of the repository.
-
-die() { echo "$@" >&2; exit 1; }
-usage() { perl -lne 'print substr($_, 2) if /^# Usage/../^$/' < $0; exit 1; }
-[ -z "$1" ] && usage
-[ "$1" = "-h" ] && usage
-[ -z "$GL_USER" ] && die GL_USER not set
-
-# ----------------------------------------------------------------------
-
-if [ "$1" = "-c" ]
-then	shift
-	takeover=true
-else	takeover=false
-fi
-
-from="$1"; shift
-to="$1"; shift
-[ -z "$to" ] && usage
-
-topath=$GL_REPO_BASE/$to.git
-
-checkto() {
-	gitolite access -q "$to" $GL_USER ^C any ||
-		die "'$to' already exists or you are not allowed to create it"
-}
-
-if gitolite access -q gitolite-admin $GL_USER
-then
-	# the user is an admin so we can avoid most permission checks
-	if $takeover
-	then checkto
-	elif [ -e $topath ]
-	then die "'$to' already exists"
-	fi
-else
-	# the user isn't an admin, so do all the checks
-	checkto
-	gitolite creator "$from" $GL_USER ||
-		die "'$from' does not exist or you are not allowed to delete it"
-fi
-
-# ----------------------------------------------------------------------
-
-mv $GL_REPO_BASE/$from.git $topath
-[ $? -ne 0 ] && exit 1
-
-$takeover && echo $GL_USER > $topath/gl-creator
-
-# Rebuild projects.list
-gitolite trigger POST_COMPILE
-
-echo "$from renamed to $to" >&2
-
-exit
diff --git a/modules/services/jitsi.nix b/modules/services/jitsi.nix
deleted file mode 100644
index 1152ac0..0000000
--- a/modules/services/jitsi.nix
+++ /dev/null
@@ -1,43 +0,0 @@
-{ config, lib, ... }:
-
-with lib;
-let
-  cfg = config.modules.services.jitsi;
-in
-{
-  options.modules.services.jitsi = {
-    enable = mkEnableOption "jitsi";
-    hostName = mkOption { type = types.str; default = config.networking.hostName; };
-    tls.acmeHost = mkOption { type = types.str; default = cfg.hostName; };
-  };
-
-  config = mkIf cfg.enable {
-    services.jitsi-meet = {
-      enable = true;
-      hostName = cfg.hostName;
-
-      config = {
-        prejoinPageEnabled = true;
-      };
-
-      interfaceConfig = {
-        SHOW_JITSI_WATERMARK = false;
-      };
-    };
-
-    services.jitsi-videobridge.openFirewall = true;
-
-    services.nginx.virtualHosts.${cfg.hostName} = {
-      enableACME = mkForce false;
-      useACMEHost = cfg.tls.acmeHost;
-      forceSSL = true;
-    };
-
-    networking.firewall.allowedTCPPorts = [ 80 443 ];
-
-    modules.persistence.directories = [
-      "/var/lib/prosody"
-      "/var/lib/jitsi-meet"
-    ];
-  };
-}
diff --git a/modules/services/ldap.nix b/modules/services/ldap.nix
deleted file mode 100644
index e75d739..0000000
--- a/modules/services/ldap.nix
+++ /dev/null
@@ -1,76 +0,0 @@
-{ config, lib, pkgs, ... }:
-
-with lib;
-let
-  cfg = config.modules.services.ldap;
-in
-{
-  options.modules.services.ldap = {
-    enable = mkEnableOption "OpenLDAP server";
-    package = mkOption { type = types.package; default = pkgs.openldap; };
-    dc = mkOption { type = types.str; };
-    tld = mkOption { type = types.str; };
-    tls.acmeHost = mkOption { type = types.str; default = "${cfg.dc}.${cfg.tld}"; };
-    secrets.rootPass = mkOption { type = types.path; description = "path to the root password file"; };
-  };
-
-  config = mkIf cfg.enable {
-    services.openldap = {
-      enable = true;
-
-      urlList = [ "ldap:///" "ldaps:///" ];
-
-      settings = {
-        attrs = {
-          olcLogLevel = "conns config";
-
-          olcTLSCACertificateFile = "${config.security.acme.certs.${cfg.tls.acmeHost}.directory}/full.pem";
-          olcTLSCertificateFile = "${config.security.acme.certs.${cfg.tls.acmeHost}.directory}/cert.pem";
-          olcTLSCertificateKeyFile = "${config.security.acme.certs.${cfg.tls.acmeHost}.directory}/key.pem";
-          olcTLSCipherSuite = "HIGH:MEDIUM:+3DES:+RC4:+aNULL";
-          olcTLSCRLCheck = "none";
-          olcTLSVerifyClient = "never";
-          olcTLSProtocolMin = "3.1";
-        };
-
-        children = {
-          "cn=schema".includes = [
-            "${cfg.package}/etc/schema/core.ldif"
-            "${cfg.package}/etc/schema/cosine.ldif"
-            "${cfg.package}/etc/schema/inetorgperson.ldif"
-          ];
-
-          "olcDatabase={1}mdb".attrs = {
-            objectClass = [ "olcDatabaseConfig" "olcMdbConfig" ];
-
-            olcDatabase = "{1}mdb";
-            olcDbDirectory = "/var/lib/openldap/data";
-
-            olcSuffix = "dc=${cfg.dc},dc=${cfg.tld}";
-
-            olcRootDN = "cn=admin,dc=${cfg.dc},dc=${cfg.tld}";
-            olcRootPW.path = cfg.secrets.rootPass;
-
-            olcAccess = [
-              # ''{0}to <changeme>
-              # by <changeme>''
-
-              ''{0}to *
-                  by * none'' # Should be changed to {1}
-            ];
-          };
-        };
-      };
-    };
-
-    systemd.services.openldap = {
-      after = [ "acme-finished-${cfg.tls.acmeHost}.target" ];
-    };
-
-    users.groups.acme.members = [ "openldap" ];
-
-    modules.persistence.directories = [
-      "/var/lib/openldap"
-    ];
-  };
-}
diff --git a/modules/services/matrix-bridge.nix b/modules/services/matrix-bridge.nix
deleted file mode 100644
index 3ea46d8..0000000
--- a/modules/services/matrix-bridge.nix
+++ /dev/null
@@ -1,390 +0,0 @@
-{ config, lib, pkgs, ... }:
-
-with lib;
-let
-  cfg = config.modules.services.matrix-bridge;
-in
-{
-  imports = [
-    ../../overlays/mautrix-signal-module.nix
-    ../../overlays/mautrix-discord-module.nix
-  ];
-
-  options.modules.services.matrix-bridge = {
-    enable = mkEnableOption "matrix-bridge";
-    domain = mkOption { type = types.str; };
-    realHost = mkOption { type = types.str; default = "matrix.${cfg.domain}"; };
-    secrets.mautrix-envs = mkOption { type = types.path; description = "path to the mautrix-* environment file"; };
-  };
-
-  config = mkIf cfg.enable {
-    sops.secrets.double-puppet-as-token = { };
-    sops.secrets.double-puppet-hs-token = { };
-
-    sops.templates."double-puppet-registration.yaml".content = ''
-      id: doublepuppet
-      url:
-      as_token: ${config.sops.placeholder.double-puppet-as-token}
-      hs_token: ${config.sops.placeholder.double-puppet-hs-token}
-      sender_localpart: 55e126746dad19e50d9c4e646b6f5ac9ba21b346a24b840330cd8d8a1d65ce80
-      rate_limited: false
-      namespaces:
-        users:
-          - regex: '@.*:exotic\.sh'
-            exclusive: false
-    '';
-
-    services.mautrix-telegram = {
-      enable = true;
-
-      environmentFile = cfg.secrets.mautrix-envs;
-      serviceDependencies = [ "matrix-synapse.service" ];
-
-      settings = {
-        homeserver.address = "https://${cfg.realHost}";
-        homeserver.domain = cfg.domain;
-        homeserver.verify_ssl = true;
-        appservice = {
-          address = "http://localhost:29317";
-          hostname = "localhost";
-          port = 29317;
-          database = "postgres:///mautrix-telegram?host=/run/postgresql";
-          bot_avatar = "mxc://maunium.net/tJCRmUyJDsgRNgqhOgoiHWbX";
-          id = "telegram";
-          max_body_size = 1;
-          provisioning.enabled = false;
-        };
-        bridge = {
-          alias_template = "tg_{groupname}";
-          username_templace = "tg_{userid}";
-          allow_matrix_login = true;
-          bot_messages_as_notices = true;
-          catch_up = true;
-          plaintext_highlights = true;
-          startup_sync = true;
-          animated_stickers = {
-            target = "webp";
-            convert_from_webm = true;
-          };
-          encryption = {
-            allow = true;
-            default = true;
-            require = true;
-            allow_key_sharing = true;
-          };
-          # NOTE: python bridge - managed via env variable
-          # login_shared_secret_map = {
-          #   "${cfg.domain}" = "as_token:$DOUBLE_PUPPET_AS_TOKEN";
-          # };
-          permissions = {
-            "@sef:exotic.sh" = "admin";
-            "exotic.sh" = "full";
-          };
-        };
-      };
-    };
-
-    services.mautrix-signal = {
-      enable = true;
-      package = pkgs.mautrix-signal;
-
-      environmentFile = cfg.secrets.mautrix-envs;
-      serviceDependencies = [ "matrix-synapse.service" ];
-
-      settings = {
-        homeserver.address = "https://${cfg.realHost}";
-        homeserver.domain = cfg.domain;
-        homeserver.verify_ssl = true;
-        appservice = {
-          address = "http://localhost:29318";
-          port = 29318;
-          database = "postgres:///mautrix-signal?host=/run/postgresql";
-          bot_avatar = "mxc://maunium.net/wPJgTQbZOtpBFmDNkiNEMDUp";
-          id = "signal";
-          max_body_size = 1;
-          provisioning.enabled = false;
-        };
-
-        signal = {
-          avatar_dir = "/var/lib/signald/avatars";
-          data_dir = "/var/lib/signald/data";
-        };
-
-        bridge = {
-          alias_template = "sig_{groupname}";
-          username_templace = "sig_{userid}";
-          allow_matrix_login = true;
-          catch_up = true;
-          plaintext_highlights = true;
-          startup_sync = true;
-          animated_stickers = {
-            target = "webp";
-            convert_from_webm = true;
-          };
-          encryption = {
-            allow = true;
-            default = true;
-            require = true;
-            allow_key_sharing = true;
-          };
-          login_shared_secret_map = {
-            "${cfg.domain}" = "as_token:$DOUBLE_PUPPET_AS_TOKEN";
-          };
-          permissions = {
-            "@sef:exotic.sh" = "admin";
-            "exotic.sh" = "full";
-          };
-        };
-      };
-    };
-
-    services.mautrix-whatsapp = {
-      enable = true;
-      environmentFile = cfg.secrets.mautrix-envs;
-      serviceDependencies = [ "matrix-synapse.service" ];
-
-      settings = {
-        homeserver.address = "https://${cfg.realHost}";
-        homeserver.domain = cfg.domain;
-        homeserver.verify_ssl = true;
-        appservice = {
-          address = "http://localhost:29319";
-          hostname = "localhost";
-          port = 29319;
-          database = {
-            type = "postgres";
-            uri = "postgres://mautrix-whatsapp:@/mautrix-whatsapp?host=/run/postgresql";
-          };
-          bot_avatar = "mxc://maunium.net/NeXNQarUbrlYBiPCpprYsRqr";
-          id = "whatsapp";
-          max_body_size = 1;
-          provisioning.enabled = false;
-        };
-
-        bridge = {
-          alias_template = "wa_{groupname}";
-          username_templace = "wa_{userid}";
-          personal_filtering_spaces = true;
-          delivery_receipts = true;
-          identity_change_notices = true;
-          history_sync = {
-            backfill = false; # MSC2716
-            request_full_sync = true;
-          };
-          send_presence_on_typing = true;
-          double_puppet_server_map = { };
-          login_shared_secret_map = {
-            "${cfg.domain}" = "as_token:$DOUBLE_PUPPET_AS_TOKEN";
-          };
-          private_chat_portal_meta = true;
-          mute_bridging = true;
-          pinned_tag = "m.favourite";
-          archive_tag = "m.lowpriority";
-          allow_user_invite = true;
-          disappearing_messages_in_groups = true;
-          url_previews = true;
-          encryption = {
-            allow = true;
-            default = true;
-            require = true;
-            allow_key_sharing = true;
-          };
-          sync_manual_marked_unread = true;
-          force_active_delivery_receipts = true;
-          parallel_member_sync = true;
-          extev_polls = true;
-          send_whatsapp_edits = true;
-          permissions = {
-            "@sef:exotic.sh" = "admin";
-            "exotic.sh" = "full";
-          };
-        };
-      };
-    };
-
-    services.mautrix-discord = {
-      enable = true;
-      environmentFile = cfg.secrets.mautrix-envs;
-      serviceDependencies = [ "matrix-synapse.service" ];
-
-      settings = {
-        homeserver.address = "https://${cfg.realHost}";
-        homeserver.domain = cfg.domain;
-        homeserver.verify_ssl = true;
-        appservice = {
-          address = "http://localhost:29320";
-          port = 29320;
-          database = {
-            type = "postgres";
-            uri = "postgres://mautrix-discord:@/mautrix-discord?host=/run/postgresql";
-          };
-          bot_avatar = "mxc://maunium.net/nIdEykemnwdisvHbpxflpDlC";
-          id = "discord";
-          max_body_size = 1;
-          provisioning.enabled = false;
-        };
-
-        bridge = {
-          username_template = "dsc_{{.}}";
-          delivery_receipts = true;
-          encryption = {
-            allow = true;
-            default = true;
-            require = true;
-            allow_key_sharing = true;
-          };
-          login_shared_secret_map = {
-            "${cfg.domain}" = "as_token:$DOUBLE_PUPPET_AS_TOKEN";
-          };
-          permissions = {
-            "@sef:exotic.sh" = "admin";
-            "exotic.sh" = "full";
-          };
-        };
-      };
-    };
-
-    services.matrix-appservice-irc = {
-      enable = true;
-      registrationUrl = "http://localhost:29321";
-      port = 29321;
-
-      settings = {
-        homeserver.url = "https://${cfg.realHost}";
-        homeserver.domain = cfg.domain;
-        homeserver.dropMatrixMessagesAfterSecs = 600; # 10 minutes
-
-        database.engine = "postgres";
-        database.connectionString = "postgres://matrix-appservice-irc:@/matrix-appservice-irc?host=/run/postgresql";
-
-        ircService.servers = let
-          # nix-community/nur-combined/repos/colinsane/hosts/by-name/servo/services/matrix/irc.nix@b2e96d5
-          ircServer = { name, additionalAddresses ? [], sasl ? true, port ? 6697}:
-            let lowerName = lib.toLower name;
-          in {
-            inherit name additionalAddresses sasl port;
-            ssl = true;
-            # Disable bridging of Matrix bots
-            botConfig.enabled = false;
-            dynamicChannels = {
-              enabled = true;
-              aliasTemplate = "#irc_${lowerName}_$CHANNEL";
-              published = false;
-              federate = false;
-            };
-            ircClients = {
-              nickTemplate = "$DISPLAY[m]";
-              allowNickChanges = true;
-              realNameFormat = "reverse-mxid";
-              lineLimit = 20;
-              # Safeguard: don't flood servers
-              maxClients = 2;
-              idleTimeout = 0;
-              concurrentReconnectLimit = 2;
-              reconnectIntervalMs = 60000;
-              kickOn = {
-                # only kick Matrix user from room when user quits
-                channelJoinFailure = false;
-                ircConnectionFailure = false;
-                userQuit = true;
-              };
-            };
-            matrixClients.userTemplate = "@irc_${lowerName}_$NICK";
-
-            "@sef:exotic.sh" = "admin";
-
-            memberShipLists = {
-              enabled = true;
-              # NOTE: when serving lots of Matrix users, these configs should
-              # be changed to reduce strain on IRC servers
-              global = {
-                ircToMatrix = {
-                  initial = true;
-                  incremental = true;
-                  requireMatrixJoined = false;
-                };
-                matrixToIrc = {
-                  initial = true;
-                  incremental = true;
-                };
-                # always bridge users, even if idle
-                ignoreIdleUsersOnStartup.enabled = false;
-              };
-              bridgeInfoState = {
-                enabled = true;
-                initial = true;
-              };
-            };
-          };
-        in {
-          "irc.libera.chat" = ircServer {
-            name = "libera";
-            # sasl = false;
-          };
-          "irc.oftc.net" = ircServer {
-            name = "oftc";
-            # sasl = false;
-          };
-        };
-      };
-    };
-
-    # HACK: https://github.com/NixOS/nixpkgs/issues/273929
-    systemd.services.matrix-appservice-irc.serviceConfig.SystemCallFilter = lib.mkForce ''
-      @system-service @pkey ~@privileged @resources @chown
-    '';
-
-
-    modules.persistence.directories = [
-      "/var/lib/private/mautrix-telegram"
-      "/var/lib/private/mautrix-signal"
-      "/var/lib/private/mautrix-whatsapp"
-      "/var/lib/private/mautrix-discord"
-      "/var/lib/matrix-appservice-irc"
-      "/var/lib/signald"
-    ];
-
-    modules.services.postgresql.enable = true;
-    services.postgresql.ensureDatabases = [ "mautrix-telegram" "mautrix-signal" "mautrix-whatsapp" "mautrix-discord" "matrix-appservice-irc" ];
-    services.postgresql.ensureUsers = [
-      {
-        name = "mautrix-telegram";
-        ensureDBOwnership = true;
-      }
-      {
-        name = "mautrix-signal";
-        ensureDBOwnership = true;
-      }
-      {
-        name = "mautrix-whatsapp";
-        ensureDBOwnership = true;
-      }
-      {
-        name = "mautrix-discord";
-        ensureDBOwnership = true;
-      }
-      {
-        name = "matrix-appservice-irc";
-        ensureDBOwnership = true;
-      }
-    ];
-
-    systemd.services.matrix-synapse.serviceConfig.LoadCredential = [
-      "mautrix-telegram:/var/lib/mautrix-telegram/telegram-registration.yaml"
-      "mautrix-signal:/var/lib/mautrix-signal/signal-registration.yaml"
-      "mautrix-whatsapp:/var/lib/mautrix-whatsapp/whatsapp-registration.yaml"
-      "mautrix-discord:/var/lib/mautrix-discord/discord-registration.yaml"
-      "double-puppet:${config.sops.templates."double-puppet-registration.yaml".path}"
-      "appservice-irc:/var/lib/matrix-appservice-irc/registration.yml"
-    ];
-
-    services.matrix-synapse.settings.app_service_config_files = [
-      "/run/credentials/matrix-synapse.service/mautrix-telegram"
-      "/run/credentials/matrix-synapse.service/mautrix-signal"
-      "/run/credentials/matrix-synapse.service/mautrix-whatsapp"
-      "/run/credentials/matrix-synapse.service/mautrix-discord"
-      "/run/credentials/matrix-synapse.service/double-puppet"
-      "/run/credentials/matrix-synapse.service/appservice-irc"
-    ];
-  };
-}
diff --git a/modules/services/matrix-homeserver.nix b/modules/services/matrix-homeserver.nix
deleted file mode 100644
index 3dc188b..0000000
--- a/modules/services/matrix-homeserver.nix
+++ /dev/null
@@ -1,190 +0,0 @@
-{ config, lib, pkgs, ... }:
-
-with lib;
-let
-  cfg = config.modules.services.matrix-homeserver;
-
-  httpPort = 8008;
-  slidingSyncPort = 8009;
-  metricsPort = 8010;
-in
-{
-  options.modules.services.matrix-homeserver = {
-    enable = mkEnableOption "matrix homeserver instance";
-    domain = mkOption { type = types.str; };
-    realHost = mkOption { type = types.str; default = "matrix.${cfg.domain}"; };
-    slidingSyncHost = mkOption { type = types.str; default = "slidingsync.${cfg.domain}"; };
-    turn = {
-      enable = mkEnableOption "VOIP using TURN";
-      domain = mkOption { type = types.str; default = "turn.${cfg.domain}"; };
-      shared_secret = mkOption { type = types.str; };
-    };
-    secrets = {
-      matrix-server-key = mkOption { type = types.path; description = "path to the server key"; };
-      matrix-shared-secret = mkOption { type = types.path; description = "path to the registration shared secret"; };
-      extra-config-path = mkOption { type = types.nullOr types.path; description = "path to the extra configuration file to source"; };
-      sliding-sync-secret = mkOption { type = types.nullOr types.path; description = "path to the sliding sync secret"; };
-    };
-  };
-
-  config = mkIf cfg.enable {
-    services.matrix-synapse = {
-      enable = true;
-      withJemalloc = true;
-      dataDir = "/var/lib/matrix-synapse";
-      settings = {
-        server_name = cfg.domain;
-        public_baseurl = "https://${cfg.realHost}";
-
-        signing_key_path = cfg.secrets.matrix-server-key;
-
-        allow_guest_access = false;
-        enable_registration = false;
-        registration_requires_token = true;
-        registration_shared_secret_path = cfg.secrets.matrix-shared-secret;
-
-        enable_metrics = true;
-        url_preview_enabled = true;
-
-        database = {
-          name = "psycopg2";
-          args.password = "synapse";
-        };
-
-        listeners = [
-          {
-            port = httpPort;
-            resources = [
-              {
-                compress = true;
-                names = [ "client" ];
-              }
-              {
-                compress = false;
-                names = [ "federation" ];
-              }
-            ];
-            type = "http";
-            tls = false;
-            x_forwarded = true;
-          }
-          {
-            port = metricsPort;
-            resources = [{
-              compress = false;
-              names = [ "metrics" ];
-            }];
-            type = "metrics";
-            tls = false;
-          }
-        ];
-
-        trusted_key_servers = [{
-          server_name = "matrix.org";
-          verify_keys = {
-            "ed25519:auto" = "Noi6WqcDj0QmPxCNQqgezwTlBKrfqehY1u2FyWP9uYw";
-          };
-        }];
-        # Yes, we want to use matrix.org as our trusted key server
-        suppress_key_server_warning = true;
-      } // optionalAttrs (cfg.turn.enable) {
-        turn_uris = [
-          "turns:${cfg.turn.domain}?transport=udp"
-          "turns:${cfg.turn.domain}?transport=tcp"
-          "turn:${cfg.turn.domain}?transport=udp"
-          "turn:${cfg.turn.domain}?transport=tcp"
-        ];
-      };
-    };
-
-    services.matrix-sliding-sync = {
-      enable = true;
-      createDatabase = true;
-      settings = {
-        SYNCV3_SERVER = "https://${cfg.realHost}";
-        SYNCV3_BINDADDR = "[::1]:${toString slidingSyncPort}";
-      };
-      environmentFile = cfg.secrets.sliding-sync-secret;
-    };
-
-    services.prometheus.scrapeConfigs = [
-      {
-        job_name = "synapse";
-        metrics_path = "/_synapse/metrics";
-        static_configs = [{
-          targets = [ "127.0.0.1:${toString metricsPort}" ];
-        }];
-      }
-    ];
-
-    modules.persistence.directories = [
-      "/var/lib/matrix-synapse"
-    ];
-
-    services.postgresql.enable = true;
-    services.postgresql.initialScript = pkgs.writeText "synapse-init.sql" ''
-      CREATE ROLE "matrix-synapse" WITH LOGIN PASSWORD 'synapse';
-      CREATE DATABASE "matrix-synapse" WITH OWNER "matrix-synapse"
-       TEMPLATE template0
-       LC_COLLATE = "C"
-       LC_CTYPE = "C";
-    '';
-    services.nginx.virtualHosts.${cfg.realHost} = {
-      forceSSL = true;
-      useACMEHost = cfg.domain;
-      listen = [
-        { addr = "0.0.0.0"; port = 443; ssl = true; }
-        { addr = "[::]"; port = 443; ssl = true; }
-        { addr = "0.0.0.0"; port = 8448; ssl = true; }
-        { addr = "[::]"; port = 8448; ssl = true; }
-
-      ];
-      extraConfig = ''
-        proxy_set_header Host $host;
-        proxy_set_header X-Forwarded-For $remote_addr;
-        proxy_set_header X-Forwarded-Proto $scheme;
-        proxy_read_timeout 600;
-        client_max_body_size ${config.services.matrix-synapse.settings.max_upload_size};
-      '';
-
-      locations."~* ^(\\/_matrix|\\/_synapse\\/client)".proxyPass = "http://[::1]:${toString httpPort}";
-    };
-
-    services.nginx.virtualHosts.${cfg.domain} =
-      let
-        server-hello = { "m.server" = "${cfg.realHost}:443"; };
-        client-hello = {
-          "m.homeserver"."base_url" = "https://${cfg.realHost}";
-          "m.identity_server"."base_url" = "https://vector.im";
-          "org.matrix.msc3575.proxy"."url" = "https://${cfg.slidingSyncHost}";
-        };
-      in
-      {
-        forceSSL = true;
-        useACMEHost = cfg.domain;
-        locations = {
-          "/.well-known/matrix/server" = {
-            extraConfig = ''
-              add_header Content-Type application/json;
-              return 200 '${builtins.toJSON server-hello}';
-            '';
-          };
-          "/.well-known/matrix/client" = {
-            extraConfig = ''
-              add_header Content-Type application/json;
-              add_header Access-Control-Allow-Origin *;
-              return 200 '${builtins.toJSON client-hello}';
-            '';
-          };
-        };
-      };
-
-    services.nginx.virtualHosts.${cfg.slidingSyncHost} = {
-      forceSSL = true;
-      useACMEHost = cfg.domain;
-      locations."/".proxyPass = "http://${config.services.matrix-sliding-sync.settings.SYNCV3_BINDADDR}";
-    };
-
-    networking.firewall.allowedTCPPorts = [ 443 8448 ];
-  };
-}
diff --git a/modules/services/matrix-moderation.nix b/modules/services/matrix-moderation.nix
deleted file mode 100644
index b44cdf3..0000000
--- a/modules/services/matrix-moderation.nix
+++ /dev/null
@@ -1,58 +0,0 @@
-{ config, lib, ... }:
-
-# TODO: rename
-
-with lib;
-let
-  cfg = config.modules.services.matrix-moderation;
-in
-{
-  options.modules.services.matrix-moderation = {
-    enable = mkEnableOption "matrix-moderation";
-    domain = mkOption { type = types.str; };
-    realHost = mkOption { type = types.str; default = "matrix.${cfg.domain}"; };
-    secrets.userPassword = mkOption { type = types.str; description = "path to the mjolnir password"; };
-  };
-
-  config = mkIf cfg.enable {
-    services.mjolnir = {
-      enable = true;
-      homeserverUrl = "http://127.0.0.1:8008";
-      pantalaimon.enable = true;
-      # NOTE: this option currently has no effect
-      pantalaimon.options = {
-        listenAddress = "127.0.0.1";
-        listenPort = 8011;
-      };
-      pantalaimon.username = "abuse";
-      pantalaimon.passwordFile = cfg.secrets.userPassword;
-      managementRoom = "#moderation:${cfg.domain}";
-
-      settings = {
-        # TODO: get rid of hardcoded values
-        homeserverUrl = "http://127.0.0.1:8011";
-        automaticallyRedactForReasons = [
-          "spam"
-          "advertising"
-          "unwanted"
-        ];
-      };
-    };
-
-    # TODO: get rid of hardcoded values
-    systemd.services.mjolnir.after = [ "matrix-synapse.service" ];
-
-    # Override the pantalaimon options, since the mjolnir one is broken
-    services.pantalaimon-headless.instances."mjolnir" = {
-      listenAddress = "127.0.0.1";
-      listenPort = 8011;
-    };
-
-    services.matrix-synapse.plugins = with config.services.matrix-synapse.package.plugins; [ matrix-synapse-mjolnir-antispam ];
-
-    modules.persistence.directories = [
-      "/var/lib/private/pantalaimon-mjolnir"
-      "/var/lib/mjolnir"
-    ];
-  };
-}
diff --git a/modules/services/metrics.nix b/modules/services/metrics.nix
deleted file mode 100644
index 5f03389..0000000
--- a/modules/services/metrics.nix
+++ /dev/null
@@ -1,169 +0,0 @@
-{ config, lib, ... }:
-
-with lib;
-let
-  cfg = config.modules.services.metrics;
-in
-{
-  options.modules.services.metrics = {
-    enable = mkEnableOption "metrics";
-    domain = mkOption { type = types.str; };
-    tls.acmeHost = mkOption { type = types.str; default = cfg.domain; };
-    secrets.adminPassword = mkOption { type = types.path; description = "path to the admin password"; };
-  };
-
-  config = mkIf cfg.enable {
-    services.prometheus = {
-      enable = true;
-      port = 9001;
-
-      exporters = {
-        node = {
-          enable = true;
-          enabledCollectors = [ "systemd" ];
-          port = 9002;
-        };
-      };
-
-      scrapeConfigs = [
-        {
-          job_name = "node";
-          static_configs = [{
-            targets = [ "127.0.0.1:${toString config.services.prometheus.exporters.node.port}" ];
-          }];
-        }
-      ];
-    };
-
-    services.loki = {
-      enable = true;
-      configuration = {
-        auth_enabled = false;
-        server.http_listen_port = 3100;
-
-        ingester = {
-          lifecycler = {
-            address = "127.0.0.1";
-            ring.kvstore.store = "inmemory";
-            ring.replication_factor = 1;
-            final_sleep = "0s";
-          };
-
-          chunk_idle_period = "1h";
-          max_chunk_age = "1h";
-          chunk_target_size = 1048576; # 1.5M
-          chunk_retain_period = "30s";
-          max_transfer_retries = 0;
-        };
-
-        schema_config.configs = [
-          {
-            from = "2023-02-24";
-            store = "boltdb-shipper";
-            object_store = "filesystem";
-            schema = "v11";
-            index = {
-              prefix = "index_";
-              period = "24h";
-            };
-          }
-        ];
-
-        storage_config = {
-          boltdb_shipper = {
-            active_index_directory = "/var/lib/loki/boltdb-shipper-active";
-            cache_location = "/var/lib/loki/boltdb-shipper-cache";
-            cache_ttl = "24h";
-            shared_store = "filesystem";
-          };
-
-          filesystem.directory = "/var/lib/loki/chunks";
-        };
-
-        limits_config = {
-          reject_old_samples = true;
-          reject_old_samples_max_age = "168h";
-
-          retention_period = "120h";
-        };
-
-        chunk_store_config = {
-          max_look_back_period = "0s";
-        };
-
-        table_manager = {
-          retention_deletes_enabled = true;
-          retention_period = "120h";
-        };
-
-        compactor = {
-          working_directory = "/var/lib/loki";
-          shared_store = "filesystem";
-          compactor_ring.kvstore.store = "inmemory";
-        };
-      };
-    };
-
-    services.promtail = {
-      enable = true;
-      configuration = {
-        server = {
-          http_listen_port = 3031;
-          grpc_listen_port = 0;
-        };
-        positions.filename = "/tmp/positions.yaml";
-        clients = [
-          { url = "http://127.0.0.1:${toString config.services.loki.configuration.server.http_listen_port}/loki/api/v1/push"; }
-        ];
-        scrape_configs = [
-          {
-            job_name = "journal";
-            journal = {
-              max_age = "12h";
-              labels = {
-                job = "systemd-journal";
-                host = config.networking.hostName;
-              };
-            };
-            relabel_configs = [
-              {
-                source_labels = [ "__journal__systemd_unit" ];
-                target_label = "unit";
-              }
-            ];
-          }
-        ];
-      };
-    };
-
-    services.grafana = {
-      enable = true;
-
-      settings.server.http_addr = "127.0.0.1";
-      settings.server.http_port = 2342;
-      settings.server.domain = cfg.domain;
-      settings.security.admin_password = "$__file{${cfg.secrets.adminPassword}}";
-    };
-
-    services.nginx.virtualHosts.${cfg.domain} = {
-      forceSSL = true;
-      useACMEHost = cfg.tls.acmeHost;
-
-      locations."/" = {
-        proxyPass = "http://localhost:${toString config.services.grafana.settings.server.http_port}";
-        proxyWebsockets = true;
-        extraConfig = ''
-          proxy_set_header X-Forwarded-For $proxy_add_x_forwarded_for;
-          # proxy_set_header Host $host;
-        '';
-      };
-    };
-
-    modules.persistence.directories = [
-      "/var/lib/prometheus2"
-      "/var/lib/loki"
-      "/var/lib/grafana"
-    ];
-  };
-}
-
diff --git a/modules/services/nebula.nix b/modules/services/nebula.nix
deleted file mode 100644
index 3f8c38a..0000000
--- a/modules/services/nebula.nix
+++ /dev/null
@@ -1,18 +0,0 @@
-{ config, options, lib, ... }:
-
-with lib;
-let
-  cfg = config.modules.services.nebula;
-in
-{
-  options.modules.services.nebula = {
-    enable = mkEnableOption "Configure a single-network Nebula";
-
-    networks = options.services.nebula.networks;
-  };
-
-  config = mkIf cfg.enable {
-    # The module is enabled when one or more module is enabled.
-    services.nebula.networks = cfg.networks;
-  };
-}
diff --git a/modules/services/nginx.nix b/modules/services/nginx.nix
deleted file mode 100644
index f9a5a31..0000000
--- a/modules/services/nginx.nix
+++ /dev/null
@@ -1,37 +0,0 @@
-{ config, lib, ... }:
-
-with lib;
-let
-  cfg = config.modules.services.nginx;
-in
-{
-  options.modules.services.nginx = {
-    enable = mkEnableOption "nginx proxy";
-  };
-  config = mkIf cfg.enable {
-    modules.services.acme.enable = true;
-
-    services.nginx = {
-      enable = true;
-      # prevent 3~5s downtime on update
-      enableReload = true;
-
-      recommendedGzipSettings = true;
-      recommendedOptimisation = true;
-      recommendedProxySettings = true;
-      recommendedTlsSettings = true;
-
-      # catch-all for unknown hosts.
-      virtualHosts."_" = {
-        default = true;
-        rejectSSL = true;
-
-        extraConfig = ''
-          return 444;
-        '';
-      };
-    };
-
-    users.extraUsers.nginx.extraGroups = [ "acme" ];
-  };
-}
diff --git a/modules/services/nixos-mailserver.nix b/modules/services/nixos-mailserver.nix
deleted file mode 100644
index 2c78780..0000000
--- a/modules/services/nixos-mailserver.nix
+++ /dev/null
@@ -1,159 +0,0 @@
-{ inputs, config, lib, ... }:
-
-with lib;
-let
-  cfg = config.modules.services.nixos-mailserver;
-in
-{
-  imports = [ inputs.nixos-mailserver.nixosModules.mailserver ];
-
-  options.modules.services.nixos-mailserver = {
-    enable = mkEnableOption "nixos-mailserver";
-    webmail = {
-      enable = mkOption {
-        type = types.bool;
-        default = false;
-        description = lib.mdDoc "Whether to enable roundcube webmail";
-      };
-      domain = mkOption { type = types.str; };
-      realHost = mkOption { type = types.str; };
-    };
-  };
-
-  config = mkIf cfg.enable {
-    sops.secrets.sefidel-imap-pass = {
-      mode = "0440";
-      owner = "dovecot2";
-      group = "dovecot2";
-    };
-    sops.secrets.system-imap-pass = {
-      mode = "0440";
-      owner = "dovecot2";
-      group = "dovecot2";
-    };
-    sops.secrets.internal-imap-pass = {
-      mode = "0440";
-      owner = "dovecot2";
-      group = "dovecot2";
-    };
-
-    systemd.services.dovecot2 = {
-      serviceConfig.SupplementaryGroups = [ "acme" ];
-    };
-
-    services.postfix = {
-      dnsBlacklists = [
-        # TODO: add sources
-        "b.barracudacentral.org"
-        "bl.spamcop.net"
-      ];
-      dnsBlacklistOverrides = ''
-        exotic.sh OK
-        sefidel.net OK
-        sefidel.com OK
-        192.168.0.0/16 OK
-      '';
-    };
-
-    # HACK: nixos-mailserver sets up reload hook on 'fqdn', which is 'mail.exotic.sh'.
-    # Since our cert is a wildcard cert with domain 'exotic.sh', it is excluded from the hook.
-    security.acme.certs."exotic.sh".reloadServices = [
-      "postfix.service"
-      "dovecot2.service"
-    ];
-
-    mailserver = {
-      enable = true;
-      fqdn = "mail.exotic.sh";
-      domains = [ "exotic.sh" "nand.moe" "sefidel.com" "sefidel.net" ];
-      mailboxes = {
-        Trash = {
-          auto = "no";
-          specialUse = "Trash";
-        };
-        Junk = {
-          auto = "subscribe";
-          specialUse = "Junk";
-        };
-        Drafts = {
-          auto = "subscribe";
-          specialUse = "Drafts";
-        };
-        Sent = {
-          auto = "subscribe";
-          specialUse = "Sent";
-        };
-      };
-
-      loginAccounts = {
-        "contact@sefidel.com" = {
-          catchAll = [ "sefidel.com" ];
-          hashedPasswordFile = config.sops.secrets.sefidel-imap-pass.path;
-        };
-        "contact@sefidel.net" = {
-          aliases = [ "sefidel" "dev@sefidel.net" "social@sefidel.net" "media@sefidel.net" "public@sefidel.net" "admin" "admin@sefidel.net" "postmaster" "postmaster@sefidel.net" ];
-          hashedPasswordFile = config.sops.secrets.sefidel-imap-pass.path;
-        };
-        "sef@exotic.sh" = {
-          aliases = [ "sef" "sefidel" "sefidel@exotic.sh" "admin" "admin@exotic.sh" "postmaster" "postmaster@exotic.sh" "admin@nand.moe" "postmaster@nand.moe" ];
-          hashedPasswordFile = config.sops.secrets.sefidel-imap-pass.path;
-        };
-        "system@exotic.sh" = {
-          aliases = [ "system" "system@nand.moe" ];
-          hashedPasswordFile = config.sops.secrets.system-imap-pass.path;
-        };
-        "internal@exotic.sh" = {
-          aliases = [ "internal" ];
-          hashedPasswordFile = config.sops.secrets.internal-imap-pass.path;
-        };
-      };
-      localDnsResolver = false;
-      certificateScheme = "manual";
-      certificateFile = "${config.security.acme.certs."exotic.sh".directory}/cert.pem";
-      keyFile = "${config.security.acme.certs."exotic.sh".directory}/key.pem";
-      enableImap = true;
-      enableImapSsl = true;
-      enableSubmission = true;
-      enableSubmissionSsl = true;
-      virusScanning = false;
-    };
-
-    services.roundcube = mkIf cfg.webmail.enable {
-      enable = true;
-      hostName = cfg.webmail.realHost;
-      database.host = "localhost"; # use localDB, pgsql db/user creation is done automatically.
-
-      plugins = [
-        "archive"
-        "enigma"
-        "help"
-        "markasjunk"
-        "vcard_attachments"
-        "zipdownload"
-      ];
-
-      extraConfig = ''
-        # STARTTLS required for authn, therefore the domain must match the SSL cert.
-        $config['smtp_server'] = 'tls://${config.mailserver.fqdn}';
-      '';
-    };
-
-    services.nginx.virtualHosts.${cfg.webmail.realHost} = {
-      enableACME = mkForce false; # conflicts with useACMEHost
-      forceSSL = true;
-      useACMEHost = cfg.webmail.domain;
-    };
-
-    modules.persistence.directories = [
-      "/var/lib/dovecot"
-      "/var/lib/rspamd"
-      "/var/lib/redis-rspamd"
-      "/var/vmail"
-      "/var/dkim"
-      "/var/sieve"
-      "/var/spool/mail"
-    ];
-
-    networking.firewall.allowedTCPPorts = [ 143 993 465 587 ];
-  };
-}
diff --git a/modules/services/obsidian-livesync.nix b/modules/services/obsidian-livesync.nix
deleted file mode 100644
index 189d92f..0000000
--- a/modules/services/obsidian-livesync.nix
+++ /dev/null
@@ -1,63 +0,0 @@
-  { config, lib, ... }:
-
-  with lib;
-  let
-    cfg = config.modules.services.obsidian-livesync;
-
-    port = 5984;
-  in
-  {
-    options.modules.services.obsidian-livesync = {
-      enable = mkEnableOption "obsidian-livesync server";
-
-      domain = mkOption { type = types.str; };
-      realHost = mkOption { type = types.str; default = "obsidian-livesync.${cfg.domain}"; };
-    };
-
-    config = mkIf cfg.enable {
-      services.couchdb = {
-        enable = true;
-        configFile = "/var/lib/couchdb/config";
-
-        extraConfig = ''
-          [couchdb]
-          single_node=true
-          max_document_size = 50000000
-
-          [admins]
-          admin = please-change-me
-
-          [chttpd]
-          require_valid_user = true
-          max_http_request_size = 4294967296
-          enable_cors = true
-
-          [chttpd_auth]
-          require_valid_user = true
-          authentication_redirect = /_utils/session.html
-
-          [httpd]
-          WWW-Authenticate = Basic realm="couchdb"
-          bind_address = 127.0.0.1
-          port = ${toString port}
-
-          [cors]
-          origins = app://obsidian.md, capacitor://localhost, http://localhost
-          credentials = true
-          headers = accept, authorization, content-type, origin, referer
-          methods = GET,PUT,POST,HEAD,DELETE
-          max_age = 3600
-      '';
-    };
-
-    modules.persistence.directories = [
-      "/var/lib/couchdb"
-    ];
-
-    services.nginx.virtualHosts.${cfg.realHost} = {
-      useACMEHost = cfg.domain;
-      forceSSL = true;
-      locations."/".proxyPass = "http://localhost:${toString port}";
-    };
-  };
-}
diff --git a/modules/services/postgresql.nix b/modules/services/postgresql.nix
deleted file mode 100644
index 05835a4..0000000
--- a/modules/services/postgresql.nix
+++ /dev/null
@@ -1,34 +0,0 @@
-{ config, lib, ... }:
-
-with lib;
-let
-  cfg = config.modules.services.postgresql;
-in
-{
-  options.modules.services.postgresql = {
-    enable = mkEnableOption "postgresql with laxed limits";
-  };
-
-  config = mkIf cfg.enable {
-    services.postgresql = {
-      enable = true;
-      settings = {
-        max_connections = "300";
-        shared_buffers = "80MB";
-      };
-      authentication = lib.mkForce ''
-        # Generated file; do not edit!
-        # TYPE  DATABASE        USER            ADDRESS                 METHOD
-        local   all             all                                     trust
-        host    all             all             127.0.0.1/32            trust
-        host    all             all             ::1/128                 trust
-      '';
-    };
-    services.postgresqlBackup.enable = true;
-
-    modules.persistence.directories = [
-      "/var/lib/postgresql"
-      "/var/backup/postgresql"
-    ];
-  };
-}
diff --git a/modules/services/rss.nix b/modules/services/rss.nix
deleted file mode 100644
index c9663ee..0000000
--- a/modules/services/rss.nix
+++ /dev/null
@@ -1,64 +0,0 @@
-{ config, lib, pkgs, ... }:
-
-with lib;
-let
-  cfg = config.modules.services.rss;
-in
-{
-  options.modules.services.rss = {
-    enable = mkEnableOption "RSS Aggregator";
-    domain = mkOption { type = types.str; };
-    realHost = mkOption { type = types.str; default = "rss.${cfg.domain}"; };
-    secrets.admin-password = mkOption { type = types.path; description = "path to file containing admin password"; };
-    bridge = {
-      enable = mkEnableOption "RSS Bridge";
-      domain = mkOption { type = types.str; default = cfg.domain; };
-      realHost = mkOption { type = types.str; default = "rss-bridge.${cfg.bridge.domain}"; };
-      whitelist = mkOption { type = types.listOf types.str; default = []; };
-    };
-  };
-
-  config = mkIf cfg.enable (mkMerge [
-    {
-      services.freshrss = {
-        enable = true;
-        virtualHost = cfg.realHost;
-        baseUrl = "https://${cfg.realHost}";
-
-        defaultUser = "admin";
-        passwordFile = cfg.secrets.admin-password;
-
-        database = {
-          type = "pgsql";
-          host = "/run/postgresql";
-        };
-      };
-
-      modules.persistence.directories = [
-        "/var/lib/freshrss"
-      ];
-
-      services.nginx.virtualHosts.${cfg.realHost} = {
-        forceSSL = true;
-        useACMEHost = cfg.domain;
-      };
-    }
-    (mkIf cfg.bridge.enable {
-      services.rss-bridge = {
-        enable = true;
-        virtualHost = cfg.bridge.realHost;
-      } // optionalAttrs (cfg.bridge.whitelist != []) {
-        whitelist = cfg.bridge.whitelist;
-      };
-
-      modules.persistence.directories = [
-        "/var/lib/rss-bridge"
-      ];
-
-      services.nginx.virtualHosts.${cfg.bridge.realHost} = {
-        forceSSL = true;
-        useACMEHost = cfg.bridge.domain;
-      };
-     })
-  ]);
-}
diff --git a/modules/services/searx.nix b/modules/services/searx.nix
deleted file mode 100644
index 98f27d9..0000000
--- a/modules/services/searx.nix
+++ /dev/null
@@ -1,50 +0,0 @@
-{ config, lib, pkgs, ... }:
-
-with lib;
-let
-  cfg = config.modules.services.searx;
-in
-{
-  options.modules.services.searx = {
-    enable = mkEnableOption "searx metasearch engine";
-    package = mkOption { type = types.package; default = pkgs.searxng; };
-    domain = mkOption { type = types.str; };
-    realHost = mkOption { type = types.str; };
-    secrets.searx-env = mkOption { type = types.path; description = "path to the searx secret envfile"; };
-  };
-
-  config = mkIf cfg.enable {
-    services.searx = {
-      enable = true;
-      package = cfg.package;
-      environmentFile = cfg.secrets.searx-env;
-      runInUwsgi = true;
-      settings = {
-        use_default_settings = true;
-
-        general.instance_name = "exotic.sh search";
-        server.secret_key = "@SEARX_SECRET_KEY@";
-      };
-      uwsgiConfig = {
-        socket = "/run/searx/searx.sock";
-        chmod-socket = "660";
-        cache2 = "name=searx_cache,items=2000,blocks=2000,blocksize=4096,bitmap=1";
-        disable-logging = true; # public service
-      };
-    };
-
-    users.extraUsers.nginx.extraGroups = [ "searx" ];
-
-    services.nginx.virtualHosts.${cfg.realHost} = {
-      forceSSL = true;
-      useACMEHost = cfg.domain;
-      locations."/".extraConfig = ''
-        proxy_set_header Host $host;
-        access_log off; # public service
-        uwsgi_pass unix:/run/searx/searx.sock;
-        include ${pkgs.nginx}/conf/uwsgi_params;
-      '';
-      locations."/static/".alias = "${cfg.package}/share/static/";
-    };
-  };
-}
diff --git a/modules/services/sefidel-web.nix b/modules/services/sefidel-web.nix
deleted file mode 100644
index fdbcb00..0000000
--- a/modules/services/sefidel-web.nix
+++ /dev/null
@@ -1,26 +0,0 @@
-{ inputs, config, lib, ... }:
-
-with lib;
-let
-  cfg = config.modules.services.sefidel-web;
-in
-{
-  options.modules.services.sefidel-web = {
-    enable = mkEnableOption "sefidel-web";
-  };
-
-  config = mkIf cfg.enable {
-    services.nginx.virtualHosts."sefidel.net" = {
-      useACMEHost = "sefidel.net";
-      forceSSL = true;
-      # TODO: causes css to be fetched every single time.
-      # This is because heuristic caching is disabled, since Nix removes the last-modified timestamp.
-      root = inputs.sefidel-web.defaultPackage.${config.nixpkgs.system};
-
-      # Fixes the problem above.
-      locations."~ \\.(js|css|woff|woff2?|png|jpe?g|svg)$".extraConfig = ''
-        add_header Cache-Control "public, max-age=14400, must-revalidate";
-      '';
-    };
-  };
-}
diff --git a/modules/services/soju.nix b/modules/services/soju.nix
deleted file mode 100644
index b2f4faf..0000000
--- a/modules/services/soju.nix
+++ /dev/null
@@ -1,48 +0,0 @@
-{ config, lib, ... }:
-
-with lib;
-let
-  cfg = config.modules.services.soju;
-in
-{
-  disabledModules = [
-    "services/networking/soju.nix"
-  ];
-
-  imports = [
-    ../../overlays/soju-module.nix
-  ];
-
-  options.modules.services.soju = {
-    enable = mkEnableOption "soju bouncer";
-
-    hostName = mkOption { type = types.str; default = config.networking.hostName; };
-    port = mkOption { type = types.port; default = 6697; };
-    tls = {
-      enable = mkEnableOption "enable TLS encryption";
-      acmeHost = mkOption { type = types.str; };
-    };
-  };
-
-  config = mkIf cfg.enable {
-    services.soju = {
-      enable = true;
-      extraGroups = [ "acme" ];
-      hostName = cfg.hostName;
-      listen = [ ":${toString cfg.port}" ];
-    } // optionalAttrs cfg.tls.enable {
-      tlsCertificate = "${config.security.acme.certs.${cfg.tls.acmeHost}.directory}/cert.pem";
-      tlsCertificateKey = "${config.security.acme.certs.${cfg.tls.acmeHost}.directory}/key.pem";
-    };
-
-    systemd.services.soju = {
-      after = [ "acme-finished-${cfg.tls.acmeHost}.target" ];
-    };
-
-    networking.firewall.allowedTCPPorts = [ cfg.port ];
-
-    modules.persistence.directories = [
-      "/var/lib/private/soju"
-    ];
-  };
-}
diff --git a/modules/services/tailscale.nix b/modules/services/tailscale.nix
deleted file mode 100644
index 97e1217..0000000
--- a/modules/services/tailscale.nix
+++ /dev/null
@@ -1,22 +0,0 @@
-{ config, lib, ... }:
-
-with lib;
-let
-  cfg = config.modules.services.tailscale;
-in
-{
-  options.modules.services.tailscale = {
-    enable = mkEnableOption "tailscale";
-  };
-
-  config = mkIf cfg.enable {
-    services.tailscale = {
-      enable = true;
-      useRoutingFeatures = "both";
-    };
-
-    modules.persistence.directories = [
-      "/var/lib/tailscale"
-    ];
-  };
-}
diff --git a/modules/services/vikunja.nix b/modules/services/vikunja.nix
deleted file mode 100644
index c54870b..0000000
--- a/modules/services/vikunja.nix
+++ /dev/null
@@ -1,50 +0,0 @@
-{ config, lib, ... }:
-
-with lib;
-let
-  cfg = config.modules.services.vikunja;
-in
-{
-  options.modules.services.vikunja = {
-    enable = mkEnableOption "vikunja";
-    domain = mkOption { type = types.str; };
-    realHost = mkOption { type = types.str; };
-  };
-
-  config = mkIf cfg.enable {
-    services.vikunja = {
-      enable = true;
-      frontendHostname = cfg.realHost;
-      frontendScheme = "https";
-
-      settings = {
-        service.enableregistration = false;
-      };
-
-      database = {
-        type = "postgres";
-        user = "vikunja";
-        database = "vikunja";
-        host = "/run/postgresql";
-      };
-    };
-
-    services.postgresql.enable = true;
-    services.postgresql.ensureDatabases = [ "vikunja" ];
-    services.postgresql.ensureUsers = [
-      {
-        name = "vikunja";
-        ensureDBOwnership = true;
-      }
-    ];
-
-    modules.persistence.directories = [
-      "/var/lib/private/vikunja"
-    ];
-
-    services.nginx.virtualHosts.${cfg.realHost} = {
-      forceSSL = true;
-      useACMEHost = cfg.domain;
-    };
-  };
-}
diff --git a/modules/sops.nix b/modules/sops.nix
deleted file mode 100644
index bd5156e..0000000
--- a/modules/sops.nix
+++ /dev/null
@@ -1,21 +0,0 @@
-{ config, lib, inputs, ... }:
-
-with lib;
-let
-  cfg = config.modules.sops;
-
-  secretsFile = ../systems/${config.networking.hostName}/secrets/secrets.yaml;
-in
-{
-  imports = [
-    inputs.sops-nix.nixosModules.sops
-  ];
-
-  options.modules.sops = {
-    enable = mkEnableOption "sops secret manager";
-  };
-
-  config = mkIf cfg.enable {
-    sops.defaultSopsFile = secretsFile;
-  };
-}