Add Lightning.Pub NixOS module
Some checks are pending
nix-bitcoin tests / build_test_drivers (push) Waiting to run
nix-bitcoin tests / test_scenario (default) (push) Blocked by required conditions
nix-bitcoin tests / test_scenario (joinmarket-bitcoind-29) (push) Blocked by required conditions
nix-bitcoin tests / test_scenario (netns) (push) Blocked by required conditions
nix-bitcoin tests / test_scenario (netnsRegtest) (push) Blocked by required conditions
nix-bitcoin tests / check_flake (push) Waiting to run
Some checks are pending
nix-bitcoin tests / build_test_drivers (push) Waiting to run
nix-bitcoin tests / test_scenario (default) (push) Blocked by required conditions
nix-bitcoin tests / test_scenario (joinmarket-bitcoind-29) (push) Blocked by required conditions
nix-bitcoin tests / test_scenario (netns) (push) Blocked by required conditions
nix-bitcoin tests / test_scenario (netnsRegtest) (push) Blocked by required conditions
nix-bitcoin tests / check_flake (push) Waiting to run
Lightning.Pub is a Lightning Network account system running on top of LND. The module follows nix-bitcoin patterns with a build oneshot service and a hardened runtime service wired to LND via gRPC. Co-Authored-By: Claude Opus 4.6 <noreply@anthropic.com>
This commit is contained in:
parent
216368a688
commit
dd399773da
2 changed files with 218 additions and 0 deletions
217
modules/lightning-pub.nix
Normal file
217
modules/lightning-pub.nix
Normal file
|
|
@ -0,0 +1,217 @@
|
|||
{ config, lib, pkgs, ... }:
|
||||
|
||||
with lib;
|
||||
|
||||
let
|
||||
options.services.lightning-pub = {
|
||||
enable = mkEnableOption "Lightning.Pub, a Lightning Network account system running on top of LND";
|
||||
|
||||
port = mkOption {
|
||||
type = types.port;
|
||||
default = 1776;
|
||||
description = "Port for the Lightning.Pub REST API.";
|
||||
};
|
||||
|
||||
dataDir = mkOption {
|
||||
type = types.path;
|
||||
default = "/var/lib/lightning-pub";
|
||||
description = "Data directory for Lightning.Pub.";
|
||||
};
|
||||
|
||||
user = mkOption {
|
||||
type = types.str;
|
||||
default = "lightning-pub";
|
||||
description = "User to run Lightning.Pub as.";
|
||||
};
|
||||
|
||||
group = mkOption {
|
||||
type = types.str;
|
||||
default = cfg.user;
|
||||
description = "Group to run Lightning.Pub as.";
|
||||
};
|
||||
|
||||
source = {
|
||||
url = mkOption {
|
||||
type = types.str;
|
||||
default = "https://git.atitlan.io/aiolabs/lightning-pub";
|
||||
description = "Git repository URL for Lightning.Pub source.";
|
||||
};
|
||||
|
||||
ref = mkOption {
|
||||
type = types.str;
|
||||
default = "master";
|
||||
description = "Git ref (branch, tag, or commit) to checkout.";
|
||||
};
|
||||
};
|
||||
|
||||
logLevel = mkOption {
|
||||
type = types.enum [ "DEBUG" "INFO" "WARN" "ERROR" ];
|
||||
default = "INFO";
|
||||
description = "Logging level for Lightning.Pub.";
|
||||
};
|
||||
|
||||
nostrRelays = mkOption {
|
||||
type = types.str;
|
||||
default = "wss://relay.lightning.pub";
|
||||
description = "Comma-separated list of Nostr relay WebSocket URLs.";
|
||||
};
|
||||
|
||||
serviceFee = {
|
||||
bps = mkOption {
|
||||
type = types.int;
|
||||
default = 60;
|
||||
description = "Service fee in basis points.";
|
||||
};
|
||||
|
||||
floorSats = mkOption {
|
||||
type = types.int;
|
||||
default = 10;
|
||||
description = "Minimum service fee floor in satoshis.";
|
||||
};
|
||||
};
|
||||
|
||||
watchdogMaxDiffSats = mkOption {
|
||||
type = types.int;
|
||||
default = 0;
|
||||
description = "Maximum allowed balance difference in satoshis for the watchdog (0 = disabled).";
|
||||
};
|
||||
|
||||
extraEnv = mkOption {
|
||||
type = with types; attrsOf str;
|
||||
default = {};
|
||||
description = "Extra environment variables to pass to Lightning.Pub.";
|
||||
};
|
||||
};
|
||||
|
||||
cfg = config.services.lightning-pub;
|
||||
nbLib = config.nix-bitcoin.lib;
|
||||
lnd = config.services.lnd;
|
||||
|
||||
lightningPubEnv = pkgs.writeShellScript "lightning-pub-env" ''
|
||||
set -euo pipefail
|
||||
export PATH=${pkgs.nodejs_22}/bin:$PATH
|
||||
cd ${cfg.dataDir}/source
|
||||
exec "$@"
|
||||
'';
|
||||
|
||||
in {
|
||||
inherit options;
|
||||
|
||||
config = mkIf cfg.enable {
|
||||
services.lnd.enable = true;
|
||||
|
||||
users.users.${cfg.user} = {
|
||||
isSystemUser = true;
|
||||
group = cfg.group;
|
||||
home = cfg.dataDir;
|
||||
extraGroups = [ lnd.group ];
|
||||
};
|
||||
users.groups.${cfg.group} = {};
|
||||
|
||||
nix-bitcoin.operator = {
|
||||
groups = [ cfg.group ];
|
||||
allowRunAsUsers = [ cfg.user ];
|
||||
};
|
||||
|
||||
systemd.tmpfiles.rules = [
|
||||
"d '${cfg.dataDir}' 0770 ${cfg.user} ${cfg.group} - -"
|
||||
];
|
||||
|
||||
# Build service (oneshot) — clones repo, installs deps, compiles TypeScript
|
||||
systemd.services.lightning-pub-build = {
|
||||
description = "Clone and Build Lightning.Pub";
|
||||
wantedBy = [ "multi-user.target" ];
|
||||
after = [ "network-online.target" ];
|
||||
wants = [ "network-online.target" ];
|
||||
|
||||
path = with pkgs; [
|
||||
nodejs_22 python3 git coreutils bash
|
||||
stdenv.cc gnumake pkg-config
|
||||
];
|
||||
|
||||
environment = {
|
||||
HOME = cfg.dataDir;
|
||||
npm_config_cache = "${cfg.dataDir}/.npm-cache";
|
||||
};
|
||||
|
||||
serviceConfig = {
|
||||
Type = "oneshot";
|
||||
RemainAfterExit = true;
|
||||
User = cfg.user;
|
||||
Group = cfg.group;
|
||||
TimeoutStartSec = "30min";
|
||||
ProtectSystem = "strict";
|
||||
ProtectHome = true;
|
||||
NoNewPrivileges = true;
|
||||
ReadWritePaths = [ cfg.dataDir ];
|
||||
PrivateTmp = true;
|
||||
};
|
||||
|
||||
script = ''
|
||||
set -euo pipefail
|
||||
SOURCE_DIR="${cfg.dataDir}/source"
|
||||
|
||||
# Clone or update
|
||||
if [ ! -d "$SOURCE_DIR/.git" ]; then
|
||||
git clone "${cfg.source.url}" "$SOURCE_DIR"
|
||||
cd "$SOURCE_DIR"
|
||||
git checkout "${cfg.source.ref}"
|
||||
NEEDS_BUILD=1
|
||||
else
|
||||
cd "$SOURCE_DIR"
|
||||
git fetch origin
|
||||
LOCAL=$(git rev-parse HEAD)
|
||||
REMOTE=$(git rev-parse "origin/${cfg.source.ref}" 2>/dev/null || git rev-parse "${cfg.source.ref}")
|
||||
if [ "$LOCAL" != "$REMOTE" ]; then
|
||||
git checkout "${cfg.source.ref}"
|
||||
git pull origin "${cfg.source.ref}" 2>/dev/null || true
|
||||
NEEDS_BUILD=1
|
||||
else
|
||||
NEEDS_BUILD=0
|
||||
fi
|
||||
fi
|
||||
|
||||
# Check build artifacts
|
||||
[ ! -d "node_modules" ] || [ ! -d "build" ] && NEEDS_BUILD=1
|
||||
|
||||
[ "$NEEDS_BUILD" = "0" ] && exit 0
|
||||
|
||||
npm install
|
||||
npx tsc
|
||||
'';
|
||||
};
|
||||
|
||||
# Main runtime service
|
||||
systemd.services.lightning-pub = rec {
|
||||
description = "Lightning.Pub";
|
||||
wantedBy = [ "multi-user.target" ];
|
||||
requires = [ "lnd.service" "lightning-pub-build.service" ];
|
||||
after = requires ++ [ "nix-bitcoin-secrets.target" ];
|
||||
|
||||
environment = {
|
||||
PORT = toString cfg.port;
|
||||
DATA_DIR = cfg.dataDir;
|
||||
LOG_LEVEL = cfg.logLevel;
|
||||
NOSTR_RELAYS = cfg.nostrRelays;
|
||||
SERVICE_FEE_BPS = toString cfg.serviceFee.bps;
|
||||
SERVICE_FEE_FLOOR_SATS = toString cfg.serviceFee.floorSats;
|
||||
WATCHDOG_MAX_DIFF_SATS = toString cfg.watchdogMaxDiffSats;
|
||||
LND_ADDRESS = "${lnd.rpcAddress}:${toString lnd.rpcPort}";
|
||||
LND_CERT_PATH = lnd.certPath;
|
||||
LND_MACAROON_PATH = "${lnd.networkDir}/admin.macaroon";
|
||||
} // cfg.extraEnv;
|
||||
|
||||
serviceConfig = nbLib.defaultHardening // {
|
||||
ExecStart = "${lightningPubEnv} ${pkgs.nodejs_22}/bin/node build/src/index.js";
|
||||
SyslogIdentifier = "lightning-pub";
|
||||
User = cfg.user;
|
||||
Restart = "on-failure";
|
||||
RestartSec = "10s";
|
||||
ReadWritePaths = [ cfg.dataDir ];
|
||||
} // nbLib.allowAllIPAddresses
|
||||
// nbLib.nodejs;
|
||||
};
|
||||
|
||||
networking.firewall.allowedTCPPorts = [ cfg.port ];
|
||||
};
|
||||
}
|
||||
|
|
@ -29,6 +29,7 @@
|
|||
./joinmarket-ob-watcher.nix
|
||||
./hardware-wallets.nix
|
||||
./lamassu-lnbits.nix
|
||||
./lightning-pub.nix
|
||||
|
||||
# Support features
|
||||
./versioning.nix
|
||||
|
|
|
|||
Loading…
Add table
Add a link
Reference in a new issue