Add LND support
This commit is contained in:
parent
4acf5cd32c
commit
9b0753135c
|
@ -30,6 +30,15 @@
|
|||
# default nix-bitcoin nodes offer outgoing connectivity.
|
||||
# services.clightning.autolisten = true;
|
||||
|
||||
### LND
|
||||
# Disable clightning and uncomment the following line in order to enable lnd,
|
||||
# a lightning implementation written in Go.
|
||||
# services.lnd.enable = assert (!config.services.clightning.enable); true;
|
||||
# WARNING: If you use lnd, you should manually backup your wallet mnemonic
|
||||
# seed. In order to do so, you can run the following command after the
|
||||
# lnd service starts:
|
||||
# nixops scp --from bitcoin-node /secrets/lnd-seed-mnemonic ./secrets/lnd-seed-mnemonic
|
||||
|
||||
### SPARK WALLET
|
||||
# Enable this module to use spark-wallet, a minimalistic wallet GUI for
|
||||
# c-lightning, accessible over the web or through mobile and desktop apps.
|
||||
|
|
|
@ -193,6 +193,18 @@ in {
|
|||
to stay under the specified target size in MiB)
|
||||
'';
|
||||
};
|
||||
zmqpubrawblock = mkOption {
|
||||
type = types.nullOr types.string;
|
||||
default = null;
|
||||
example = "tcp://127.0.0.1:28332";
|
||||
description = "ZMQ address for zmqpubrawblock notifications";
|
||||
};
|
||||
zmqpubrawtx = mkOption {
|
||||
type = types.nullOr types.string;
|
||||
default = null;
|
||||
example = "tcp://127.0.0.1:28333";
|
||||
description = "ZMQ address for zmqpubrawtx notifications";
|
||||
};
|
||||
enforceTor = nix-bitcoin-services.enforceTor;
|
||||
};
|
||||
};
|
||||
|
@ -239,7 +251,7 @@ in {
|
|||
// (if cfg.enforceTor
|
||||
then nix-bitcoin-services.allowTor
|
||||
else nix-bitcoin-services.allowAnyIP
|
||||
);
|
||||
) // optionals config.services.lnd.enable nix-bitcoin-services.allowAnyProtocol; # FOR ZMQ
|
||||
};
|
||||
systemd.services.bitcoind-import-banlist = {
|
||||
description = "Bitcoin daemon banlist importer";
|
||||
|
|
|
@ -11,4 +11,5 @@
|
|||
nix-bitcoin-webindex = ./nix-bitcoin-webindex.nix;
|
||||
spark-wallet = ./spark-wallet.nix;
|
||||
recurring-donations = ./recurring-donations.nix;
|
||||
lnd = ./lnd.nix;
|
||||
}
|
||||
|
|
128
modules/lnd.nix
Normal file
128
modules/lnd.nix
Normal file
|
@ -0,0 +1,128 @@
|
|||
{ config, lib, pkgs, ... }:
|
||||
|
||||
with lib;
|
||||
|
||||
let
|
||||
nix-bitcoin-services = pkgs.callPackage ./nix-bitcoin-services.nix { };
|
||||
cfg = config.services.lnd;
|
||||
configFile = pkgs.writeText "lnd.conf" ''
|
||||
datadir=${cfg.dataDir}
|
||||
bitcoin.mainnet=1
|
||||
tlscertpath=/secrets/lnd_cert
|
||||
tlskeypath=/secrets/lnd_key
|
||||
|
||||
bitcoin.active=1
|
||||
bitcoin.node=bitcoind
|
||||
|
||||
tor.active=true
|
||||
tor.v3=true
|
||||
tor.streamisolation=true
|
||||
|
||||
bitcoind.rpcuser=${config.services.bitcoind.rpcuser}
|
||||
bitcoind.zmqpubrawblock=${config.services.bitcoind.zmqpubrawblock}
|
||||
bitcoind.zmqpubrawtx=${config.services.bitcoind.zmqpubrawtx}
|
||||
|
||||
${cfg.extraConfig}
|
||||
'';
|
||||
init-lnd-wallet-script = pkgs.writeScript "init-lnd-wallet.sh" ''
|
||||
#!/bin/sh
|
||||
|
||||
set -e
|
||||
|
||||
${pkgs.coreutils}/bin/sleep 5
|
||||
|
||||
if [ ! -f ${cfg.dataDir}/chain/bitcoin/mainnet/wallet.db ]
|
||||
then
|
||||
${pkgs.coreutils}/bin/echo creating LND wallet
|
||||
|
||||
${pkgs.curl}/bin/curl -s \
|
||||
--cacert /secrets/lnd_cert \
|
||||
-X GET https://127.0.0.1:8080/v1/genseed | ${pkgs.jq}/bin/jq -c '.cipher_seed_mnemonic' > /secrets/lnd-seed-mnemonic
|
||||
|
||||
${pkgs.curl}/bin/curl -s \
|
||||
--cacert /secrets/lnd_cert \
|
||||
-X POST -d "{\"wallet_password\": \"$(${pkgs.coreutils}/bin/cat /secrets/lnd-wallet-password | ${pkgs.coreutils}/bin/tr -d '\n' | ${pkgs.coreutils}/bin/base64 -w0)\", \
|
||||
\"cipher_seed_mnemonic\": $(${pkgs.coreutils}/bin/cat /secrets/lnd-seed-mnemonic | ${pkgs.coreutils}/bin/tr -d '\n')}" \
|
||||
https://127.0.0.1:8080/v1/initwallet
|
||||
|
||||
${pkgs.coreutils}/bin/echo wallet created
|
||||
else
|
||||
${pkgs.coreutils}/bin/echo unlocking wallet
|
||||
|
||||
${pkgs.curl}/bin/curl -s \
|
||||
-H "Grpc-Metadata-macaroon: $(${pkgs.xxd}/bin/xxd -ps -u -c 1000 ${cfg.dataDir}/chain/bitcoin/mainnet/admin.macaroon)" \
|
||||
--cacert /secrets/lnd_cert \
|
||||
-X POST \
|
||||
-d "{\"wallet_password\": \"$(${pkgs.coreutils}/bin/cat /secrets/lnd-wallet-password | ${pkgs.coreutils}/bin/tr -d '\n' | ${pkgs.coreutils}/bin/base64 -w0)\"}" \
|
||||
https://127.0.0.1:8080/v1/unlockwallet
|
||||
|
||||
${pkgs.coreutils}/bin/echo wallet unlocked
|
||||
fi
|
||||
|
||||
exit 0
|
||||
'';
|
||||
in {
|
||||
|
||||
options.services.lnd = {
|
||||
enable = mkOption {
|
||||
type = types.bool;
|
||||
default = false;
|
||||
description = ''
|
||||
If enabled, the LND service will be installed.
|
||||
'';
|
||||
};
|
||||
dataDir = mkOption {
|
||||
type = types.path;
|
||||
default = "/var/lib/lnd";
|
||||
description = "The data directory for LND.";
|
||||
};
|
||||
extraConfig = mkOption {
|
||||
type = types.lines;
|
||||
default = "";
|
||||
example = ''
|
||||
autopilot.active=1
|
||||
'';
|
||||
description = "Additional configurations to be appended to <filename>lnd.conf</filename>.";
|
||||
};
|
||||
enforceTor = nix-bitcoin-services.enforceTor;
|
||||
};
|
||||
|
||||
config = mkIf cfg.enable {
|
||||
users.users.lnd = {
|
||||
description = "LND User";
|
||||
group = "lnd";
|
||||
extraGroups = [ "bitcoinrpc" "keys" ];
|
||||
home = cfg.dataDir;
|
||||
};
|
||||
users.groups.lnd = {
|
||||
name = "lnd";
|
||||
};
|
||||
|
||||
systemd.services.lnd = {
|
||||
description = "Run LND";
|
||||
path = [ pkgs.altcoins.bitcoind ];
|
||||
wantedBy = [ "multi-user.target" ];
|
||||
requires = [ "bitcoind.service" ];
|
||||
after = [ "bitcoind.service" ];
|
||||
preStart = ''
|
||||
mkdir -m 0770 -p ${cfg.dataDir}
|
||||
cp ${configFile} ${cfg.dataDir}/lnd.conf
|
||||
chown -R 'lnd:lnd' '${cfg.dataDir}'
|
||||
chmod u=rw,g=r,o= ${cfg.dataDir}/lnd.conf
|
||||
echo "bitcoind.rpcpass=$(cat /secrets/bitcoin-rpcpassword)" >> '${cfg.dataDir}/lnd.conf'
|
||||
'';
|
||||
serviceConfig = {
|
||||
PermissionsStartOnly = "true";
|
||||
ExecStart = "${pkgs.lnd}/bin/lnd --configfile=${cfg.dataDir}/lnd.conf";
|
||||
ExecStartPost = "${pkgs.bash}/bin/bash ${init-lnd-wallet-script}";
|
||||
User = "lnd";
|
||||
Restart = "on-failure";
|
||||
RestartSec = "10s";
|
||||
} // nix-bitcoin-services.defaultHardening
|
||||
// (if cfg.enforceTor
|
||||
then nix-bitcoin-services.allowTor
|
||||
else nix-bitcoin-services.allowAnyIP
|
||||
) // nix-bitcoin-services.allowAnyProtocol; # For ZMQ
|
||||
};
|
||||
};
|
||||
}
|
|
@ -15,5 +15,6 @@ in {
|
|||
bitcoin = nixpkgs-unstable.bitcoin.override { miniupnpc = null; };
|
||||
altcoins.bitcoind = nixpkgs-unstable.altcoins.bitcoind.override { miniupnpc = null; };
|
||||
clightning = nixpkgs-unstable.clightning.override { };
|
||||
lnd = nixpkgs-unstable.lnd.override { };
|
||||
};
|
||||
}
|
||||
|
|
|
@ -42,6 +42,3 @@ in
|
|||
'';
|
||||
};
|
||||
}
|
||||
|
||||
|
||||
|
||||
|
|
|
@ -28,6 +28,7 @@ in {
|
|||
./onion-chef.nix
|
||||
./recurring-donations.nix
|
||||
./hardware-wallets.nix
|
||||
./lnd.nix
|
||||
];
|
||||
|
||||
options.services.nix-bitcoin = {
|
||||
|
@ -46,6 +47,8 @@ in {
|
|||
# Tor
|
||||
services.tor.enable = true;
|
||||
services.tor.client.enable = true;
|
||||
# LND uses ControlPort to create onion services
|
||||
services.tor.controlPort = if config.services.lnd.enable then 9051 else null;
|
||||
|
||||
# Tor SSH service
|
||||
services.tor.hiddenServices.sshd = {
|
||||
|
@ -64,12 +67,16 @@ in {
|
|||
services.bitcoind.enforceTor = true;
|
||||
services.bitcoind.port = 8333;
|
||||
services.bitcoind.rpcuser = "bitcoinrpc";
|
||||
services.bitcoind.zmqpubrawblock = "tcp://127.0.0.1:28332";
|
||||
services.bitcoind.zmqpubrawtx = "tcp://127.0.0.1:28333";
|
||||
services.bitcoind.extraConfig = ''
|
||||
assumevalid=0000000000000000000726d186d6298b5054b9a5c49639752294b322a305d240
|
||||
addnode=ecoc5q34tmbq54wl.onion
|
||||
discover=0
|
||||
addresstype=bech32
|
||||
changetype=bech32
|
||||
${optionalString (config.services.lnd.enable) "zmqpubrawblock=${config.services.bitcoind.zmqpubrawblock}"}
|
||||
${optionalString (config.services.lnd.enable) "zmqpubrawtx=${config.services.bitcoind.zmqpubrawtx}"}
|
||||
'';
|
||||
services.bitcoind.prune = 0;
|
||||
services.bitcoind.dbCache = 1000;
|
||||
|
@ -96,32 +103,51 @@ in {
|
|||
version = 3;
|
||||
};
|
||||
|
||||
# lnd
|
||||
services.lnd.enforceTor = true;
|
||||
services.tor.hiddenServices.lnd = {
|
||||
map = [{
|
||||
port = 9735; toPort = 9735;
|
||||
}];
|
||||
version = 3;
|
||||
};
|
||||
|
||||
# Create user operator which can use bitcoin-cli and lightning-cli
|
||||
users.users.operator = {
|
||||
isNormalUser = true;
|
||||
extraGroups = [ config.services.bitcoind.group ]
|
||||
++ (if config.services.clightning.enable then [ "clightning" ] else [ ])
|
||||
++ (if config.services.lnd.enable then [ "lnd" ] else [ ])
|
||||
++ (if config.services.liquidd.enable then [ config.services.liquidd.group ] else [ ])
|
||||
++ (if (config.services.hardware-wallets.ledger || config.services.hardware-wallets.trezor)
|
||||
then [ config.services.hardware-wallets.group ] else [ ]);
|
||||
};
|
||||
# Give operator access to onion hostnames
|
||||
services.onion-chef.enable = true;
|
||||
services.onion-chef.access.operator = [ "bitcoind" "clightning" "nginx" "liquidd" "spark-wallet" "electrs" "sshd" ];
|
||||
services.onion-chef.access.operator = [ "bitcoind" "clightning" "lnd" "nginx" "liquidd" "spark-wallet" "electrs" "sshd" ];
|
||||
|
||||
environment.interactiveShellInit = ''
|
||||
alias bitcoin-cli='bitcoin-cli -datadir=${config.services.bitcoind.dataDir}'
|
||||
alias lightning-cli='sudo -u clightning lightning-cli --lightning-dir=${config.services.clightning.dataDir}'
|
||||
'' + (if config.services.liquidd.enable then ''
|
||||
alias elements-cli='elements-cli -datadir=${config.services.liquidd.dataDir}'
|
||||
alias liquidswap-cli='liquidswap-cli -c ${config.services.liquidd.dataDir}/elements.conf'
|
||||
'' else "");
|
||||
${optionalString (config.services.clightning.enable) ''
|
||||
alias lightning-cli='sudo -u clightning lightning-cli --lightning-dir=${config.services.clightning.dataDir}'
|
||||
''}
|
||||
${optionalString (config.services.lnd.enable) ''
|
||||
alias lncli='sudo -u lnd lncli --tlscertpath /secrets/lnd_cert --macaroonpath ${config.services.lnd.dataDir}/chain/bitcoin/mainnet/admin.macaroon'
|
||||
''}
|
||||
${optionalString (config.services.liquidd.enable) ''
|
||||
alias elements-cli='elements-cli -datadir=${config.services.liquidd.dataDir}'
|
||||
alias liquidswap-cli='liquidswap-cli -c ${config.services.liquidd.dataDir}/elements.conf'
|
||||
''}
|
||||
'';
|
||||
# Unfortunately c-lightning doesn't allow setting the permissions of the rpc socket
|
||||
# https://github.com/ElementsProject/lightning/issues/1366
|
||||
security.sudo.configFile = (
|
||||
if config.services.clightning.enable then ''
|
||||
operator ALL=(clightning) NOPASSWD: ALL
|
||||
''
|
||||
else if config.services.lnd.enable then ''
|
||||
operator ALL=(lnd) NOPASSWD: ALL
|
||||
''
|
||||
else ""
|
||||
);
|
||||
|
||||
|
@ -176,6 +202,7 @@ in {
|
|||
qrencode
|
||||
]
|
||||
++ optionals config.services.clightning.enable [clightning]
|
||||
++ optionals config.services.lnd.enable [lnd]
|
||||
++ optionals config.services.lightning-charge.enable [lightning-charge]
|
||||
++ optionals config.services.nanopos.enable [nanopos]
|
||||
++ optionals config.services.nix-bitcoin-webindex.enable [nginx]
|
||||
|
|
|
@ -7,6 +7,13 @@ let
|
|||
group = "bitcoinrpc";
|
||||
permissions = "0440";
|
||||
};
|
||||
lnd-wallet-password = {
|
||||
text = secrets.lnd-wallet-password;
|
||||
destDir = "/secrets/";
|
||||
user = "lnd";
|
||||
group = "lnd";
|
||||
permissions = "0440";
|
||||
};
|
||||
lightning-charge-api-token = {
|
||||
text = "API_TOKEN=" + secrets.lightning-charge-api-token;
|
||||
destDir = "/secrets/";
|
||||
|
@ -50,6 +57,20 @@ let
|
|||
group = "root";
|
||||
permissions = "0440";
|
||||
};
|
||||
lnd_key = {
|
||||
keyFile = ../secrets/lnd.key;
|
||||
destDir = "/secrets/";
|
||||
user = "lnd";
|
||||
group = "lnd";
|
||||
permissions = "0440";
|
||||
};
|
||||
lnd_cert = {
|
||||
keyFile = ../secrets/lnd.cert;
|
||||
destDir = "/secrets/";
|
||||
user = "lnd";
|
||||
group = "lnd";
|
||||
permissions = "0440";
|
||||
};
|
||||
in {
|
||||
network.description = "Bitcoin Core node";
|
||||
|
||||
|
@ -61,6 +82,7 @@ in {
|
|||
deployment.keys = {
|
||||
inherit bitcoin-rpcpassword;
|
||||
}
|
||||
// (if (config.services.lnd.enable) then { inherit lnd-wallet-password lnd_key lnd_cert; } else { })
|
||||
// (if (config.services.lightning-charge.enable) then { inherit lightning-charge-api-token; } else { })
|
||||
// (if (config.services.nanopos.enable) then { inherit lightning-charge-api-token-for-nanopos; } else { })
|
||||
// (if (config.services.liquidd.enable) then { inherit liquid-rpcpassword; } else { })
|
||||
|
|
|
@ -2,14 +2,21 @@ set -e
|
|||
set -o pipefail
|
||||
|
||||
BITCOIND_ONION="$(cat /var/lib/onion-chef/operator/bitcoind)"
|
||||
CLIGHTNING_NODEID=$(sudo -u clightning lightning-cli --lightning-dir=/var/lib/clightning getinfo | jq -r '.id')
|
||||
CLIGHTNING_ONION="$(cat /var/lib/onion-chef/operator/clightning)"
|
||||
CLIGHTNING_ID="$CLIGHTNING_NODEID@$CLIGHTNING_ONION:9735"
|
||||
|
||||
echo BITCOIND_ONION="$BITCOIND_ONION"
|
||||
echo CLIGHTNING_NODEID="$CLIGHTNING_NODEID"
|
||||
echo CLIGHTNING_ONION="$CLIGHTNING_ONION"
|
||||
echo CLIGHTNING_ID="$CLIGHTNING_ID"
|
||||
|
||||
if [ -x "$(command -v clightning)" ]; then
|
||||
CLIGHTNING_NODEID=$(sudo -u clightning lightning-cli --lightning-dir=/var/lib/clightning getinfo | jq -r '.id')
|
||||
CLIGHTNING_ONION="$(cat /var/lib/onion-chef/operator/clightning)"
|
||||
CLIGHTNING_ID="$CLIGHTNING_NODEID@$CLIGHTNING_ONION:9735"
|
||||
echo CLIGHTNING_NODEID="$CLIGHTNING_NODEID"
|
||||
echo CLIGHTNING_ONION="$CLIGHTNING_ONION"
|
||||
echo CLIGHTNING_ID="$CLIGHTNING_ID"
|
||||
fi
|
||||
|
||||
if [ -x "$(command -v lncli)" ]; then
|
||||
LND_NODEID=$(sudo -u lnd lncli --tlscertpath /secrets/lnd_cert --macaroonpath /var/lib/lnd/chain/bitcoin/mainnet/admin.macaroon getinfo | jq -r '.uris[0]')
|
||||
echo LND_NODEID="$LND_NODEID"
|
||||
fi
|
||||
|
||||
NGINX_ONION_FILE=/var/lib/onion-chef/operator/nginx
|
||||
if [ -e "$NGINX_ONION_FILE" ]; then
|
||||
|
|
|
@ -11,6 +11,7 @@ echo Write secrets to $SECRETSFILE
|
|||
{
|
||||
echo \{
|
||||
echo " bitcoinrpcpassword = \"$(apg -m 20 -x 20 -M Ncl -n 1)\";"
|
||||
echo " lnd-wallet-password = \"$(apg -m 20 -x 20 -M Ncl -n 1)\";"
|
||||
echo " lightning-charge-api-token = \"$(apg -m 20 -x 20 -M Ncl -n 1)\";"
|
||||
echo " liquidrpcpassword = \"$(apg -m 20 -x 20 -M Ncl -n 1)\";"
|
||||
echo " spark-wallet-password = \"$(apg -m 20 -x 20 -M Ncl -n 1)\";"
|
||||
|
@ -24,3 +25,10 @@ openssl req -new -key secrets/nginx.key -out secrets/nginx.csr -subj "/C=KN"
|
|||
openssl x509 -req -days 1825 -in secrets/nginx.csr -signkey secrets/nginx.key -out secrets/nginx.cert
|
||||
rm secrets/nginx.csr
|
||||
echo Done
|
||||
|
||||
echo Generate LND compatible TLS Cert
|
||||
openssl ecparam -genkey -name prime256v1 -out secrets/lnd.key
|
||||
openssl req -config secrets/openssl.cnf -new -sha256 -key secrets/lnd.key -out secrets/lnd.csr -subj '/CN=localhost/O=lnd'
|
||||
openssl req -config secrets/openssl.cnf -x509 -sha256 -days 1825 -key secrets/lnd.key -in secrets/lnd.csr -out secrets/lnd.cert
|
||||
rm secrets/lnd.csr
|
||||
echo Done
|
||||
|
|
32
secrets/openssl.cnf
Normal file
32
secrets/openssl.cnf
Normal file
|
@ -0,0 +1,32 @@
|
|||
[ req ]
|
||||
#default_bits = 2048
|
||||
#default_md = sha256
|
||||
#default_keyfile = privkey.pem
|
||||
distinguished_name = req_distinguished_name
|
||||
attributes = req_attributes
|
||||
x509_extensions = v3_ca
|
||||
|
||||
[ req_distinguished_name ]
|
||||
countryName = Country Name (2 letter code)
|
||||
countryName_min = 2
|
||||
countryName_max = 2
|
||||
stateOrProvinceName = State or Province Name (full name)
|
||||
localityName = Locality Name (eg, city)
|
||||
0.organizationName = Organization Name (eg, company)
|
||||
organizationalUnitName = Organizational Unit Name (eg, section)
|
||||
commonName = Common Name (eg, fully qualified host name)
|
||||
commonName_max = 64
|
||||
emailAddress = Email Address
|
||||
emailAddress_max = 64
|
||||
|
||||
[ req_attributes ]
|
||||
challengePassword = A challenge password
|
||||
challengePassword_min = 4
|
||||
challengePassword_max = 20
|
||||
|
||||
[ v3_ca ]
|
||||
subjectAltName = @alt_names
|
||||
|
||||
[ alt_names ]
|
||||
IP.1 = 127.0.0.1
|
||||
DNS.1 = localhost
|
Loading…
Reference in New Issue
Block a user