From 46048f48ee61dd3f6ed0829089e09d82d0b021ae Mon Sep 17 00:00:00 2001 From: stakeynet Date: Tue, 2 Dec 2025 16:40:42 -0800 Subject: [PATCH] vspd: optionally vendor the webapi (public and templates) --- docs/dcrwallet.md | 2 +- docs/vspd.md | 12 +++++------- modules/vspd.nix | 21 ++++++++++++++++++++- pkgs/vspd.nix | 6 ++++++ 4 files changed, 32 insertions(+), 9 deletions(-) diff --git a/docs/dcrwallet.md b/docs/dcrwallet.md index 43a8c6b..d50d4a3 100644 --- a/docs/dcrwallet.md +++ b/docs/dcrwallet.md @@ -66,7 +66,7 @@ If you run dcrwallet as a service, here's how to intialize a wallet as `root`. ```bash cd /var/lib/dcrwallet -export DCRWALLET_BIN=$(systemctl cat --runtime dcrwallet.service | grep ExecStart | awk '{print $1}' | cut -d= -f2) +export DCRWALLET_BIN=$(systemctl cat --runtime dcrwallet.service | grep ExecStart= | awk '{print $1}' | cut -d= -f2) doas -u dcrwallet $DCRWALLET_BIN \ --configfile=/run/secrets/rendered/dcrwallet.conf \ --appdata=/var/lib/dcrwallet \ diff --git a/docs/vspd.md b/docs/vspd.md index 781f470..7a5cdcc 100644 --- a/docs/vspd.md +++ b/docs/vspd.md @@ -11,9 +11,6 @@ Render `vspd.conf` with `sops-nix` and point the service at it. Example: { # Define credentials as secrets sops.secrets."vspd/adminpass" = {}; - sops.secrets."dcrd/rpcuser" = {}; - sops.secrets."dcrd/rpcpass" = {}; - sops.secrets."dcrwallet/rpcuser" = {}; sops.secrets."dcrwallet/rpcpass" = {}; # Render vspd.conf owned by the vspd service user/group @@ -24,7 +21,7 @@ Render `vspd.conf` with `sops-nix` and point the service at it. Example: restartUnits = [ "vspd.service" ]; content = '' [Application Options] - network = mainnet + network = testnet # Web server listen = 0.0.0.0:8800 @@ -34,14 +31,14 @@ Render `vspd.conf` with `sops-nix` and point the service at it. Example: # dcrd connection dcrdhost = 127.0.0.1:9109 - dcrduser = ${config.sops.placeholder."dcrd/rpcuser"} - dcrdpass = ${config.sops.placeholder."dcrd/rpcpass"} + dcrduser = myusername + dcrdpass = ${config.sops.placeholder."dcrwallet/rpcpass"} dcrdcert = /var/lib/dcrd/rpc.cert # dcrwallet connections # Multiple wallets are comma-separated wallethost = 10.0.0.1:9110,10.0.0.2:9110,10.0.0.3:9110 - walletuser = ${config.sops.placeholder."dcrwallet/rpcuser"},${config.sops.placeholder."dcrwallet/rpcuser"},${config.sops.placeholder."dcrwallet/rpcuser"} + walletuser = wallet1user,wallet2user,wallet3user walletpass = ${config.sops.placeholder."dcrwallet/rpcpass"},${config.sops.placeholder."dcrwallet/rpcpass"},${config.sops.placeholder."dcrwallet/rpcpass"} walletcert = /var/lib/vspd/wallet1.cert,/var/lib/vspd/wallet2.cert,/var/lib/vspd/wallet3.cert ''; @@ -62,6 +59,7 @@ Render `vspd.conf` with `sops-nix` and point the service at it. Example: ## Notes - `vspd` expects its configuration file to be named `vspd.conf` and located in its home directory. The NixOS module handles this by symlinking the file provided in `configFile` to `/var/lib/vspd/vspd.conf` on startup. +- Web assets (`public` and `templates`) are symlinked to `services.vspd.webPath` if it is set (default `null`). Set this to a path (e.g. `/var/www/vspd`) to serve these assets with a web server like Caddy or Nginx. - `vspd` requires access to the `rpc.cert` files for both `dcrd` and all voting `dcrwallet` instances. Ensure permissions are set correctly so the `vspd` user can read them. - `vspd` periodically writes a backup of its database to `{homedir}/data/{network}/vspd.db-backup`. Ensure this file is backed up regularly. diff --git a/modules/vspd.nix b/modules/vspd.nix index 579198e..fa2079b 100644 --- a/modules/vspd.nix +++ b/modules/vspd.nix @@ -1,6 +1,7 @@ { config, lib, pkgs, ... }: let + dcrdEnabled = config.services.dcrd.enable or false; cfg = config.services.vspd; in { options.services.vspd = with lib; { @@ -30,6 +31,12 @@ in { description = "State directory for vspd"; }; + webPath = mkOption { + type = types.nullOr types.path; + default = null; + description = "Directory for vspd web assets (public and templates)"; + }; + configFile = mkOption { type = types.path; description = "Path to vspd.conf"; @@ -42,10 +49,15 @@ in { home = cfg.dataDir; isSystemUser = true; description = "vspd user"; + # vspd needs read access to the dcrd RPC certificate + extraGroups = lib.optional (dcrdEnabled && config.services.dcrd.group != cfg.group) config.services.dcrd.group; }; users.groups.${cfg.group} = {}; + systemd.tmpfiles.rules = lib.optional (cfg.webPath != null) + "d '${cfg.webPath}' 0755 ${cfg.user} ${cfg.group} - -"; + systemd.services.vspd = { description = "Voting Service Provider Daemon"; wantedBy = [ "multi-user.target" ]; @@ -59,7 +71,14 @@ in { StateDirectoryMode = "0750"; WorkingDirectory = cfg.dataDir; # Link the provided config file to the expected location in homedir - ExecStartPre = "${pkgs.bash}/bin/bash -c 'ln -sf ${cfg.configFile} ${cfg.dataDir}/vspd.conf'"; + ExecStartPre = "${pkgs.writeShellScript "vspd-pre-start" '' + set -e + ln -sf ${cfg.configFile} ${cfg.dataDir}/vspd.conf + ${lib.optionalString (cfg.webPath != null) '' + ln -sfn ${cfg.package}/share/vspd/internal/webapi/public ${cfg.webPath}/public + ln -sfn ${cfg.package}/share/vspd/internal/webapi/templates ${cfg.webPath}/templates + ''} + ''}"; ExecStart = "${lib.getExe cfg.package} --homedir=${cfg.dataDir}"; Restart = "on-failure"; RestartSec = "10s"; diff --git a/pkgs/vspd.nix b/pkgs/vspd.nix index 5d2c904..6c9d97a 100644 --- a/pkgs/vspd.nix +++ b/pkgs/vspd.nix @@ -22,6 +22,12 @@ buildGoModule (finalAttrs: { "cmd/vspadmin" ]; + postInstall = '' + mkdir -p $out/share/vspd/internal/webapi + cp -r internal/webapi/public $out/share/vspd/internal/webapi/ + cp -r internal/webapi/templates $out/share/vspd/internal/webapi/ + ''; + meta = { homepage = "https://github.com/decred/vspd"; description = "Voting Service Provider Daemon";