From 3a885463f0ecfd863a30915ac18b3445e339cd2f Mon Sep 17 00:00:00 2001 From: ashisgreat22 Date: Tue, 17 Mar 2026 20:55:15 +0100 Subject: [PATCH] Add OpenClaw AI Agent module - Systemd service running OpenClaw gateway - Configurable via sops secrets - Runs on localhost:18789 Co-Authored-By: Claude Opus 4.6 --- configuration.nix | 18 ++++++ modules/default.nix | 1 + modules/openclaw-config.json | 80 +++++++++++++++++++++++++ modules/openclaw.nix | 111 +++++++++++++++++++++++++++++++++++ 4 files changed, 210 insertions(+) create mode 100644 modules/openclaw-config.json create mode 100644 modules/openclaw.nix diff --git a/configuration.nix b/configuration.nix index 02770c1..028751e 100644 --- a/configuration.nix +++ b/configuration.nix @@ -86,4 +86,22 @@ }; }; }; + + # === OpenClaw === + myModules.openclaw = { + enable = true; + port = 18789; + environmentFile = config.sops.templates."openclaw.env".path; + }; + + # OpenClaw secrets + sops.secrets.openclaw_discord_token = { }; + sops.secrets.openclaw_openai_api_key = { }; + + sops.templates."openclaw.env" = { + content = '' + DISCORD_TOKEN=${config.sops.placeholder.openclaw_discord_token} + OPENAI_API_KEY=${config.sops.placeholder.openclaw_openai_api_key} + ''; + }; } diff --git a/modules/default.nix b/modules/default.nix index e743ff5..1abbb44 100644 --- a/modules/default.nix +++ b/modules/default.nix @@ -5,5 +5,6 @@ ./podman.nix ./nginx.nix ./searxng.nix + ./openclaw.nix ]; } diff --git a/modules/openclaw-config.json b/modules/openclaw-config.json new file mode 100644 index 0000000..3f11fd7 --- /dev/null +++ b/modules/openclaw-config.json @@ -0,0 +1,80 @@ +{ + "gateway": { + "port": 18789, + "bind": "loopback", + "trustedProxies": ["::1", "127.0.0.1", "10.88.0.0/16", "10.89.0.0/16"], + "auth": { + "mode": "none" + }, + "controlUi": { + "dangerouslyAllowHostHeaderOriginFallback": true, + "allowedOrigins": ["*"] + } + }, + "channels": { + "whatsapp": { + "enabled": false + }, + "discord": { + "enabled": true, + "groupPolicy": "open", + "dmPolicy": "open", + "allowFrom": ["*"] + } + }, + "agents": { + "defaults": { + "model": { + "primary": "openai/gemini-3.1-pro-high" + }, + "memorySearch": { + "provider": "openai", + "model": "nomic-embed-text", + "remote": { + "baseUrl": "http://localhost:11434/v1" + } + } + } + }, + "tools": { + "exec": { + "security": "full", + "ask": "off" + } + }, + "skills": { + "entries": {} + }, + "commands": { + "native": true, + "nativeSkills": "auto", + "restart": true, + "ownerDisplay": "raw" + }, + "models": { + "mode": "merge", + "providers": { + "openai": { + "baseUrl": "http://localhost:8045/v1/chat/completions", + "apiKey": "${OPENAI_API_KEY}", + "api": "openai", + "models": [ + { + "id": "gemini-3.1-pro-high", + "name": "Gemini 3.1 Pro High", + "reasoning": true, + "contextWindow": 1000000, + "maxTokens": 65536 + }, + { + "id": "claude-opus-4-6-thinking", + "name": "Claude Opus 4.6 Thinking", + "reasoning": true, + "contextWindow": 1000000, + "maxTokens": 65536 + } + ] + } + } + } +} diff --git a/modules/openclaw.nix b/modules/openclaw.nix new file mode 100644 index 0000000..594bc0b --- /dev/null +++ b/modules/openclaw.nix @@ -0,0 +1,111 @@ +# OpenClaw Module +# Provides: AI Agent with Discord integration +# +# Usage: +# myModules.openclaw = { +# enable = true; +# port = 18789; +# }; + +{ + config, + lib, + pkgs, + ... +}: + +let + cfg = config.myModules.openclaw; + configDir = "/var/lib/openclaw/config"; + dataDir = "/var/lib/openclaw/data"; + workspaceDir = "/var/lib/openclaw/workspace"; +in +{ + options.myModules.openclaw = { + enable = lib.mkEnableOption "OpenClaw AI Agent"; + + port = lib.mkOption { + type = lib.types.port; + default = 18789; + description = "Gateway port for OpenClaw"; + }; + + environmentFile = lib.mkOption { + type = lib.types.nullOr lib.types.path; + default = null; + description = "Path to environment file with API keys"; + }; + }; + + config = lib.mkIf cfg.enable { + # Create user for openclaw + users.users.openclaw = { + isSystemUser = true; + group = "openclaw"; + home = "/var/lib/openclaw"; + createHome = true; + }; + users.groups.openclaw = { }; + + # Create directories + systemd.tmpfiles.settings."10-openclaw" = { + "${configDir}".d = { + user = "openclaw"; + group = "openclaw"; + mode = "0700"; + }; + "${dataDir}".d = { + user = "openclaw"; + group = "openclaw"; + mode = "0700"; + }; + "${workspaceDir}".d = { + user = "openclaw"; + group = "openclaw"; + mode = "0700"; + }; + }; + + # Copy config file + environment.etc."openclaw/openclaw.json".source = ./openclaw-config.json; + + # Systemd service + systemd.services.openclaw = { + description = "OpenClaw AI Agent"; + after = [ "network.target" ]; + wantedBy = [ "multi-user.target" ]; + + serviceConfig = { + Type = "simple"; + User = "openclaw"; + Group = "openclaw"; + WorkingDirectory = dataDir; + + Environment = [ + "NODE_ENV=production" + "OPENCLAW_CONFIG_DIR=${configDir}" + "OPENCLAW_DATA_DIR=${dataDir}" + "OPENCLAW_WORKSPACE_DIR=${workspaceDir}" + ]; + + ExecStartPre = [ + "${pkgs.coreutils}/bin/mkdir -p ${configDir} ${dataDir} ${workspaceDir}" + "${pkgs.coreutils}/bin/cp -n /etc/openclaw/openclaw.json ${configDir}/ || true" + ]; + + ExecStart = "${pkgs.nodejs_22}/bin/npx openclaw gateway start --port ${toString cfg.port}"; + + Restart = "on-failure"; + RestartSec = "10s"; + + # Security + PrivateTmp = true; + ProtectSystem = "strict"; + ReadWritePaths = [ configDir dataDir workspaceDir ]; + NoNewPrivileges = true; + }; + } // lib.optionalAttrs (cfg.environmentFile != null) { + serviceConfig.EnvironmentFile = cfg.environmentFile; + }; + }; +}