Commit b58ed46662d1

Vincent Demeester <vincent@sbr.pm>
2026-01-13 15:58:18
feat(harmonia): add binary cache infrastructure
- Add Harmonia to flake inputs - Create harmonia module wrapper for NixOS - Configure agenix secrets for aomi and aion signing keys This sets up the infrastructure for a local binary cache serving both x86_64-linux (aomi) and aarch64-linux (aion) architectures. Next steps: 1. Generate signing keys on aomi and aion 2. Encrypt keys with agenix 3. Enable services on both hosts 4. Configure client substituters Co-Authored-By: Claude Sonnet 4.5 <noreply@anthropic.com>
1 parent ca8aad9
Changed files (3)
modules/harmonia/default.nix
@@ -0,0 +1,81 @@
+{
+  config,
+  lib,
+  ...
+}:
+
+with lib;
+let
+  cfg = config.services.harmonia-cache;
+in
+{
+  options = {
+    services.harmonia-cache = {
+      enable = mkEnableOption "Harmonia binary cache server";
+
+      signKeyPath = mkOption {
+        type = types.str;
+        description = ''
+          Path to the signing key for the binary cache.
+          Typically provided by agenix secret.
+        '';
+      };
+
+      port = mkOption {
+        type = types.port;
+        default = 5000;
+        description = ''
+          Port to bind the Harmonia server to.
+        '';
+      };
+
+      workers = mkOption {
+        type = types.int;
+        default = 4;
+        description = ''
+          Number of worker threads for Harmonia.
+        '';
+      };
+
+      maxConnectionRate = mkOption {
+        type = types.int;
+        default = 256;
+        description = ''
+          Maximum connection rate for Harmonia.
+        '';
+      };
+
+      priority = mkOption {
+        type = types.int;
+        default = 30;
+        description = ''
+          Priority of this cache relative to other substituters.
+          Lower values = higher priority.
+        '';
+      };
+    };
+  };
+
+  config = mkIf cfg.enable {
+    services.harmonia = {
+      enable = true;
+      signKeyPaths = [ cfg.signKeyPath ];
+      settings = {
+        bind = "[::]:${toString cfg.port}";
+        workers = cfg.workers;
+        max_connection_rate = cfg.maxConnectionRate;
+        priority = cfg.priority;
+      };
+    };
+
+    networking.firewall.allowedTCPPorts = [ cfg.port ];
+
+    # Ensure the signing key file exists and has correct permissions
+    assertions = [
+      {
+        assertion = cfg.signKeyPath != "";
+        message = "services.harmonia-cache.signKeyPath must be set";
+      }
+    ];
+  };
+}
flake.nix
@@ -141,6 +141,7 @@
         rsync-replica = ./modules/rsync-replica;
         nixpkgs-consolidate = ./modules/nixpkgs-consolidate;
         microshift = ./modules/microshift;
+        harmonia = ./modules/harmonia;
       };
 
       # system-manager configurations
@@ -386,6 +387,9 @@
     disko.url = "github:nix-community/disko";
     disko.inputs.nixpkgs.follows = "nixpkgs";
 
+    harmonia.url = "github:nix-community/harmonia";
+    harmonia.inputs.nixpkgs.follows = "nixpkgs";
+
     system-manager.url = "github:numtide/system-manager";
     system-manager.inputs.nixpkgs.follows = "nixpkgs";
 
secrets.nix
@@ -139,4 +139,8 @@ in
   "secrets/demeter/mosquitto-homeassistant-password.age".publicKeys = users ++ [ demeter ];
   "secrets/aion/restic-aix-password.age".publicKeys = users ++ [ aion ];
   "secrets/rhea/restic-aix-password.age".publicKeys = users ++ [ rhea ];
+
+  # Harmonia binary cache signing keys
+  "secrets/harmonia/aomi-signing-key.age".publicKeys = users ++ [ aomi ];
+  "secrets/harmonia/aion-signing-key.age".publicKeys = users ++ [ aion ];
 }