Merge fort-nix/nix-bitcoin#378: Misc. improvements

b0c66c41e1 tests: add container-minimal example (Erik Arvstedt)
a8a8b9ce4d backups: backup NixOS uid, gid mappings (Erik Arvstedt)
ee8b83681b modules: document module dependencies (Erik Arvstedt)
9f7d048769 modules: move assertion to lnd.nix (Erik Arvstedt)
cce9a3f6b2 modules: move nix-bitcoin options to file 'nix-bitcoin.nix' (Erik Arvstedt)
fdc278a0b8 lib: fix comment (Erik Arvstedt)
13b4650e84 versioning: add usage comment (Erik Arvstedt)
ca3c7a281b secrets: mark option 'secretsSetupMethod' as internal (Erik Arvstedt)
f9a0fd7a17 nodeinfo: fix indentation (Erik Arvstedt)
4ece606e8b examples/minimal-configuration: improve comment (Erik Arvstedt)
6de9aba854 run-tests: quote scriptDir (Erik Arvstedt)
1ef8cbb384 joinmarket: fix allowRunAsUsers setting (Erik Arvstedt)
fb36f2abe5 joinmarket-ob-watcher: use consistent mode formatting (Erik Arvstedt)
f14af1fc48 treewide: use consistent echo message formatting (Erik Arvstedt)
b8043d3db5 treewide: use consistent bash script indentation (Erik Arvstedt)
c758d68ea4 lib: rename privileged -> rootScript (Erik Arvstedt)
1c3735b600 examples/README: add nixbitcoin.org server repo (Erik Arvstedt)
c041079ae1 configuration.nix: reorder sections (Erik Arvstedt)
3734ab38a6 configuration.nix: improve wording and formatting (Erik Arvstedt)

Pull request description:

ACKs for top commit:
  jonasnick:
    ACK b0c66c41e1

Tree-SHA512: 11411e13de4ed8a6c8c942b2843b9ad45f3340a0682fe673a5cee18db93bb75f995c717eb9624f6a754615c508d089c03bf1790848c5112a7d5e9546d583fb24
This commit is contained in:
Jonas Nick 2021-08-15 21:27:56 +00:00
commit 9b24a74b23
No known key found for this signature in database
GPG Key ID: 4861DBF262123605
18 changed files with 172 additions and 148 deletions

View File

@ -68,3 +68,10 @@ c systemctl status bitcoind
}' container --run c nodeinfo
```
See [`run-tests.sh`](../test/run-tests.sh) for a complete documentation.
### Real-world example
Check the [server repo](https://github.com/fort-nix/nixbitcoin.org) for https://nixbitcoin.org
to see the configuration of a nix-bitcoin node that's used in production.
The commands in `shell.nix` allow you to locally run the node in a VM or container.

View File

@ -24,9 +24,9 @@
# modules by commenting out their respective line.
### BITCOIND
# Bitcoind is enabled by default if nix-bitcoin is enabled
# Bitcoind is enabled by default.
#
# Enable this option to set pruning to a specified MiB value.
# Set this option to enable pruning with a specified MiB value.
# clightning is compatible with pruning. See
# https://github.com/ElementsProject/lightning/#pruning for more information.
# LND and electrs are not compatible with pruning.
@ -42,8 +42,7 @@
# '';
### CLIGHTNING
# Enable this module to use clightning, a Lightning Network implementation
# in C.
# Enable clightning, a Lightning Network implementation in C.
services.clightning.enable = true;
#
# Set this to create an onion service by which clightning can accept incoming connections
@ -56,12 +55,13 @@
# services.clightning.plugins.prometheus.enable = true;
### LND
# Uncomment the following line in order to enable lnd, a lightning
# implementation written in Go. In order to avoid collisions with clightning
# you must disable clightning or change the services.clightning.port or
# services.lnd.port to a port other than 9735.
# Set this to enable lnd, a lightning implementation written in Go.
# services.lnd.enable = true;
#
# NOTE: In order to avoid collisions with clightning you must disable clightning or
# change the services.clightning.port or services.lnd.port to a port other than
# 9735.
#
# Set this to create an onion service by which lnd can accept incoming connections
# via Tor.
# The onion service is automatically announced to peers.
@ -85,33 +85,37 @@
# scp bitcoin-node:/var/lib/lnd/chain/bitcoin/mainnet/channel.backup ./backups/lnd/
### SPARK WALLET
# Enable this module to use spark-wallet, a minimalistic wallet GUI for
# Set this to enable spark-wallet, a minimalistic wallet GUI for
# c-lightning, accessible over the web or through mobile and desktop apps.
# Automatically enables clightning.
# services.spark-wallet.enable = true;
### ELECTRS
# Enable this module to use electrs, an efficient re-implementation of
# Electrum Server in Rust.
# Set this to enable electrs, an efficient Electrum server implemented in Rust.
# services.electrs.enable = true;
#
# If you have more than 8GB memory, enable this option so electrs will
# sync faster. Only available if hardware wallets are disabled.
# services.electrs.high-memory = true;
### BTCPayServer
# Enable this module to use BTCPayServer, a self-hosted, open-source
# Set this to enable BTCPayServer, a self-hosted, open-source
# cryptocurrency payment processor.
# services.btcpayserver.enable = true;
#
# Privacy Warning: BTCPayServer currently looks up price rates without
# proxying them through Tor. This means an outside observer can correlate
# your BTCPayServer usage, like invoice creation times, with your IP address.
# services.btcpayserver.enable = true;
#
# Enable this option to connect BTCPayServer to clightning.
# services.btcpayserver.lightningBackend = "clightning";
#
# Enable this option to connect BTCPayServert to lnd.
# services.btcpayserver.lightningBackend = "lnd";
# The lightning backend service automatically enabled.
#
# The lightning backend service is automatically enabled.
# Afterwards you need to go into Store > General Settings > Lightning Nodes
# and click to use "the internal lightning node of this BTCPay Server".
# and select "the internal lightning node of this BTCPay Server".
#
# Set this to create an onion service to make the btcpayserver web interface
# accessible via Tor.
@ -122,16 +126,18 @@
### LIQUIDD
# Enable this module to use Liquid, a sidechain for an inter-exchange
# settlement network linking together cryptocurrency exchanges and
# institutions around the world. Liquid is accessed with the elements-cli
# tool run as user operator.
# institutions around the world.
# services.liquidd.enable = true;
#
# Liquid can be controlled with command 'elements-cli'.
### RECURRING-DONATIONS
# Enable this module to send recurring donations. This is EXPERIMENTAL; it's
# Set this to enable recurring donations. This is EXPERIMENTAL; it's
# not guaranteed that payments are succeeding or that you will notice payment
# failure.
# Automatically enables clightning.
# services.recurring-donations.enable = true;
# This automatically enables clightning.
#
# Specify the receivers of the donations. By default donations are every
# Monday at a randomized time. Check `journalctl -eu recurring-donations` or
# `lightning-cli listpayments` for successful lightning donations.
@ -142,54 +148,68 @@
# };
### Hardware wallets
# Enable this module to allow using hardware wallets. See https://github.com/bitcoin-core/HWI
# for more information. Only available if electrs.high-memory is disabled.
# Enable the following to allow using hardware wallets.
# See https://github.com/bitcoin-core/HWI for more information.
# Only available if electrs.high-memory is disabled.
#
# Ledger must be initialized through the official ledger live app and the Bitcoin app must
# be installed and running on the device.
# services.hardware-wallets.ledger = true;
#
# Trezor can be initialized with the trezorctl command in nix-bitcoin. More information in
# `docs/usage.md`.
# services.hardware-wallets.trezor = true;
### netns-isolation (EXPERIMENTAL)
# Enable this module to use Network Namespace Isolation. This feature places
# every service in its own network namespace and only allows truly necessary
# connections between network namespaces, making sure services are isolated on
# a network-level as much as possible.
# nix-bitcoin.netns-isolation.enable = true;
### lightning-loop
# Enable this module to use lightninglab's non-custodial off/on chain bridge.
# Set this to enable lightninglab's non-custodial off/on chain bridge.
# services.lightning-loop.enable = true;
#
# loopd (lightning-loop daemon) will be started automatically. Users can
# interact with off/on chain bridge using `loop in` and `loop out`.
# Automatically enables lnd.
# services.lightning-loop.enable = true;
### lightning-pool
# Enable this module to use Lightning Lab's non-custodial batched uniform
# Set this to enable Lightning Lab's non-custodial batched uniform
# clearing-price auction for Lightning Channel Leases.
# services.lightning-pool.enable = true;
#
# Use the `pool` command to interact with the lightning-pool service.
# Automatically enables lnd.
# services.lightning-pool.enable = true;
#
# lightning-pool requires that lnd has a publicly reachable address.
# Set this to create a public onion service for lnd.
# nix-bitcoin.onionServices.lnd.public = true;
### charge-lnd
# Enable this module to use charge-lnd, a simple policy based fee manager for
# Set this to enable charge-lnd, a simple policy based fee manager for
# LND. With this tool you can set fees to autobalance, recover channel open
# costs, use on-chain fees as reference, or just use static fees. You decide.
# services.charge-lnd.enable = true;
#
# Define policies as outlined in the project documentation.
# services.charge-lnd.policies = ''
# '';
### JOINMARKET
# Set this to enable the JoinMarket service, including its command-line scripts.
# These scripts have prefix 'jm-', like 'jm-tumbler'.
# Note: JoinMarket has full access to bitcoind, including its wallet functionality.
# services.joinmarket.enable = true;
#
# Set this to enable the JoinMarket Yield Generator Bot. You will be able to
# earn sats by providing CoinJoin liquidity. This makes it impossible to use other
# scripts that access your wallet.
# services.joinmarket.yieldgenerator.enable = true;
#
# Set this to enable the JoinMarket order book watcher.
# services.joinmarket-ob-watcher.enable = true;
### Backups
# Enable this module to use nix-bitcoin's own backups module. By default, it
# Set this to enable nix-bitcoin's own backup service. By default, it
# uses duplicity to incrementally back up all important files in /var/lib to
# /var/lib/localBackups once a day.
# services.backups.enable = true;
#
# You can pull the localBackups folder with
# `scp bitcoin-node:/var/lib/localBackups /my-backup-path/`
# Alternatively, you can also set a remote target url, for example
@ -206,17 +226,12 @@
# and electrs data directory, enable
# services.backups.with-bulk-data = true;
### JOINMARKET
# Enable this module to allow using JoinMarket's user interactive scripts (including
# tumbler.py).
# Note: JoinMarket has full access to bitcoind, including its wallet functionality.
# services.joinmarket.enable = true;
# Enable this option to enable the JoinMarket Yield Generator Bot. You will be able to
# earn sats by providing CoinJoin liquidity. This makes it impossible to use other
# scripts that access your wallet.
# services.joinmarket.yieldgenerator.enable = true;
# Enable this option to enable the JoinMarket order book watcher.
# services.joinmarket-ob-watcher.enable = true;
### netns-isolation (EXPERIMENTAL)
# Enable this module to use Network Namespace Isolation. This feature places
# every service in its own network namespace and only allows truly necessary
# connections between network namespaces, making sure services are isolated on
# a network-level as much as possible.
# nix-bitcoin.netns-isolation.enable = true;
# FIXME: Define your hostname.
networking.hostName = "host";

View File

@ -1,6 +1,6 @@
{ config, pkgs, lib, ... }: {
imports = [
<nix-bitcoin/modules/nix-bitcoin.nix>
<nix-bitcoin/modules/modules.nix>
];
nix-bitcoin.generateSecrets = true;
@ -15,7 +15,8 @@
name = "main"; # Set this to your system's main user
};
# The system's main unprivileged user
# The system's main unprivileged user. This setting is usually part of your
# existing NixOS configuration.
users.users.main = {
isNormalUser = true;
password = "a";

View File

@ -21,6 +21,8 @@ let
${config.services.postgresqlBackup.location}/btcpaydb.sql.gz
${optionalString config.nix-bitcoin.generateSecrets "${config.nix-bitcoin.secretsDir}"}
/var/lib/tor
/var/lib/nixos
# Extra files
${cfg.extraFiles}

View File

@ -374,11 +374,11 @@ in {
cd ${cfg.cli}/bin
echo "Importing node banlist..."
cat ${./banlist.cli.txt} | while read line; do
if ! err=$(eval "$line" 2>&1) && [[ $err != *already\ banned* ]]; then
# unexpected error
echo "$err"
exit 1
fi
if ! err=$(eval "$line" 2>&1) && [[ $err != *already\ banned* ]]; then
# unexpected error
echo "$err"
exit 1
fi
done
'';
serviceConfig = nbLib.defaultHardening // {

View File

@ -111,7 +111,6 @@ in {
requires = [ "bitcoind.service" ];
after = [ "bitcoind.service" ];
preStart = ''
chown -R '${cfg.user}:${cfg.group}' '${cfg.dataDir}'
# The RPC socket has to be removed otherwise we might have stale sockets
rm -f ${cfg.networkDir}/lightning-rpc
install -m 640 ${configFile} '${cfg.dataDir}/config'

View File

@ -74,7 +74,7 @@ in {
serviceConfig = nbLib.defaultHardening // rec {
DynamicUser = true;
StateDirectory = "joinmarket-ob-watcher";
StateDirectoryMode = "0770";
StateDirectoryMode = "770";
WorkingDirectory = cfg.dataDir; # The service creates dir 'logs' in the working dir
ExecStart = ''
${nbPkgs.joinmarket}/bin/ob-watcher --datadir=${cfg.dataDir} \

View File

@ -282,7 +282,7 @@ in {
users.groups.${cfg.group} = {};
nix-bitcoin.operator = {
groups = [ cfg.group ];
allowRunAsUsers = [ cfg.group ];
allowRunAsUsers = [ cfg.user ];
};
nix-bitcoin.secrets.jm-wallet-password.user = cfg.user;

View File

@ -221,7 +221,6 @@ in {
after = [ "bitcoind.service" ];
wantedBy = [ "multi-user.target" ];
preStart = ''
chown -R '${cfg.user}:${cfg.group}' '${cfg.dataDir}'
install -m 640 ${configFile} '${cfg.dataDir}/elements.conf'
{
echo "rpcpassword=$(cat ${secretsDir}/liquid-rpcpassword)"

View File

@ -157,6 +157,16 @@ in {
{ assertion = bitcoind.prune == 0;
message = "lnd does not support bitcoind pruning.";
}
{ assertion =
!(config.services ? clightning)
|| !config.services.clightning.enable
|| config.services.clightning.port != cfg.port;
message = ''
LND and clightning can't both bind to lightning port 9735. Either
disable LND/clightning or change services.clightning.port or
services.lnd.port to a port other than 9735.
'';
}
];
services.bitcoind = {
@ -207,31 +217,31 @@ in {
(nbLib.script "lnd-create-wallet" ''
attempts=250
while ! { exec 3>/dev/tcp/${cfg.restAddress}/${toString cfg.restPort} && exec 3>&-; } &>/dev/null; do
((attempts-- == 0)) && { echo "lnd REST service unreachable"; exit 1; }
sleep 0.1
((attempts-- == 0)) && { echo "lnd REST service unreachable"; exit 1; }
sleep 0.1
done
if [[ ! -f ${networkDir}/wallet.db ]]; then
mnemonic="${cfg.dataDir}/lnd-seed-mnemonic"
if [[ ! -f "$mnemonic" ]]; then
echo Create lnd seed
echo "Create lnd seed"
umask u=r,go=
${curl} -X GET ${restUrl}/genseed | ${pkgs.jq}/bin/jq -c '.cipher_seed_mnemonic' > "$mnemonic"
fi
echo Create lnd wallet
echo "Create lnd wallet"
${curl} --output /dev/null \
-X POST -d "{\"wallet_password\": \"$(cat ${secretsDir}/lnd-wallet-password | tr -d '\n' | base64 -w0)\", \
\"cipher_seed_mnemonic\": $(cat "$mnemonic" | tr -d '\n')}" \
${restUrl}/initwallet
# Guarantees that RPC calls with cfg.cli succeed after the service is started
echo Wait until wallet is created
echo "Wait until wallet is created"
while [[ ! -f ${networkDir}/admin.macaroon ]]; do
sleep 0.1
done
else
echo Unlock lnd wallet
echo "Unlock lnd wallet"
${curl} \
-H "Grpc-Metadata-macaroon: $(${pkgs.xxd}/bin/xxd -ps -u -c 99999 '${networkDir}/admin.macaroon')" \
-X POST \
@ -244,7 +254,7 @@ in {
done
'')
# Setting macaroon permission for other users needs root permissions
(nbLib.privileged "lnd-create-macaroons" ''
(nbLib.rootScript "lnd-create-macaroons" ''
umask ug=r,o=
${lib.concatMapStrings (macaroon: ''
echo "Create custom macaroon ${macaroon}"

View File

@ -1,9 +1,10 @@
{ config, pkgs, lib, ... }:
with lib;
{
# The modules are topologically sorted by their dependencies.
# This means that modules only depend on modules higher in the list
# (unless otherwise noted).
imports = [
# Core modules
./nix-bitcoin.nix
./secrets/secrets.nix
./operator.nix
@ -13,7 +14,7 @@ with lib;
./clightning-plugins
./spark-wallet.nix
./lnd.nix
./lnd-rest-onion-service.nix
./lnd-rest-onion-service.nix # Requires onion-addresses.nix
./lightning-loop.nix
./lightning-pool.nix
./charge-lnd.nix
@ -36,56 +37,4 @@ with lib;
];
disabledModules = [ "services/networking/bitcoind.nix" ];
options = {
nix-bitcoin = {
pkgs = mkOption {
type = types.attrs;
default = (import ../pkgs { inherit pkgs; }).modulesPkgs;
};
lib = mkOption {
readOnly = true;
default = import ../pkgs/lib.nix lib pkgs;
};
torClientAddressWithPort = mkOption {
readOnly = true;
default = with config.services.tor.client.socksListenAddress;
"${addr}:${toString port}";
};
# Torify binary that works with custom Tor SOCKS addresses
# Related issue: https://github.com/NixOS/nixpkgs/issues/94236
torify = mkOption {
readOnly = true;
default = pkgs.writeScriptBin "torify" ''
${pkgs.tor}/bin/torify \
--address ${config.services.tor.client.socksListenAddress.addr} \
"$@"
'';
};
# A helper for using doas instead of sudo when doas is enabled
runAsUserCmd = mkOption {
readOnly = true;
default = if config.security.doas.enable
# TODO: Use absolute path until https://github.com/NixOS/nixpkgs/pull/133622 is available.
then "/run/wrappers/bin/doas -u"
else "sudo -u";
};
};
};
config = {
assertions = [
{ assertion = (config.services.lnd.enable -> ( !config.services.clightning.enable || config.services.clightning.port != config.services.lnd.port));
message = ''
LND and clightning can't both bind to lightning port 9735. Either
disable LND/clightning or change services.clightning.bindPort or
services.lnd.port to a port other than 9735.
'';
}
];
};
}

View File

@ -1,9 +1,44 @@
# This file exists only for backwards compatibility
{ config, pkgs, lib, ... }:
{ lib, ... }:
with lib;
{
imports = [
./presets/secure-node.nix
(lib.mkRemovedOptionModule [ "services" "nix-bitcoin" "enable" ] "Please directly import ./presets/secure-node.nix")
];
options = {
nix-bitcoin = {
pkgs = mkOption {
type = types.attrs;
default = (import ../pkgs { inherit pkgs; }).modulesPkgs;
};
lib = mkOption {
readOnly = true;
default = import ../pkgs/lib.nix lib pkgs;
};
torClientAddressWithPort = mkOption {
readOnly = true;
default = with config.services.tor.client.socksListenAddress;
"${addr}:${toString port}";
};
# Torify binary that works with custom Tor SOCKS addresses
# Related issue: https://github.com/NixOS/nixpkgs/issues/94236
torify = mkOption {
readOnly = true;
default = pkgs.writeScriptBin "torify" ''
${pkgs.tor}/bin/torify \
--address ${config.services.tor.client.socksListenAddress.addr} \
"$@"
'';
};
# A helper for using doas instead of sudo when doas is enabled
runAsUserCmd = mkOption {
readOnly = true;
default = if config.security.doas.enable
# TODO: Use absolute path until https://github.com/NixOS/nixpkgs/pull/133622 is available.
then "/run/wrappers/bin/doas -u"
else "sudo -u";
};
};
};
}

View File

@ -94,13 +94,13 @@ let
""")
'';
mkIfOnionPort = name: fn:
if onionServices ? ${name} then
fn (toString (builtins.elemAt onionServices.${name}.map 0).port)
else
"";
mkIfOnionPort = name: fn:
if onionServices ? ${name} then
fn (toString (builtins.elemAt onionServices.${name}.map 0).port)
else
"";
inherit (config.services.tor.relay) onionServices;
inherit (config.services.tor.relay) onionServices;
in {
options = {
nix-bitcoin.nodeinfo = {

View File

@ -10,7 +10,7 @@ let
pay_tallycoin() {
NAME=$1
AMOUNT=$2
echo Attempting to pay $AMOUNT sat to $NAME
echo "Attempting to pay $AMOUNT sat to $NAME"
INVOICE=$(curl --socks5-hostname ${config.nix-bitcoin.torClientAddressWithPort} -d "satoshi_amount=$AMOUNT&payment_method=ln&id=$NAME&type=profile" -X POST https://api.tallyco.in/v1/payment/request/ | jq -r '.lightning_pay_request') 2> /dev/null
if [ -z "$INVOICE" ] || [ "$INVOICE" = "null" ]; then
echo "ERROR: did not get invoice from tallycoin"
@ -23,10 +23,10 @@ let
return
fi
if [ $DECODED_AMOUNT -eq $AMOUNT ]; then
echo Paying with invoice "$INVOICE"
echo "Paying with invoice $INVOICE"
$LNCLI pay "$INVOICE"
else
echo ERROR: requested amount and invoice amount do not match. $AMOUNT vs $DECODED_AMOUNT
echo "ERROR: requested amount and invoice amount do not match. $AMOUNT vs $DECODED_AMOUNT"
return
fi
}

View File

@ -60,6 +60,7 @@ in
};
secretsSetupMethod = mkOption {
internal = true;
type = types.str;
default = throw ''
Error: No secrets setup method has been defined.
@ -110,17 +111,17 @@ in
''}
setupSecret() {
file="$1"
user="$2"
group="$3"
permissions="$4"
if [[ ! -e $file ]]; then
echo "Error: Secret file '$file' is missing"
exit 1
fi
chown "$user:$group" "$file"
chmod "$permissions" "$file"
processedFiles+=("$file")
file="$1"
user="$2"
group="$3"
permissions="$4"
if [[ ! -e $file ]]; then
echo "Error: Secret file '$file' is missing"
exit 1
fi
chown "$user:$group" "$file"
chmod "$permissions" "$file"
processedFiles+=("$file")
}
dir="${cfg.secretsDir}"

View File

@ -1,5 +1,10 @@
{ config, pkgs, lib, ... }:
# Workflow for releasing a new nix-bitcoin version with incompatible changes:
# Let V be the version of the upcoming, incompatible release.
# 1. Add change descriptions with `version = V` at the end of the `changes` list below.
# 2. Set `nix-bitcoin.configVersion = V` in ../examples/configuration.nix.
with lib;
let
version = config.nix-bitcoin.configVersion;

View File

@ -3,7 +3,7 @@ lib: pkgs:
with lib;
# See `man systemd.exec` and `man systemd.resource-control` for an explanation
# of the systemd-related options available through this module.
# of the systemd-related options available through this file.
let self = {
# These settings roughly follow systemd's "strict" security profile
defaultHardening = {
@ -70,7 +70,7 @@ let self = {
'';
# Used for ExecStart*
privileged = name: src: "+${self.script name src}";
rootScript = name: src: "+${self.script name src}";
cliExec = mkOption {
# Used by netns-isolation to execute the cli in the service's private netns

View File

@ -274,10 +274,11 @@ examples() {
script="
set -e
./deploy-container.sh
./deploy-container-minimal.sh
./deploy-qemu-vm.sh
./deploy-krops.sh
"
(cd $scriptDir/../examples && nix-shell --run "$script")
(cd "$scriptDir/../examples" && nix-shell --run "$script")
}
all() {