diff --git a/flake.nix b/flake.nix index e1ffe93..388ab2c 100644 --- a/flake.nix +++ b/flake.nix @@ -8,10 +8,14 @@ inputs.darwin.follows = ""; inputs.nixpkgs.follows = "nixpkgs"; }; + lix = { + url = "git+https://git.lix.systems/lix-project/lix?ref=main"; + inputs.nixpkgs.follows = "nixpkgs"; + }; self.submodules = true; }; - outputs = { self, nixpkgs, agenix, ... }@inputs: + outputs = { self, nixpkgs, agenix, lix, ... }@inputs: let system = "x86_64-linux"; keys = import ./lib/keys.nix; @@ -26,6 +30,9 @@ pkgs = import nixpkgs { inherit system overlays; config.allowUnfree = true; + config.permittedInsecurePackages = [ + "openclaw-2026.3.12" + ]; }; devShell = import ./shells/nix_dev.nix { @@ -35,12 +42,16 @@ { nixosConfigurations = { lazyworkhorse = nixpkgs.lib.nixosSystem { - specialArgs = { inherit system self keys paths; }; + specialArgs = { inherit system self keys paths inputs; }; modules = [ { nixpkgs.overlays = overlays; nixpkgs.config.allowUnfree = true; nixpkgs.config.rocmSupport = true; + nixpkgs.config.permittedInsecurePackages = [ + "openclaw-2026.3.12" + ]; + nix.package = lix.packages.${system}.default; } agenix.nixosModules.default ./hosts/lazyworkhorse/configuration.nix @@ -49,6 +60,7 @@ ./modules/nixos/services/docker_manager.nix ./modules/nixos/services/open_code_server.nix ./modules/nixos/services/ollama_init_custom_models.nix + ./modules/nixos/services/openclaw_node.nix ./users/gortium.nix ]; }; diff --git a/hosts/lazyworkhorse/configuration.nix b/hosts/lazyworkhorse/configuration.nix index 828868c..290916e 100644 --- a/hosts/lazyworkhorse/configuration.nix +++ b/hosts/lazyworkhorse/configuration.nix @@ -209,6 +209,7 @@ coms = { path = self + "/assets/compose/coms"; + envFile = config.age.secrets.containers_env.path; }; finance = { @@ -255,9 +256,26 @@ # mode = "0600"; # path = "/home/n8n-worker/.ssh/n8n_ssh_key"; # }; + openclaw_gateway_token = { + file = ../../secrets/openclaw_gateway_token.age; + owner = "root"; + group = "openclaw-node"; + mode = "0440"; + path = "/run/secrets/openclaw_gateway_token"; + }; }; }; + # OpenClaw Node service (host-side execution for Docker gateway) + services.openclaw-node = { + enable = true; + user = "ai-worker"; + gatewayHost = "127.0.0.1"; + gatewayPort = 18789; + gatewayTokenFile = "/run/secrets/openclaw_gateway_token"; + displayName = "lazyworkhorse-host"; + }; + # Public host ssh key (kept in sync with the private one) environment.etc."ssh/ssh_host_ed25519_key.pub".text = "${keys.hosts.lazyworkhorse.main}"; diff --git a/modules/nixos/services/openclaw_node.nix b/modules/nixos/services/openclaw_node.nix new file mode 100644 index 0000000..376ff30 --- /dev/null +++ b/modules/nixos/services/openclaw_node.nix @@ -0,0 +1,69 @@ +{ config, lib, pkgs, ... }: + +let + cfg = config.services.openclaw-node; + openclawPkg = pkgs.openclaw; +in { + options.services.openclaw-node = { + enable = lib.mkEnableOption "OpenClaw Node service"; + + user = lib.mkOption { + type = lib.types.str; + default = "ai-worker"; + description = "User to run the OpenClaw headless node as."; + }; + + gatewayHost = lib.mkOption { + type = lib.types.str; + default = "127.0.0.1"; + description = "Gateway host (IP or hostname)."; + }; + + gatewayPort = lib.mkOption { + type = lib.types.int; + default = 18789; + description = "Gateway WebSocket port."; + }; + + gatewayTokenFile = lib.mkOption { + type = lib.types.str; + default = ""; + description = "Path to file containing the gateway auth token."; + }; + + displayName = lib.mkOption { + type = lib.types.str; + default = "lazyworkhorse-host"; + description = "Display name for this node (shown in pairing)."; + }; + }; + + config = lib.mkIf cfg.enable { + systemd.services.openclaw-node = { + description = "OpenClaw Headless Node Service"; + after = [ "network.target" ]; + wantedBy = [ "multi-user.target" ]; + + serviceConfig = { + Type = "exec"; + User = cfg.user; + Group = cfg.user; + WorkingDirectory = "/var/lib/${cfg.user}"; + ExecStart = '' + ${openclawPkg}/bin/openclaw \ + node run \ + --host ${cfg.gatewayHost} \ + --port ${toString cfg.gatewayPort} \ + --display-name "${cfg.displayName}" + ''; + Restart = "on-failure"; + RestartSec = 10; + }; + + environment = { + OPENCLAW_GATEWAY_TOKEN_FILE = cfg.gatewayTokenFile; + NODE_ENV = "production"; + }; + }; + }; +} diff --git a/secrets/openclaw_gateway_token.age b/secrets/openclaw_gateway_token.age new file mode 100644 index 0000000..e0de049 --- /dev/null +++ b/secrets/openclaw_gateway_token.age @@ -0,0 +1,11 @@ +-----BEGIN AGE ENCRYPTED FILE----- +YWdlLWVuY3J5cHRpb24ub3JnL3YxCi0+IHNzaC1lZDI1NTE5IEdoTUQ4QSBCWEpO +cG9yNnFpcHFqTkNzTngxU1MxN0NYK0hrZFhUTjVORWFrK3JNd2tZCmtMTGpwQk1E +WlUwL3N6SGRWblpnNEkrWkkyU2hQMkRIK0M3R0pOVEREV3MKLT4gY2osLWdyZWFz +ZSBacSozVVQgUCAxRS1OQSAuKXxDPCoKbStWNW1BZjBZQzNDaTlDbU5EZkxsRWxM +cXJ3dDU1RDNpOXRlV0tzdEp2NUo3S1lhRG5Md0RHTGlJdkFSYmt5YQo4R1hiQWRG +V2VxekJKZwotLS0geG1XSi9VbkhXZHQzcEFVS3hKNzVueXFLa2xnZTc3Q2tJTVZ5 +eXJabWk5Ywp6bJCP3s0xxzjE+eTR+cv7ZUnkoliT/n7uIprq1BTn/LIRLkUTUqs3 +NiDwrXcoq4/QKd0Dt+8ap3vFAuusjGxRlnYMaRrZie2AGtTV8U7Q7durm9o2K+/4 +QzRQ/MtumIQm +-----END AGE ENCRYPTED FILE----- diff --git a/secrets/secrets.nix b/secrets/secrets.nix index 51ea713..d5c44d6 100644 --- a/secrets/secrets.nix +++ b/secrets/secrets.nix @@ -10,4 +10,5 @@ in "containers.env.age".publicKeys = authorizedKeys; "lazyworkhorse_host_ssh_key.age".publicKeys = authorizedKeys; "n8n_ssh_key.age".publicKeys = authorizedKeys; + "openclaw_gateway_token.age".publicKeys = authorizedKeys; }