feat(nixos): NixOS module with systemd hardening#3
Merged
jeanlucthumm merged 23 commits intomainfrom Feb 9, 2026
Merged
Conversation
Add system service module that runs the gateway as an isolated system user with systemd hardening (ProtectHome, PrivateTmp, NoNewPrivileges, etc.). Exports nixosModules.openclaw from the flake. Based on work by @das-monki.
Tests: - Service starts successfully - User/group created (clawdbot:clawdbot) - State directories exist with correct ownership - Config file symlinked to /var/lib/clawdbot - Hardening: ProtectHome hides /home from service - Service runs as clawdbot user Run with: nix build .#checks.x86_64-linux.nixos-module -L Interactive: nix build .#checks.x86_64-linux.nixos-module.driverInteractive
The /run/agenix and /run/secrets paths were causing service startup failure when they don't exist. With ProtectSystem=strict, /run/* is already readable, so these explicit paths are unnecessary.
Adds providers.anthropic.oauthCredentialsDir option that bind-mounts the user's ~/.claude directory into the service's sandbox. This allows using Claude Pro/Max subscription via OAuth while maintaining isolation. The service: - Still has ProtectHome=true (can't see /home generally) - Gets read-write access to ONLY the specified .claude dir via BindPaths - Can refresh OAuth tokens as needed Example: services.clawdbot.providers.anthropic.oauthCredentialsDir = "/home/user/.claude";
Adds second test node (oauth) that verifies: - Service starts with oauthCredentialsDir configured - Credentials are accessible via bind-mount at /var/lib/clawdbot/.claude - Other files in /home remain inaccessible (ProtectHome still works)
The gateway uses os.networkInterfaces() which requires AF_NETLINK sockets to enumerate interfaces. Without this, the service fails with: uv_interface_addresses returned Unknown system error 97
System services aren't exposed externally, so disable gateway auth by default. Users can override via configOverrides if needed.
Match home-manager behavior - don't set gateway.auth.mode in the module. Users can configure via configOverrides based on their use case.
Upstream now requires gateway authentication by default (c4a80f4ed).
Add gateway.auth.{mode,tokenFile,passwordFile} options to support this.
Users can either:
- Set tokenFile/passwordFile to load credentials from files at runtime
- Use configOverrides to set gateway.auth.token directly in the config
The wrapper script loads credentials from files and sets the appropriate
environment variables (CLAWDBOT_GATEWAY_TOKEN/CLAWDBOT_GATEWAY_PASSWORD).
The @mariozechner/clipboard native module (transitive dependency from pi-tui) needs resource syscalls that were blocked by ~@resources filter, causing SIGSYS crashes on headless systems.
Remove ~@PRIVILEGED and ~@resources filters - Node.js with native modules needs these syscalls. Security is maintained through: - CapabilityBoundingSet = "" (no capabilities) - NoNewPrivileges = true - ProtectHome, ProtectSystem = strict - RestrictNamespaces, PrivateDevices, PrivateTmp
Instance-level providers.telegram and providers.anthropic options now default to the top-level cfg values instead of hardcoded defaults. This ensures that when users set top-level providers and only override specific instance options (like configOverrides), the provider settings are still inherited.
BindPaths can't access /home when ProtectHome=true, so disable it when oauthCredentialsDir is configured (typically points to ~/.claude).
The short-lived OAuth tokens from Claude CLI's .credentials.json aren't practical for server deployments. Replace with oauthTokenFile which loads a long-lived token from `claude setup-token`. - Remove oauthCredentialsDir option and bind mount logic - Add oauthTokenFile option (sets ANTHROPIC_OAUTH_TOKEN env var) - Restore ProtectHome=true now that we don't need /home access - Update module header with new example usage
The OAuth bind-mount test referenced oauthCredentialsDir which was removed in ddc7bd5. The new oauthTokenFile approach doesn't need bind mounts - tokens are loaded via env vars from paths outside /home.
These options were defined but never wired up to the config generation. Rather than ship dead options, remove them and add a note pointing to the home-manager module which has the full implementation.
Add documents-skills.nix with parallel implementation to home-manager: - Documents: copies AGENTS.md, SOUL.md, TOOLS.md to workspace with appended Nix-managed tools report - Skills: supports copy and inline modes (symlink omitted for system service where it doesn't make sense) - Uses systemd-tmpfiles for installation The implementation is kept separate to ease future consolidation with the home-manager module.
The `config` option (using generatedConfigOptions from upstream schema) was defined but never wired into config generation. Users setting `inst.config.*` would see no effect, which is confusing. The `configOverrides` option remains as the escape hatch for arbitrary JSON config. If typed schema options are needed later, they can be added with actual implementation.
Fail early with clear messages when: - Neither apiKeyFile nor oauthTokenFile is set for Anthropic - gateway.auth.tokenFile is missing when mode is "token" - gateway.auth.passwordFile is missing when mode is "password" Update test to provide dummy tokens to satisfy assertions.
The instances option was defined in both options.nix and clawdbot.nix. The one in clawdbot.nix always overrode the one in options.nix, making the latter dead code.
This file contains hidden or bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Sign up for free
to join this conversation on GitHub.
Already have an account?
Sign in to comment
Add this suggestion to a batch that can be applied as a single commit.This suggestion is invalid because no changes were made to the code.Suggestions cannot be applied while the pull request is closed.Suggestions cannot be applied while viewing a subset of changes.Only one suggestion per line can be applied in a batch.Add this suggestion to a batch that can be applied as a single commit.Applying suggestions on deleted lines is not supported.You must change the existing code in this line in order to create a valid suggestion.Outdated suggestions cannot be applied.This suggestion has been applied or marked resolved.Suggestions cannot be applied from pending reviews.Suggestions cannot be applied on multi-line comments.Suggestions cannot be applied while the pull request is queued to merge.Suggestion cannot be applied right now. Please check back later.
Summary
Adds a NixOS module (
nixosModules.openclaw) that runs the gateway as an isolated system user with systemd hardening. Contains the blast radius if the LLM is compromised.openclawsystem user with minimal privilegesProtectHome,PrivateTmp,NoNewPrivileges, syscall filtering, namespace isolationinstances.<name>Context
Based on upstream openclaw#24.