nix-bitcoin/modules/btcpayserver.nix

234 lines
8.5 KiB
Nix
Raw Normal View History

2020-08-12 07:47:56 -07:00
{ config, lib, pkgs, ... }:
with lib;
let
cfg = config.services;
inherit (config) nix-bitcoin-services;
in {
options.services = {
nbxplorer = {
package = mkOption {
type = types.package;
default = pkgs.nix-bitcoin.nbxplorer;
defaultText = "pkgs.nix-bitcoin.nbxplorer";
description = "The package providing nbxplorer binaries.";
};
dataDir = mkOption {
type = types.path;
default = "/var/lib/nbxplorer";
description = "The data directory for nbxplorer.";
};
user = mkOption {
type = types.str;
default = "nbxplorer";
description = "The user as which to run nbxplorer.";
};
group = mkOption {
type = types.str;
default = cfg.nbxplorer.user;
description = "The group as which to run nbxplorer.";
};
bind = mkOption {
type = types.str;
default = "127.0.0.1";
description = "The address on which to bind.";
};
2020-10-16 08:43:11 -07:00
port = mkOption {
type = types.port;
default = 24444;
description = "Port on which to bind.";
};
2020-08-12 07:47:56 -07:00
enable = mkOption {
# This option is only used by netns-isolation
internal = true;
default = cfg.btcpayserver.enable;
};
enforceTor = nix-bitcoin-services.enforceTor;
};
btcpayserver = {
enable = mkEnableOption "btcpayserver";
package = mkOption {
type = types.package;
default = pkgs.nix-bitcoin.btcpayserver;
defaultText = "pkgs.nix-bitcoin.btcpayserver";
description = "The package providing btcpayserver binaries.";
};
dataDir = mkOption {
type = types.path;
default = "/var/lib/btcpayserver";
description = "The data directory for btcpayserver.";
};
user = mkOption {
type = types.str;
default = "btcpayserver";
description = "The user as which to run btcpayserver.";
};
group = mkOption {
type = types.str;
default = cfg.btcpayserver.user;
description = "The group as which to run btcpayserver.";
};
bind = mkOption {
type = types.str;
default = "127.0.0.1";
description = "The address on which to bind.";
};
2020-10-16 08:43:11 -07:00
port = mkOption {
type = types.port;
default = 23000;
description = "Port on which to bind.";
};
2020-08-12 07:47:56 -07:00
lightningBackend = mkOption {
type = types.nullOr (types.enum [ "clightning" "lnd" ]);
default = null;
description = "The lightning node implementation to use.";
};
enforceTor = nix-bitcoin-services.enforceTor;
};
};
config = mkIf cfg.btcpayserver.enable {
assertions = let
backend = cfg.btcpayserver.lightningBackend;
in [
{ assertion = (backend != null) -> cfg.${backend}.enable;
message = "btcpayserver requires ${backend}.";
}
];
systemd.tmpfiles.rules = [
"d '${cfg.nbxplorer.dataDir}' 0770 ${cfg.nbxplorer.user} ${cfg.nbxplorer.group} - -"
"d '${cfg.btcpayserver.dataDir}' 0770 ${cfg.btcpayserver.user} ${cfg.btcpayserver.group} - -"
];
2020-09-17 01:04:23 -07:00
services.postgresql = {
enable = true;
ensureDatabases = [ "btcpaydb" ];
ensureUsers = [{
name = "${cfg.btcpayserver.user}";
ensurePermissions."DATABASE btcpaydb" = "ALL PRIVILEGES";
}];
};
2020-08-12 07:47:56 -07:00
systemd.services.nbxplorer = let
configFile = builtins.toFile "config" ''
network=mainnet
btcrpcuser=${cfg.bitcoind.rpc.users.btcpayserver.name}
btcrpcurl=http://${builtins.elemAt config.services.bitcoind.rpcbind 0}:${toString cfg.bitcoind.rpc.port}
2020-08-12 07:47:56 -07:00
btcnodeendpoint=${config.services.bitcoind.bind}:8333
bind=${cfg.nbxplorer.bind}
2020-10-16 08:43:11 -07:00
port=${toString cfg.nbxplorer.port}
2020-08-12 07:47:56 -07:00
'';
in {
description = "Run nbxplorer";
wantedBy = [ "multi-user.target" ];
requires = [ "bitcoind.service" ];
after = [ "bitcoind.service" ];
preStart = ''
install -m 600 ${configFile} ${cfg.nbxplorer.dataDir}/settings.config
echo "btcrpcpassword=$(cat ${config.nix-bitcoin.secretsDir}/bitcoin-rpcpassword-btcpayserver)" \
>> '${cfg.nbxplorer.dataDir}/settings.config'
'';
serviceConfig = nix-bitcoin-services.defaultHardening // {
ExecStart = ''
${cfg.nbxplorer.package}/bin/nbxplorer --conf=${cfg.nbxplorer.dataDir}/settings.config \
--datadir=${cfg.nbxplorer.dataDir}
'';
User = cfg.nbxplorer.user;
Restart = "on-failure";
RestartSec = "10s";
ReadWritePaths = cfg.nbxplorer.dataDir;
MemoryDenyWriteExecute = "false";
} // (if cfg.nbxplorer.enforceTor
then nix-bitcoin-services.allowTor
else nix-bitcoin-services.allowAnyIP
);
};
systemd.services.btcpayserver = let
configFile = builtins.toFile "config" (''
network=mainnet
2020-09-17 01:04:23 -07:00
postgres=User ID=${cfg.btcpayserver.user};Host=/run/postgresql;Database=btcpaydb
2020-08-12 07:47:56 -07:00
socksendpoint=${cfg.tor.client.socksListenAddress}
2020-10-16 08:43:11 -07:00
btcexplorerurl=http://${cfg.nbxplorer.bind}:${toString cfg.nbxplorer.port}/
2020-08-12 07:47:56 -07:00
btcexplorercookiefile=${cfg.nbxplorer.dataDir}/Main/.cookie
bind=${cfg.btcpayserver.bind}
2020-10-16 08:43:11 -07:00
port=${toString cfg.btcpayserver.port}
2020-08-12 07:47:56 -07:00
'' + optionalString (cfg.btcpayserver.lightningBackend == "clightning") ''
btclightning=type=clightning;server=unix:///${cfg.clightning.dataDir}/bitcoin/lightning-rpc
'');
lndConfig =
"btclightning=type=lnd-rest;" +
"server=https://${toString cfg.lnd.listen}:${toString cfg.lnd.restPort}/;" +
"macaroonfilepath=/run/lnd/btcpayserver.macaroon;" +
"certthumbprint=";
in let self = {
wantedBy = [ "multi-user.target" ];
requires = [ "nbxplorer.service" ]
++ optional (cfg.btcpayserver.lightningBackend != null) "${cfg.btcpayserver.lightningBackend}.service";
after = self.requires;
preStart = ''
install -m 600 ${configFile} ${cfg.btcpayserver.dataDir}/settings.config
${optionalString (cfg.btcpayserver.lightningBackend == "lnd") ''
{
echo -n "${lndConfig}";
${pkgs.openssl}/bin/openssl x509 -noout -fingerprint -sha256 -in ${config.nix-bitcoin.secretsDir}/lnd-cert \
| sed -e 's/.*=//;s/://g';
} >> ${cfg.btcpayserver.dataDir}/settings.config
''}
'';
serviceConfig = nix-bitcoin-services.defaultHardening // {
ExecStart = ''
${cfg.btcpayserver.package}/bin/btcpayserver --conf=${cfg.btcpayserver.dataDir}/settings.config \
--datadir=${cfg.btcpayserver.dataDir}
'';
User = cfg.btcpayserver.user;
Restart = "on-failure";
RestartSec = "10s";
ReadWritePaths = cfg.btcpayserver.dataDir;
MemoryDenyWriteExecute = "false";
} // (if cfg.btcpayserver.enforceTor
then nix-bitcoin-services.allowTor
else nix-bitcoin-services.allowAnyIP
);
}; in self;
services.lnd.macaroons.btcpayserver = mkIf (cfg.btcpayserver.lightningBackend == "lnd") {
inherit (cfg.btcpayserver) user;
permissions = ''{"entity":"info","action":"read"},{"entity":"onchain","action":"read"},{"entity":"offchain","action":"read"},{"entity":"address","action":"read"},{"entity":"message","action":"read"},{"entity":"peers","action":"read"},{"entity":"signer","action":"read"},{"entity":"invoices","action":"read"},{"entity":"invoices","action":"write"},{"entity":"address","action":"write"}'';
};
users.users.${cfg.nbxplorer.user} = {
description = "nbxplorer user";
group = cfg.nbxplorer.group;
extraGroups = [ "bitcoinrpc" ];
home = cfg.nbxplorer.dataDir;
};
users.groups.${cfg.nbxplorer.group} = {};
users.users.${cfg.btcpayserver.user} = {
description = "btcpayserver user";
group = cfg.btcpayserver.group;
extraGroups = [ "nbxplorer" ]
++ optional (cfg.btcpayserver.lightningBackend == "clightning") cfg.clightning.user;
home = cfg.btcpayserver.dataDir;
};
users.groups.${cfg.btcpayserver.group} = {};
services.bitcoind.rpc.users.btcpayserver = {
passwordHMACFromFile = true;
rpcwhitelist = cfg.bitcoind.rpc.users.public.rpcwhitelist ++ [
"setban"
"generatetoaddress"
"getpeerinfo"
];
};
nix-bitcoin.secrets.bitcoin-rpcpassword-btcpayserver = {
user = "bitcoin";
group = "nbxplorer";
};
nix-bitcoin.secrets.bitcoin-HMAC-btcpayserver.user = "bitcoin";
};
}