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
|
./joinmarket-ob-watcher.nix
|
||||||
./hardware-wallets.nix
|
./hardware-wallets.nix
|
||||||
./lamassu-lnbits.nix
|
./lamassu-lnbits.nix
|
||||||
|
./lightning-pub.nix
|
||||||
|
|
||||||
# Support features
|
# Support features
|
||||||
./versioning.nix
|
./versioning.nix
|
||||||
|
|
|
||||||
Loading…
Add table
Add a link
Reference in a new issue