From 3a1cb7487a9bff28bcaf106308e8a1d1a3eff685 Mon Sep 17 00:00:00 2001 From: Harald Hoyer Date: Tue, 5 May 2026 13:42:52 +0200 Subject: [PATCH] refactor(opencode): extract serve service into shared NixOS module New `metacfg.services.opencode` module under modules/nixos/services/opencode/ with options for port, user, homeDir, sopsFile, and extraPackages. User and homeDir default off `metacfg.user`. Host configs for amd and sgx reduce to enabling the module and pointing at their respective sops file. Service PATH gains jq, yq-go, python3, gh, gnutar, gzip, unzip, wget, diffutils, patch, file, tree, bun, uv, ast-grep, claude-code, and tmux for agent ergonomics. Co-Authored-By: Claude Opus 4.7 (1M context) --- modules/nixos/services/opencode/default.nix | 115 ++++++++++++++++++++ systems/x86_64-linux/amd/opencode.nix | 60 +--------- systems/x86_64-linux/sgx/opencode.nix | 60 +--------- 3 files changed, 119 insertions(+), 116 deletions(-) create mode 100644 modules/nixos/services/opencode/default.nix diff --git a/modules/nixos/services/opencode/default.nix b/modules/nixos/services/opencode/default.nix new file mode 100644 index 0000000..d6473c6 --- /dev/null +++ b/modules/nixos/services/opencode/default.nix @@ -0,0 +1,115 @@ +{ + config, + pkgs, + lib, + ... +}: +with lib; +with lib.metacfg; +let + cfg = config.metacfg.services.opencode; +in +{ + options.metacfg.services.opencode = with types; { + enable = mkBoolOpt false "Whether or not to enable the OpenCode web server."; + port = mkOption { + type = types.port; + default = 4196; + description = "Port for the OpenCode web server to listen on."; + }; + user = mkOption { + type = types.str; + default = config.metacfg.user.name; + defaultText = literalExpression "config.metacfg.user.name"; + description = "User to run the OpenCode service as."; + }; + homeDir = mkOption { + type = types.path; + default = config.users.users.${cfg.user}.home; + defaultText = literalExpression "config.users.users.\${cfg.user}.home"; + description = "Home directory used as the working directory for the service."; + }; + sopsFile = mkOption { + type = types.path; + description = "Path to the sops-encrypted yaml file containing opencode-web-password."; + }; + extraPackages = mkOption { + type = types.listOf types.package; + default = [ ]; + description = "Additional packages to add to the service PATH."; + }; + }; + + config = mkIf cfg.enable { + systemd.services.opencode-serve = { + description = "OpenCode Web Server"; + after = [ "network.target" ]; + wantedBy = [ "multi-user.target" ]; + + path = + (with pkgs; [ + git + bash + coreutils + findutils + gnused + gnugrep + gawk + gnumake + nix + nodejs + ripgrep + fd + curl + which + jq + yq-go + python3 + gh + gnutar + gzip + unzip + wget + diffutils + patch + file + tree + bun + uv + ast-grep + claude-code + tmux + ]) + ++ cfg.extraPackages; + + environment = { + HOME = cfg.homeDir; + LD_LIBRARY_PATH = "${pkgs.stdenv.cc.cc.lib}/lib"; + }; + + serviceConfig = { + Type = "simple"; + User = cfg.user; + Group = "users"; + WorkingDirectory = cfg.homeDir; + ExecStart = "${pkgs.opencode}/bin/opencode serve --hostname 127.0.0.1 --port ${toString cfg.port}"; + Restart = "always"; + RestartSec = 5; + EnvironmentFile = config.sops.secrets.opencode-web-password.path; + + # Security hardening + PrivateTmp = true; + ProtectSystem = "strict"; + ProtectHome = false; + NoNewPrivileges = true; + ReadWritePaths = [ cfg.homeDir ]; + }; + }; + + sops.secrets.opencode-web-password = { + inherit (cfg) sopsFile; + owner = cfg.user; + restartUnits = [ "opencode-serve.service" ]; + }; + }; +} diff --git a/systems/x86_64-linux/amd/opencode.nix b/systems/x86_64-linux/amd/opencode.nix index d862c8c..6e3242c 100644 --- a/systems/x86_64-linux/amd/opencode.nix +++ b/systems/x86_64-linux/amd/opencode.nix @@ -1,65 +1,9 @@ { - config, - pkgs, - lib, ... }: - -let - port = 4196; - user = "harald"; - homeDir = "/home/harald"; -in { - systemd.services.opencode-serve = { - description = "OpenCode Web Server"; - after = [ "network.target" ]; - wantedBy = [ "multi-user.target" ]; - - path = with pkgs; [ - git - bash - coreutils - findutils - gnused - gnugrep - gawk - gnumake - nix - nodejs - ripgrep - fd - curl - which - ]; - - environment = { - HOME = homeDir; - LD_LIBRARY_PATH = "${pkgs.stdenv.cc.cc.lib}/lib"; - }; - - serviceConfig = { - Type = "simple"; - User = user; - Group = "users"; - WorkingDirectory = homeDir; - ExecStart = "${pkgs.opencode}/bin/opencode serve --hostname 127.0.0.1 --port ${toString port}"; - Restart = "always"; - RestartSec = 5; - EnvironmentFile = config.sops.secrets.opencode-web-password.path; - - # Security hardening - PrivateTmp = true; - ProtectSystem = "strict"; - ProtectHome = false; - NoNewPrivileges = true; - ReadWritePaths = [ homeDir ]; - }; - }; - - sops.secrets.opencode-web-password = { + metacfg.services.opencode = { + enable = true; sopsFile = ../../../.secrets/amd/opencode-web.yaml; - owner = user; - restartUnits = [ "opencode-serve.service" ]; }; } diff --git a/systems/x86_64-linux/sgx/opencode.nix b/systems/x86_64-linux/sgx/opencode.nix index 0060f25..f04fd1b 100644 --- a/systems/x86_64-linux/sgx/opencode.nix +++ b/systems/x86_64-linux/sgx/opencode.nix @@ -1,65 +1,9 @@ { - config, - pkgs, - lib, ... }: - -let - port = 4196; - user = "harald"; - homeDir = "/home/harald"; -in { - systemd.services.opencode-serve = { - description = "OpenCode Web Server"; - after = [ "network.target" ]; - wantedBy = [ "multi-user.target" ]; - - path = with pkgs; [ - git - bash - coreutils - findutils - gnused - gnugrep - gawk - gnumake - nix - nodejs - ripgrep - fd - curl - which - ]; - - environment = { - HOME = homeDir; - LD_LIBRARY_PATH = "${pkgs.stdenv.cc.cc.lib}/lib"; - }; - - serviceConfig = { - Type = "simple"; - User = user; - Group = "users"; - WorkingDirectory = homeDir; - ExecStart = "${pkgs.opencode}/bin/opencode serve --hostname 127.0.0.1 --port ${toString port}"; - Restart = "always"; - RestartSec = 5; - EnvironmentFile = config.sops.secrets.opencode-web-password.path; - - # Security hardening - PrivateTmp = true; - ProtectSystem = "strict"; - ProtectHome = false; - NoNewPrivileges = true; - ReadWritePaths = [ homeDir ]; - }; - }; - - sops.secrets.opencode-web-password = { + metacfg.services.opencode = { + enable = true; sopsFile = ../../../.secrets/sgx/opencode-web.yaml; - owner = user; - restartUnits = [ "opencode-serve.service" ]; }; }