From 8aa28da110123c1d5de9dad343615dace8cb4337 Mon Sep 17 00:00:00 2001 From: Erik Arvstedt Date: Fri, 26 Nov 2021 15:13:28 +0100 Subject: [PATCH 01/17] remove `recurring-donations` module This module has failed to evaluate for quite some time. We might bring it back someday with bolt12 and LNURL support. --- README.md | 1 - examples/configuration.nix | 16 ----- modules/default.nix | 1 - modules/modules.nix | 1 - modules/netns-isolation.nix | 4 -- modules/presets/enable-tor.nix | 1 - modules/recurring-donations.nix | 107 -------------------------------- 7 files changed, 131 deletions(-) delete mode 100644 modules/recurring-donations.nix diff --git a/README.md b/README.md index 2956de9..dea57e3 100644 --- a/README.md +++ b/README.md @@ -75,7 +75,6 @@ NixOS modules ([src](modules/modules.nix)) * [liquid](https://github.com/elementsproject/elements) * [JoinMarket](https://github.com/joinmarket-org/joinmarket-clientserver) * [JoinMarket Orderbook Watcher](https://github.com/JoinMarket-Org/joinmarket-clientserver/blob/master/docs/orderbook.md) - * [recurring-donations](modules/recurring-donations.nix): for periodic lightning payments * [bitcoin-core-hwi](https://github.com/bitcoin-core/HWI) * Helper * [netns-isolation](modules/netns-isolation.nix): isolates applications on the network-level via network namespaces diff --git a/examples/configuration.nix b/examples/configuration.nix index 03dd1ba..66212ff 100644 --- a/examples/configuration.nix +++ b/examples/configuration.nix @@ -145,22 +145,6 @@ # # Liquid can be controlled with command 'elements-cli'. - ### RECURRING-DONATIONS - # Set this to enable recurring donations. This is EXPERIMENTAL; it's - # not guaranteed that payments are succeeding or that you will notice payment - # failure. - # 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. - # services.recurring-donations.tallycoin = { - # "" = " - # "" = ; - # "djbooth007" = 1000; - # }; - ### Hardware wallets # Enable the following to allow using hardware wallets. # See https://github.com/bitcoin-core/HWI for more information. diff --git a/modules/default.nix b/modules/default.nix index 6cef1ed..f173f9a 100644 --- a/modules/default.nix +++ b/modules/default.nix @@ -8,7 +8,6 @@ presets.secure-node = ./presets/secure-node.nix; rtl = ./rtl.nix; spark-wallet = ./spark-wallet.nix; - recurring-donations = ./recurring-donations.nix; lnd = ./lnd.nix; charge-lnd = ./charge-lnd.nix; joinmarket = ./joinmarket.nix; diff --git a/modules/modules.nix b/modules/modules.nix index 428eff8..e7a6a63 100644 --- a/modules/modules.nix +++ b/modules/modules.nix @@ -25,7 +25,6 @@ ./joinmarket.nix ./joinmarket-ob-watcher.nix ./hardware-wallets.nix - ./recurring-donations.nix # Support features ./versioning.nix diff --git a/modules/netns-isolation.nix b/modules/netns-isolation.nix index ff39ac8..afce2a5 100644 --- a/modules/netns-isolation.nix +++ b/modules/netns-isolation.nix @@ -246,10 +246,6 @@ in { id = 17; # communicates with clightning over lightning-rpc socket }; - recurring-donations = { - id = 20; - # communicates with clightning over lightning-rpc socket - }; nginx = { id = 21; }; diff --git a/modules/presets/enable-tor.nix b/modules/presets/enable-tor.nix index 583c6c1..ccde835 100644 --- a/modules/presets/enable-tor.nix +++ b/modules/presets/enable-tor.nix @@ -19,7 +19,6 @@ in { # btcpayserver.enforceTor = true; nbxplorer.enforceTor = true; spark-wallet.enforceTor = true; - recurring-donations.enforceTor = true; lightning-pool.enforceTor = true; rtl.enforceTor = true; }; diff --git a/modules/recurring-donations.nix b/modules/recurring-donations.nix deleted file mode 100644 index 84922a0..0000000 --- a/modules/recurring-donations.nix +++ /dev/null @@ -1,107 +0,0 @@ -{ config, lib, pkgs, ... }: - -with lib; -let - options.services.recurring-donations = { - enable = mkEnableOption "recurring-donations"; - tallycoin = mkOption { - type = types.attrs; - default = {}; - description = '' - This option is used to specify tallycoin donation receivers using an - attribute set. For example the following setting instructs the module - to repeatedly send 1000 satoshis to djbooth007. - { - "djbooth007" = 1000; - } - ''; - }; - interval = mkOption { - type = types.str; - default = "Mon *-*-* 00:00:00"; - description = '' - Schedules the donations. Default is weekly on Mon 00:00:00. See `man - systemd.time` for further options. - ''; - }; - randomizedDelaySec = mkOption { - type = types.int; - default = 86400; - description = '' - Random delay to add to scheduled time for donation. Default is one day. - ''; - }; - enforceTor = nbLib.enforceTor; - }; - - cfg = config.services.recurring-donations; - nbLib = config.nix-bitcoin.lib; - recurring-donations-script = pkgs.writeScript "recurring-donations.sh" '' - LNCLI="${config.nix-bitcoin.pkgs.clightning}/bin/lightning-cli --lightning-dir=${config.services.clightning.dataDir}" - pay_tallycoin() { - NAME=$1 - AMOUNT=$2 - 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" - return - fi - # Decode invoice and compare amount with requested amount - DECODED_AMOUNT=$($LNCLI decodepay "$INVOICE" | jq -r '.amount_msat' | head -c -8) - if [ -z "$DECODED_AMOUNT" ] || [ "$DECODED_AMOUNT" = "null" ]; then - echo "ERROR: did not get response from clightning" - return - fi - if [ $DECODED_AMOUNT -eq $AMOUNT ]; then - echo "Paying with invoice $INVOICE" - $LNCLI pay "$INVOICE" - else - echo "ERROR: requested amount and invoice amount do not match. $AMOUNT vs $DECODED_AMOUNT" - return - fi - } - ${ builtins.foldl' - (x: receiver: x + - '' - pay_tallycoin ${receiver} ${toString (builtins.getAttr receiver cfg.tallycoin)} - '') - "" - (builtins.attrNames cfg.tallycoin) - } - ''; -in { - inherit options; - - config = mkIf cfg.enable { - services.clightning.enable = true; - - systemd.services.recurring-donations = { - requires = [ "clightning.service" ]; - after = [ "clightning.service" ]; - path = with pkgs; [ nix-bitcoin.clightning curl jq ]; - serviceConfig = nbLib.defaultHardening // { - ExecStart = "${pkgs.bash}/bin/bash ${recurring-donations-script}"; - User = "recurring-donations"; - Type = "oneshot"; - } // nbLib.allowedIPAddresses cfg.enforceTor; - }; - systemd.timers.recurring-donations = { - requires = [ "clightning.service" ]; - after = [ "clightning.service" ]; - timerConfig = { - Unit = "recurring-donations.service"; - OnCalendar = cfg.interval; - RandomizedDelaySec = toString cfg.randomizedDelaySec; - }; - wantedBy = [ "multi-user.target" ]; - }; - - users.users.recurring-donations = { - isSystemUser = true; - group = "recurring-donations"; - extraGroups = [ config.services.clightning.group ]; - }; - users.groups.recurring-donations = {}; - }; -} From bd275d3a9ad45d950e157821d4345d2d37257c08 Mon Sep 17 00:00:00 2001 From: Erik Arvstedt Date: Fri, 26 Nov 2021 15:13:29 +0100 Subject: [PATCH 02/17] minor improvements - README: - Add RTL - examples/configuration.nix: - Fix comment - btcpayserver.nix: - Use nbLib.addressWithPort - Embed optionalString like the other optionalStrings - clboss.nix: - Improve description - clightning.nix: - Option `extraConfig`: Add example, improve description. - Disable `log-timestamps`. Timestamps are already logged via journald. - Simplify `preStart` script - electrs.nix: - Use `port` description wording like in other services. --- README.md | 1 + examples/configuration.nix | 2 +- modules/btcpayserver.nix | 5 +++-- modules/clightning-plugins/clboss.nix | 4 +++- modules/clightning.nix | 17 ++++++++++++++--- modules/electrs.nix | 2 +- 6 files changed, 23 insertions(+), 8 deletions(-) diff --git a/README.md b/README.md index dea57e3..8c9d614 100644 --- a/README.md +++ b/README.md @@ -69,6 +69,7 @@ NixOS modules ([src](modules/modules.nix)) * [Lightning Pool](https://github.com/lightninglabs/pool) * [charge-lnd](https://github.com/accumulator/charge-lnd): policy-based channel fee manager * [lndconnect](https://github.com/LN-Zap/lndconnect) via a REST onion service + * [Ride The Lightning](https://github.com/Ride-The-Lightning/RTL): web interface for `lnd` and `clightning` * [spark-wallet](https://github.com/shesek/spark-wallet) * [electrs](https://github.com/romanz/electrs) * [btcpayserver](https://github.com/btcpayserver/btcpayserver) diff --git a/examples/configuration.nix b/examples/configuration.nix index 66212ff..4e75f64 100644 --- a/examples/configuration.nix +++ b/examples/configuration.nix @@ -16,7 +16,7 @@ # See the comments at the top of `hardened-extended.nix` for further details. # - # FIXME: Uncomment next line to import your hardware configuration. If so, + # FIXME: Uncomment the next line to import your hardware configuration. If so, # add the hardware configuration file to the same directory as this file. #./hardware-configuration.nix ]; diff --git a/modules/btcpayserver.nix b/modules/btcpayserver.nix index 5143b48..55b709a 100644 --- a/modules/btcpayserver.nix +++ b/modules/btcpayserver.nix @@ -186,7 +186,7 @@ in { }; systemd.services.btcpayserver = let - nbExplorerUrl = "http://${cfg.nbxplorer.address}:${toString cfg.nbxplorer.port}/"; + nbExplorerUrl = "http://${nbLib.addressWithPort cfg.nbxplorer.address cfg.nbxplorer.port}/"; nbExplorerCookie = "${cfg.nbxplorer.dataDir}/${bitcoind.makeNetworkName "Main" "RegTest"}/.cookie"; configFile = builtins.toFile "config" ('' network=${bitcoind.network} @@ -196,7 +196,8 @@ in { btcexplorerurl=${nbExplorerUrl} btcexplorercookiefile=${nbExplorerCookie} postgres=User ID=${cfg.btcpayserver.user};Host=/run/postgresql;Database=btcpaydb - ${optionalString (cfg.btcpayserver.rootpath != null) "rootpath=${cfg.btcpayserver.rootpath}"} + '' + optionalString (cfg.btcpayserver.rootpath != null) '' + rootpath=${cfg.btcpayserver.rootpath} '' + optionalString (cfg.btcpayserver.lightningBackend == "clightning") '' btclightning=type=clightning;server=unix:///${cfg.clightning.dataDir}/bitcoin/lightning-rpc '' + optionalString cfg.btcpayserver.lbtc '' diff --git a/modules/clightning-plugins/clboss.nix b/modules/clightning-plugins/clboss.nix index c50c85e..c07122c 100644 --- a/modules/clightning-plugins/clboss.nix +++ b/modules/clightning-plugins/clboss.nix @@ -9,7 +9,9 @@ let cfg = config.services.clightning.plugins.clboss; in type = types.ints.positive; default = 30000; description = '' - Specify target amount (in satoshi) that CLBOSS will leave onchain. + Target amount (in satoshi) that CLBOSS will leave on-chain. + clboss will only open new channels if this amount is smaller than + the funds in your clightning wallet. ''; }; package = mkOption { diff --git a/modules/clightning.nix b/modules/clightning.nix index 44809e4..f9a41d3 100644 --- a/modules/clightning.nix +++ b/modules/clightning.nix @@ -43,7 +43,16 @@ let extraConfig = mkOption { type = types.lines; default = ""; - description = "Extra lines appended to the configuration file."; + example = '' + alias=mynode + ''; + description = '' + Extra lines appended to the configuration file. + + See all available options at + https://github.com/ElementsProject/lightning/blob/master/doc/lightningd-config.5.md + or by running `lightningd --help`. + ''; }; user = mkOption { type = types.str; @@ -88,6 +97,7 @@ let bitcoin-rpcport=${toString config.services.bitcoind.rpc.port} bitcoin-rpcuser=${config.services.bitcoind.rpc.users.public.name} rpc-file-mode=0660 + log-timestamps=false ${cfg.extraConfig} ''; @@ -123,13 +133,14 @@ in { preStart = '' # 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' + umask u=rw,g=r,o= { + cat ${configFile} echo "bitcoin-rpcpassword=$(cat ${config.nix-bitcoin.secretsDir}/bitcoin-rpcpassword-public)" ${optionalString (cfg.getPublicAddressCmd != "") '' echo "announce-addr=$(${cfg.getPublicAddressCmd}):${toString publicPort}" ''} - } >> '${cfg.dataDir}/config' + } > '${cfg.dataDir}/config' ''; serviceConfig = nbLib.defaultHardening // { ExecStart = "${nbPkgs.clightning}/bin/lightningd --lightning-dir=${cfg.dataDir}"; diff --git a/modules/electrs.nix b/modules/electrs.nix index 3dee769..5f9b042 100644 --- a/modules/electrs.nix +++ b/modules/electrs.nix @@ -12,7 +12,7 @@ let port = mkOption { type = types.port; default = 50001; - description = "RPC port."; + description = "Port to listen for RPC connections."; }; dataDir = mkOption { type = types.path; From e44cd7ecdc7ae72cf7256d01bdf4efbf9d06f417 Mon Sep 17 00:00:00 2001 From: Erik Arvstedt Date: Fri, 26 Nov 2021 15:13:30 +0100 Subject: [PATCH 03/17] rtl: improve descriptions Also move cl-rest to the bottom. --- modules/rtl.nix | 30 +++++++++++++++++------------- 1 file changed, 17 insertions(+), 13 deletions(-) diff --git a/modules/rtl.nix b/modules/rtl.nix index 70797f1..4d44310 100644 --- a/modules/rtl.nix +++ b/modules/rtl.nix @@ -23,12 +23,12 @@ let clightning = mkOption { type = types.bool; default = false; - description = "Add a node interface for clightning."; + description = "Enable the clightning node interface."; }; lnd = mkOption { type = types.bool; default = false; - description = "Add a node interface for lnd."; + description = "Enable the lnd node interface."; }; reverseOrder = mkOption { type = types.bool; @@ -49,11 +49,25 @@ let default = false; description = "Enable the Night UI Theme."; }; + user = mkOption { + type = types.str; + default = "rtl"; + description = "The user as which to run RTL."; + }; + group = mkOption { + type = types.str; + default = cfg.user; + description = "The group as which to run RTL."; + }; cl-rest = { enable = mkOption { + readOnly = true; type = types.bool; default = cfg.nodes.clightning; - description = "Enable c-lightning-REST server."; + description = '' + Enable c-lightning-REST server. This service is required for + clightning support and is automatically enabled. + ''; }; address = mkOption { readOnly = true; @@ -75,16 +89,6 @@ let description = "Swagger API documentation server port."; }; }; - user = mkOption { - type = types.str; - default = "rtl"; - description = "The user as which to run RTL."; - }; - group = mkOption { - type = types.str; - default = cfg.user; - description = "The group as which to run RTL."; - }; inherit (nbLib) enforceTor; }; From e1d869d76c40c5d981b302a1df102891e4e2560c Mon Sep 17 00:00:00 2001 From: Erik Arvstedt Date: Fri, 26 Nov 2021 15:13:31 +0100 Subject: [PATCH 04/17] modules.nix: move rtl to fix topological sorting rtl depends on lnd and lightning-loop. --- modules/modules.nix | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/modules/modules.nix b/modules/modules.nix index e7a6a63..a0512f6 100644 --- a/modules/modules.nix +++ b/modules/modules.nix @@ -12,13 +12,13 @@ ./bitcoind.nix ./clightning.nix ./clightning-plugins - ./rtl.nix ./spark-wallet.nix ./lnd.nix ./lnd-rest-onion-service.nix # Requires onion-addresses.nix ./lightning-loop.nix ./lightning-pool.nix ./charge-lnd.nix + ./rtl.nix ./electrs.nix ./liquid.nix ./btcpayserver.nix From 017e08ca10d44d3e08b11de3c6c5613c89c5999c Mon Sep 17 00:00:00 2001 From: Erik Arvstedt Date: Fri, 26 Nov 2021 15:13:32 +0100 Subject: [PATCH 05/17] btcpayserver: move nbxplorer options to bottom These are largely irrelevant to end users. --- modules/btcpayserver.nix | 81 +++++++++++++++++++++------------------- 1 file changed, 42 insertions(+), 39 deletions(-) diff --git a/modules/btcpayserver.nix b/modules/btcpayserver.nix index 55b709a..a90c611 100644 --- a/modules/btcpayserver.nix +++ b/modules/btcpayserver.nix @@ -3,45 +3,6 @@ with lib; let options.services = { - nbxplorer = { - package = mkOption { - type = types.package; - default = nbPkgs.nbxplorer; - description = "The package providing nbxplorer binaries."; - }; - address = mkOption { - type = types.str; - default = "127.0.0.1"; - description = "Address to listen on."; - }; - port = mkOption { - type = types.port; - default = 24444; - description = "Port to listen on."; - }; - 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."; - }; - enable = mkOption { - # This option is only used by netns-isolation - internal = true; - default = cfg.btcpayserver.enable; - }; - enforceTor = nbLib.enforceTor; - }; - btcpayserver = { enable = mkEnableOption "btcpayserver"; address = mkOption { @@ -95,6 +56,48 @@ let }; enforceTor = nbLib.enforceTor; }; + + nbxplorer = { + enable = mkOption { + # This option is only used by netns-isolation + internal = true; + default = cfg.btcpayserver.enable; + description = '' + nbxplorer is always enabled when btcpayserver is enabled. + ''; + }; + package = mkOption { + type = types.package; + default = nbPkgs.nbxplorer; + description = "The package providing nbxplorer binaries."; + }; + address = mkOption { + type = types.str; + default = "127.0.0.1"; + description = "Address to listen on."; + }; + port = mkOption { + type = types.port; + default = 24444; + description = "Port to listen on."; + }; + 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."; + }; + enforceTor = nbLib.enforceTor; + }; }; cfg = config.services; From c6fe017aeb8acde5b14ab91c4f76cc1f5ed9fdd3 Mon Sep 17 00:00:00 2001 From: Erik Arvstedt Date: Fri, 26 Nov 2021 15:13:33 +0100 Subject: [PATCH 06/17] netns-isolation: avoid creating service files for disabled services Only set the `serviceConfig` option when the service is enabled. Otherwise a service file is created. --- modules/netns-isolation.nix | 6 ++++-- 1 file changed, 4 insertions(+), 2 deletions(-) diff --git a/modules/netns-isolation.nix b/modules/netns-isolation.nix index afce2a5..42cf190 100644 --- a/modules/netns-isolation.nix +++ b/modules/netns-isolation.nix @@ -332,14 +332,16 @@ in { payjoinAddress = netns.joinmarket.address; cliExec = mkCliExec "joinmarket"; }; - systemd.services.joinmarket-yieldgenerator.serviceConfig.NetworkNamespacePath = "/var/run/netns/nb-joinmarket"; + systemd.services.joinmarket-yieldgenerator = mkIf config.services.joinmarket.yieldgenerator.enable { + serviceConfig.NetworkNamespacePath = "/var/run/netns/nb-joinmarket"; + }; services.joinmarket-ob-watcher.address = netns.joinmarket-ob-watcher.address; services.lightning-pool.rpcAddress = netns.lightning-pool.address; services.rtl.address = netns.rtl.address; - systemd.services.cl-rest = { + systemd.services.cl-rest = mkIf config.services.rtl.cl-rest.enable { serviceConfig.NetworkNamespacePath = "/var/run/netns/nb-rtl"; requires = [ "netns-rtl.service" ] ; after = [ "netns-rtl.service" ]; From ff24e73ad7491cb5b26ae1492ada803f6960992b Mon Sep 17 00:00:00 2001 From: Erik Arvstedt Date: Sun, 28 Nov 2021 21:19:20 +0100 Subject: [PATCH 07/17] onion-addresses: fix files not being copied When NixOS is already running and Tor is restarted due to config changes, `/var/lib/tor/state` may be present even when Tor has not yet finished setting up onion services. This caused the previous version of `onion-addresses` to not wait for Tor and to skip not yet present onion service files. `onion-addresses` now waits until each required onion service file has appeared. --- modules/onion-addresses.nix | 28 +++++++++++++++++++--------- 1 file changed, 19 insertions(+), 9 deletions(-) diff --git a/modules/onion-addresses.nix b/modules/onion-addresses.nix index 9a5cd47..07466c5 100644 --- a/modules/onion-addresses.nix +++ b/modules/onion-addresses.nix @@ -58,8 +58,20 @@ in { CapabilityBoundingSet = "CAP_CHOWN CAP_FSETID CAP_SETFCAP CAP_DAC_OVERRIDE CAP_DAC_READ_SEARCH CAP_FOWNER CAP_IPC_OWNER"; }; script = '' + waitForFile() { + file=$1 + for ((i=0; i<300; i++)); do + if [[ -e $file ]]; then + return; + fi + sleep 0.1 + done + echo "Error: File $file did not appear after 30 sec." + exit 1 + } + # Wait until tor is up - until [[ -e /var/lib/tor/state ]]; do sleep 0.1; done + waitForFile /var/lib/tor/state cd ${cfg.dataDir} rm -rf * @@ -71,22 +83,20 @@ in { ${concatMapStrings (service: '' onionFile=/var/lib/tor/onion/${service}/hostname - if [[ -e $onionFile ]]; then - cp $onionFile ${user}/${service} - chown ${user} ${user}/${service} - fi + waitForFile $onionFile + cp $onionFile ${user}/${service} + chown ${user} ${user}/${service} '') cfg.access.${user} - } + } '') (builtins.attrNames cfg.access) } ${concatMapStrings (service: '' onionFile=/var/lib/tor/onion/${service}/hostname - if [[ -e $onionFile ]]; then - install -D -o ${config.systemd.services.${service}.serviceConfig.User} -m 400 $onionFile services/${service} - fi + waitForFile $onionFile + install -D -o ${config.systemd.services.${service}.serviceConfig.User} -m 400 $onionFile services/${service} '') cfg.services} ''; }; From 9bda7305fd270765734b7a08f3a45dd8debe1650 Mon Sep 17 00:00:00 2001 From: Erik Arvstedt Date: Sun, 28 Nov 2021 21:24:49 +0100 Subject: [PATCH 08/17] services: add `tor.*` options Split `enforceTor` into `tor.proxy` and `tor.enforce`. By enabling `tor.proxy` without `tor.enforce`, a service can accept incoming clearnet connections. E.g., this allows setting up a Tor-proxied bitcoind node that accepts RPC connections from LAN. --- modules/bitcoind.nix | 6 ++-- modules/btcpayserver.nix | 8 +++--- modules/clightning-plugins/clboss.nix | 2 +- modules/clightning.nix | 8 +++--- modules/electrs.nix | 4 +-- modules/joinmarket-ob-watcher.nix | 10 +++---- modules/joinmarket.nix | 10 +++---- modules/lightning-loop.nix | 6 ++-- modules/lightning-pool.nix | 6 ++-- modules/liquid.nix | 6 ++-- modules/lnd.nix | 8 +++--- modules/netns-isolation.nix | 2 +- modules/obsolete-options.nix | 27 +++++++++++++++++- modules/presets/enable-tor.nix | 40 +++++++++++++++++++-------- modules/rtl.nix | 4 +-- modules/spark-wallet.nix | 6 ++-- pkgs/lib.nix | 21 +++++++++----- 17 files changed, 109 insertions(+), 65 deletions(-) diff --git a/modules/bitcoind.nix b/modules/bitcoind.nix index c7cd1ae..d6b1ae0 100644 --- a/modules/bitcoind.nix +++ b/modules/bitcoind.nix @@ -157,7 +157,7 @@ let }; proxy = mkOption { type = types.nullOr types.str; - default = if cfg.enforceTor then config.nix-bitcoin.torClientAddressWithPort else null; + default = if cfg.tor.proxy then config.nix-bitcoin.torClientAddressWithPort else null; description = "Connect through SOCKS5 proxy"; }; i2p = mkOption { @@ -262,7 +262,7 @@ let ''; description = "Binary to connect with the bitcoind instance."; }; - enforceTor = nbLib.enforceTor; + tor = nbLib.tor; }; }; @@ -407,7 +407,7 @@ in { Restart = "on-failure"; UMask = mkIf cfg.dataDirReadableByGroup "0027"; ReadWritePaths = cfg.dataDir; - } // nbLib.allowedIPAddresses cfg.enforceTor + } // nbLib.allowedIPAddresses cfg.tor.enforce // optionalAttrs zmqServerEnabled nbLib.allowNetlink; }; diff --git a/modules/btcpayserver.nix b/modules/btcpayserver.nix index a90c611..94f6074 100644 --- a/modules/btcpayserver.nix +++ b/modules/btcpayserver.nix @@ -54,7 +54,7 @@ let default = cfg.btcpayserver.user; description = "The group as which to run btcpayserver."; }; - enforceTor = nbLib.enforceTor; + tor.enforce = nbLib.tor.enforce; }; nbxplorer = { @@ -96,7 +96,7 @@ let default = cfg.nbxplorer.user; description = "The group as which to run nbxplorer."; }; - enforceTor = nbLib.enforceTor; + tor.enforce = nbLib.tor.enforce; }; }; @@ -185,7 +185,7 @@ in { RestartSec = "10s"; ReadWritePaths = cfg.nbxplorer.dataDir; MemoryDenyWriteExecute = "false"; - } // nbLib.allowedIPAddresses cfg.nbxplorer.enforceTor; + } // nbLib.allowedIPAddresses cfg.nbxplorer.tor.enforce; }; systemd.services.btcpayserver = let @@ -238,7 +238,7 @@ in { RestartSec = "10s"; ReadWritePaths = cfg.btcpayserver.dataDir; MemoryDenyWriteExecute = "false"; - } // nbLib.allowedIPAddresses cfg.btcpayserver.enforceTor; + } // nbLib.allowedIPAddresses cfg.btcpayserver.tor.enforce; }; in self; users.users.${cfg.nbxplorer.user} = { diff --git a/modules/clightning-plugins/clboss.nix b/modules/clightning-plugins/clboss.nix index c07122c..fe48358 100644 --- a/modules/clightning-plugins/clboss.nix +++ b/modules/clightning-plugins/clboss.nix @@ -28,6 +28,6 @@ let cfg = config.services.clightning.plugins.clboss; in ''; systemd.services.clightning.path = [ pkgs.dnsutils - ] ++ optional config.services.clightning.enforceTor (hiPrio config.nix-bitcoin.torify); + ] ++ optional config.services.clightning.tor.proxy (hiPrio config.nix-bitcoin.torify); }; } diff --git a/modules/clightning.nix b/modules/clightning.nix index f9a41d3..1c0cabf 100644 --- a/modules/clightning.nix +++ b/modules/clightning.nix @@ -16,14 +16,14 @@ let }; proxy = mkOption { type = types.nullOr types.str; - default = if cfg.enforceTor then config.nix-bitcoin.torClientAddressWithPort else null; + default = if cfg.tor.proxy then config.nix-bitcoin.torClientAddressWithPort else null; description = '' Socks proxy for connecting to Tor nodes (or for all connections if option always-use-proxy is set). ''; }; always-use-proxy = mkOption { type = types.bool; - default = cfg.enforceTor; + default = cfg.tor.proxy; description = '' Always use the proxy, even to connect to normal IP addresses. You can still connect to Unix domain sockets manually. @@ -79,7 +79,7 @@ let If left empty, no address is announced. ''; }; - inherit (nbLib) enforceTor; + tor = nbLib.tor; }; cfg = config.services.clightning; @@ -156,7 +156,7 @@ in { # # Disable seccomp filtering because clightning depends on this syscall. SystemCallFilter = []; - } // nbLib.allowedIPAddresses cfg.enforceTor; + } // nbLib.allowedIPAddresses cfg.tor.enforce; # Wait until the rpc socket appears postStart = '' while [[ ! -e ${cfg.networkDir}/lightning-rpc ]]; do diff --git a/modules/electrs.nix b/modules/electrs.nix index 5f9b042..76c6f09 100644 --- a/modules/electrs.nix +++ b/modules/electrs.nix @@ -39,7 +39,7 @@ let default = cfg.user; description = "The group as which to run electrs."; }; - enforceTor = nbLib.enforceTor; + tor.enforce = nbLib.tor.enforce; }; cfg = config.services.electrs; @@ -94,7 +94,7 @@ in { Restart = "on-failure"; RestartSec = "10s"; ReadWritePaths = cfg.dataDir; - } // nbLib.allowedIPAddresses cfg.enforceTor; + } // nbLib.allowedIPAddresses cfg.tor.enforce; }; users.users.${cfg.user} = { diff --git a/modules/joinmarket-ob-watcher.nix b/modules/joinmarket-ob-watcher.nix index 7353798..27b0b2c 100644 --- a/modules/joinmarket-ob-watcher.nix +++ b/modules/joinmarket-ob-watcher.nix @@ -29,11 +29,9 @@ let default = cfg.user; description = "The group as which to run JoinMarket."; }; - # This option is only used by netns-isolation - enforceTor = mkOption { - readOnly = true; - default = true; - }; + # This option is only used by netns-isolation. + # Tor is always enabled. + tor.enforce = nbLib.tor.enforce; }; cfg = config.services.joinmarket-ob-watcher; @@ -100,7 +98,7 @@ in { SystemCallFilter = nbLib.defaultHardening.SystemCallFilter ++ [ "mbind" ] ; Restart = "on-failure"; RestartSec = "10s"; - } // nbLib.allowTor; + } // nbLib.allowedIPAddresses cfg.tor.enforce; }; users.users.${cfg.user} = { diff --git a/modules/joinmarket.nix b/modules/joinmarket.nix index 58ca77a..94a3479 100644 --- a/modules/joinmarket.nix +++ b/modules/joinmarket.nix @@ -50,11 +50,9 @@ let readOnly = true; default = ircServers; }; - # This option is only used by netns-isolation - enforceTor = mkOption { - readOnly = true; - default = true; - }; + # This option is only used by netns-isolation. + # Tor is always enabled. + tor.enforce = nbLib.tor.enforce; inherit (nbLib) cliExec; yieldgenerator = { @@ -328,7 +326,7 @@ in { Restart = "on-failure"; RestartSec = "10s"; ReadWritePaths = cfg.dataDir; - } // nbLib.allowTor; + } // nbLib.allowedIPAddresses cfg.tor.enforce; }; users.users.${cfg.user} = { diff --git a/modules/lightning-loop.nix b/modules/lightning-loop.nix index 1249a3a..2d2441a 100644 --- a/modules/lightning-loop.nix +++ b/modules/lightning-loop.nix @@ -36,7 +36,7 @@ let }; proxy = mkOption { type = types.nullOr types.str; - default = if cfg.enforceTor then config.nix-bitcoin.torClientAddressWithPort else null; + default = if cfg.tor.proxy then config.nix-bitcoin.torClientAddressWithPort else null; description = "host:port of SOCKS5 proxy for connnecting to the loop server."; }; extraConfig = mkOption { @@ -56,7 +56,7 @@ let ''; description = "Binary to connect with the lightning-loop instance."; }; - enforceTor = nbLib.enforceTor; + tor = nbLib.tor; }; cfg = config.services.lightning-loop; @@ -105,7 +105,7 @@ in { Restart = "on-failure"; RestartSec = "10s"; ReadWritePaths = cfg.dataDir; - } // nbLib.allowedIPAddresses cfg.enforceTor; + } // nbLib.allowedIPAddresses cfg.tor.enforce; }; nix-bitcoin.secrets = { diff --git a/modules/lightning-pool.nix b/modules/lightning-pool.nix index 0c69d32..c93aa6a 100644 --- a/modules/lightning-pool.nix +++ b/modules/lightning-pool.nix @@ -36,7 +36,7 @@ let }; proxy = mkOption { type = types.nullOr types.str; - default = if cfg.enforceTor then config.nix-bitcoin.torClientAddressWithPort else null; + default = if cfg.tor.proxy then config.nix-bitcoin.torClientAddressWithPort else null; description = "host:port of SOCKS5 proxy for connnecting to the pool auction server."; }; extraConfig = mkOption { @@ -56,7 +56,7 @@ let ''; description = "Binary to connect with the lightning-pool instance."; }; - enforceTor = nbLib.enforceTor; + tor = nbLib.tor; }; cfg = config.services.lightning-pool; @@ -102,7 +102,7 @@ in { Restart = "on-failure"; RestartSec = "10s"; ReadWritePaths = cfg.dataDir; - } // (nbLib.allowedIPAddresses cfg.enforceTor) + } // (nbLib.allowedIPAddresses cfg.tor.enforce) // nbLib.allowNetlink; # required by gRPC-Go }; }; diff --git a/modules/liquid.nix b/modules/liquid.nix index dd8d884..6e7e6ad 100644 --- a/modules/liquid.nix +++ b/modules/liquid.nix @@ -98,7 +98,7 @@ let }; proxy = mkOption { type = types.nullOr types.str; - default = if cfg.enforceTor then config.nix-bitcoin.torClientAddressWithPort else null; + default = if cfg.tor.proxy then config.nix-bitcoin.torClientAddressWithPort else null; description = "Connect through SOCKS5 proxy"; }; dbCache = mkOption { @@ -156,7 +156,7 @@ let ''; description = "Binary for managing liquid swaps."; }; - enforceTor = nbLib.enforceTor; + tor = nbLib.tor; }; }; @@ -271,7 +271,7 @@ in { ExecStart = "${nbPkgs.elementsd}/bin/elementsd -datadir='${cfg.dataDir}'"; Restart = "on-failure"; ReadWritePaths = cfg.dataDir; - } // nbLib.allowedIPAddresses cfg.enforceTor; + } // nbLib.allowedIPAddresses cfg.tor.enforce; }; users.users.${cfg.user} = { diff --git a/modules/lnd.nix b/modules/lnd.nix index 0e1c76a..5d14846 100644 --- a/modules/lnd.nix +++ b/modules/lnd.nix @@ -46,7 +46,7 @@ let }; tor-socks = mkOption { type = types.nullOr types.str; - default = if cfg.enforceTor then config.nix-bitcoin.torClientAddressWithPort else null; + default = if cfg.tor.proxy then config.nix-bitcoin.torClientAddressWithPort else null; description = "Socks proxy for connecting to Tor nodes"; }; macaroons = mkOption { @@ -117,7 +117,7 @@ let default = "${secretsDir}/lnd-cert"; description = "LND TLS certificate path."; }; - inherit (nbLib) enforceTor; + tor = nbLib.tor; }; cfg = config.services.lnd; @@ -143,7 +143,7 @@ let bitcoin.active=1 bitcoin.node=bitcoind - ${optionalString (cfg.enforceTor) "tor.active=true"} + ${optionalString (cfg.tor.proxy) "tor.active=true"} ${optionalString (cfg.tor-socks != null) "tor.socks=${cfg.tor-socks}"} bitcoind.rpchost=${bitcoindRpcAddress}:${toString bitcoind.rpc.port} @@ -277,7 +277,7 @@ in { '') (attrNames cfg.macaroons)} '') ]; - } // nbLib.allowedIPAddresses cfg.enforceTor; + } // nbLib.allowedIPAddresses cfg.tor.enforce; }; users.users.${cfg.user} = { diff --git a/modules/netns-isolation.nix b/modules/netns-isolation.nix index 42cf190..09686d6 100644 --- a/modules/netns-isolation.nix +++ b/modules/netns-isolation.nix @@ -179,7 +179,7 @@ in { ${iptables} -w -A INPUT -s 127.0.0.1,${bridgeIp},${v.address} -j ACCEPT # allow return traffic to outgoing connections initiated by the service itself ${iptables} -w -A INPUT -m conntrack --ctstate ESTABLISHED -j ACCEPT - '' + optionalString (config.services.${n}.enforceTor or false) '' + '' + optionalString (config.services.${n}.tor.enforce or false) '' ${iptables} -w -P OUTPUT DROP ${iptables} -w -A OUTPUT -d 127.0.0.1,${bridgeIp},${v.address} -j ACCEPT '' + optionalString (v.availableNetns != []) '' diff --git a/modules/obsolete-options.nix b/modules/obsolete-options.nix index 137165f..fc79164 100644 --- a/modules/obsolete-options.nix +++ b/modules/obsolete-options.nix @@ -7,6 +7,16 @@ let mkRemovedOptionModule [ "services" service "announce-tor" ] '' Use option `nix-bitcoin.onionServices.${service}.public` instead. ''; + + mkSplitEnforceTorOption = service: + (mkRemovedOptionModule [ "services" service "enforceTor" ] '' + The option has been split into options `tor.proxy` and `tor.enforce`. + Set `tor.proxy = true` to proxy outgoing connections with Tor. + Set `tor.enforce = true` to only allow connections (incoming and outgoing) through Tor. + ''); + mkRenamedEnforceTorOption = service: + (mkRenamedOptionModule [ "services" service "enforceTor" ] [ "services" service "tor" "enforce" ]); + in { imports = [ (mkRenamedOptionModule [ "services" "bitcoind" "bind" ] [ "services" "bitcoind" "address" ]) @@ -33,5 +43,20 @@ in { bitcoin peer connections for syncing blocks. This performs well on low and high memory systems. '') - ]; + ] ++ + # 0.0.59 + (map mkSplitEnforceTorOption [ + "clightning" + "lightning-loop" + "lightning-pool" + "liquid" + "lnd" + "spark-wallet" + "bitcoind" + ]) ++ + (map mkRenamedEnforceTorOption [ + "btcpayserver" + "rtl" + "electrs" + ]); } diff --git a/modules/presets/enable-tor.nix b/modules/presets/enable-tor.nix index ccde835..d61341b 100644 --- a/modules/presets/enable-tor.nix +++ b/modules/presets/enable-tor.nix @@ -1,26 +1,42 @@ { lib, config, ... }: let defaultTrue = lib.mkDefault true; + defaultEnableTorProxy = { + tor.proxy = defaultTrue; + tor.enforce = defaultTrue; + }; + defaultEnforceTor = { + tor.enforce = defaultTrue; + }; in { services.tor = { enable = true; client.enable = true; }; - # Use Tor for all outgoing connections services = { - bitcoind.enforceTor = true; - clightning.enforceTor = true; - lnd.enforceTor = true; - lightning-loop.enforceTor = true; - liquidd.enforceTor = true; - electrs.enforceTor = true; + # Use Tor as a proxy for outgoing connections + # and restrict all connections to Tor + # + bitcoind = defaultEnableTorProxy; + clightning = defaultEnableTorProxy; + lnd = defaultEnableTorProxy; + lightning-loop = defaultEnableTorProxy; + liquidd = defaultEnableTorProxy; # disable Tor enforcement until btcpayserver can fetch rates over Tor - # btcpayserver.enforceTor = true; - nbxplorer.enforceTor = true; - spark-wallet.enforceTor = true; - lightning-pool.enforceTor = true; - rtl.enforceTor = true; + # btcpayserver = defaultEnableTorProxy; + spark-wallet = defaultEnableTorProxy; + lightning-pool = defaultEnableTorProxy; + + # These services don't make outgoing connections + # (or use Tor by default in case of joinmarket) + # but we restrict them to Tor just to be safe. + # + electrs = defaultEnforceTor; + nbxplorer = defaultEnforceTor; + rtl = defaultEnforceTor; + joinmarket = defaultEnforceTor; + joinmarket-ob-watcher = defaultEnforceTor; }; # Add onion services for incoming connections diff --git a/modules/rtl.nix b/modules/rtl.nix index 4d44310..f4111f3 100644 --- a/modules/rtl.nix +++ b/modules/rtl.nix @@ -89,7 +89,7 @@ let description = "Swagger API documentation server port."; }; }; - inherit (nbLib) enforceTor; + tor.enforce = nbLib.tor.enforce; }; cfg = config.services.rtl; @@ -214,7 +214,7 @@ in { Restart = "on-failure"; RestartSec = "10s"; ReadWritePaths = cfg.dataDir; - } // nbLib.allowedIPAddresses cfg.enforceTor + } // nbLib.allowedIPAddresses cfg.tor.enforce // nbLib.nodejs; }; diff --git a/modules/spark-wallet.nix b/modules/spark-wallet.nix index a55be9a..adf6c87 100644 --- a/modules/spark-wallet.nix +++ b/modules/spark-wallet.nix @@ -38,7 +38,7 @@ let default = cfg.user; description = "The group as which to run spark-wallet."; }; - inherit (nbLib) enforceTor; + tor = nbLib.tor; }; cfg = config.services.spark-wallet; @@ -57,7 +57,7 @@ let --ln-path '${clightning.networkDir}' \ --host ${cfg.address} --port ${toString cfg.port} \ --config '${config.nix-bitcoin.secretsDir}/spark-wallet-login' \ - ${optionalString cfg.enforceTor torRateProvider} \ + ${optionalString cfg.tor.proxy torRateProvider} \ $publicURL \ --pairing-qr --print-key ${cfg.extraArgs} ''; @@ -76,7 +76,7 @@ in { User = cfg.user; Restart = "on-failure"; RestartSec = "10s"; - } // nbLib.allowedIPAddresses cfg.enforceTor + } // nbLib.allowedIPAddresses cfg.tor.enforce // nbLib.nodejs; }; diff --git a/pkgs/lib.nix b/pkgs/lib.nix index 61db1b0..9181796 100644 --- a/pkgs/lib.nix +++ b/pkgs/lib.nix @@ -55,13 +55,20 @@ let self = { then self.allowLocalIPAddresses else self.allowAllIPAddresses; - enforceTor = mkOption { - type = types.bool; - default = false; - description = '' - Whether to force Tor on a service by only allowing connections from and - to 127.0.0.1; - ''; + tor = { + proxy = mkOption { + type = types.bool; + default = false; + description = "Whether to proxy outgoing connections with Tor."; + }; + enforce = mkOption { + type = types.bool; + default = false; + description = '' + Whether to enforce Tor on a service by only allowing connections + from and to localhost and link-local addresses. + ''; + }; }; script = name: src: pkgs.writers.writeBash name '' From 62a2602e7832e01b668090d5f3df1d9b2c231d11 Mon Sep 17 00:00:00 2001 From: Erik Arvstedt Date: Fri, 26 Nov 2021 15:13:36 +0100 Subject: [PATCH 09/17] electrs: use dataDir for storing extra config This is simpler and more memory-efficient. We've also changed other services to use this appraoch. Also remove unneded `wait_for_unit` in the electrs regtest test. --- modules/electrs.nix | 4 +--- test/tests.py | 1 - 2 files changed, 1 insertion(+), 4 deletions(-) diff --git a/modules/electrs.nix b/modules/electrs.nix index 76c6f09..d01d95f 100644 --- a/modules/electrs.nix +++ b/modules/electrs.nix @@ -74,10 +74,8 @@ in { > electrs.toml ''; serviceConfig = nbLib.defaultHardening // { - RuntimeDirectory = "electrs"; - RuntimeDirectoryMode = "700"; # electrs only uses the working directory for reading electrs.toml - WorkingDirectory = "/run/electrs"; + WorkingDirectory = cfg.dataDir; ExecStart = '' ${config.nix-bitcoin.pkgs.electrs}/bin/electrs -vv \ --network=${bitcoind.makeNetworkName "bitcoin" "regtest"} \ diff --git a/test/tests.py b/test/tests.py index af7cb81..d7224c4 100644 --- a/test/tests.py +++ b/test/tests.py @@ -375,7 +375,6 @@ def _(): num_blocks = test_data["num_blocks"] if enabled("electrs"): - machine.wait_for_unit("onion-addresses") machine.wait_until_succeeds(log_has_string("electrs", "serving Electrum RPC")) get_block_height_cmd = ( """echo '{"method": "blockchain.headers.subscribe", "id": 0, "params": []}'""" From 10a744a59845e59c7a31ac4fd922368110728047 Mon Sep 17 00:00:00 2001 From: Erik Arvstedt Date: Fri, 26 Nov 2021 15:13:37 +0100 Subject: [PATCH 10/17] rtl: add option `extraCurrency` --- modules/rtl.nix | 18 +++++++++++++++++- test/tests.nix | 1 + 2 files changed, 18 insertions(+), 1 deletion(-) diff --git a/modules/rtl.nix b/modules/rtl.nix index f4111f3..095fe4a 100644 --- a/modules/rtl.nix +++ b/modules/rtl.nix @@ -49,6 +49,17 @@ let default = false; description = "Enable the Night UI Theme."; }; + extraCurrency = mkOption { + type = with types; nullOr str; + default = null; + example = "USD"; + description = '' + Currency code (ISO 4217) of the extra currency used for displaying balances. + When set, this option enables online currency rate fetching. + Warning: Rate fetching requires outgoing clearnet connections, so option + `tor.enforce` is automatically disabled. + ''; + }; user = mkOption { type = types.str; default = "rtl"; @@ -118,7 +129,10 @@ let ''"channelBackupPath": "${cfg.dataDir}/backup/lnd",'' } "logLevel": "INFO", - "fiatConversion": false, + "fiatConversion": ${if cfg.extraCurrency == null then "false" else "true"}, + ${optionalString (cfg.extraCurrency != null) + ''"currencyUnit": "${cfg.extraCurrency}",'' + } ${optionalString (isLnd && cfg.loop) ''"swapServerUrl": "https://${nbLib.addressWithPort lightning-loop.restAddress lightning-loop.restPort}",'' } @@ -190,6 +204,8 @@ in { "d '${cfg.dataDir}' 0770 ${cfg.user} ${cfg.group} - -" ]; + services.rtl.tor.enforce = mkIf (cfg.extraCurrency != null) false; + systemd.services.rtl = rec { wantedBy = [ "multi-user.target" ]; requires = optional cfg.nodes.clightning "cl-rest.service" ++ diff --git a/test/tests.nix b/test/tests.nix index 9afcd97..7f06a16 100644 --- a/test/tests.nix +++ b/test/tests.nix @@ -67,6 +67,7 @@ let nix-bitcoin.generateSecretsCmds.rtl = mkIf cfg.rtl.enable (mkForce '' echo a > rtl-password ''); + services.rtl.extraCurrency = mkDefault "CHF"; tests.spark-wallet = cfg.spark-wallet.enable; From 9e4f4d6b0f9fd57ee893adb754e76501c98d36fc Mon Sep 17 00:00:00 2001 From: Erik Arvstedt Date: Fri, 26 Nov 2021 15:13:38 +0100 Subject: [PATCH 11/17] bitcoind: add option `txindex` --- modules/bitcoind.nix | 6 ++++++ 1 file changed, 6 insertions(+) diff --git a/modules/bitcoind.nix b/modules/bitcoind.nix index d6b1ae0..b38cf25 100644 --- a/modules/bitcoind.nix +++ b/modules/bitcoind.nix @@ -206,6 +206,11 @@ let Value 0 disables pruning. ''; }; + txindex = mkOption { + type = types.bool; + default = false; + description = "Enable the transaction index."; + }; zmqpubrawblock = mkOption { type = types.nullOr types.str; default = null; @@ -284,6 +289,7 @@ let ''} ${optionalString (cfg.dbCache != null) "dbcache=${toString cfg.dbCache}"} prune=${toString cfg.prune} + ${optionalString cfg.txindex "txindex=1"} ${optionalString (cfg.sysperms != null) "sysperms=${if cfg.sysperms then "1" else "0"}"} ${optionalString (cfg.disablewallet != null) "disablewallet=${if cfg.disablewallet then "1" else "0"}"} ${optionalString (cfg.assumevalid != null) "assumevalid=${cfg.assumevalid}"} From 91fbcfcc776db3201ee30869f9dded59931786a7 Mon Sep 17 00:00:00 2001 From: Erik Arvstedt Date: Fri, 26 Nov 2021 15:13:39 +0100 Subject: [PATCH 12/17] faq.md: reformat Improves readability in both the rendered and raw formats. Also, mention that `doas` is enabled only via the `secure-node.nix` template. --- docs/faq.md | 25 +++++++++++++++++++------ 1 file changed, 19 insertions(+), 6 deletions(-) diff --git a/docs/faq.md b/docs/faq.md index 7fa972e..53f7d1a 100644 --- a/docs/faq.md +++ b/docs/faq.md @@ -1,6 +1,19 @@ -* **Q:** The clightning service is running but when I try to use it (f.e. by running `lightning-cli getinfo` as user operator) all I get is `lightning-cli: Connecting to 'lightning-rpc': Connection refused`. - * **A:** Check your clightning logs with `journalctl -eu clightning`. Do you see something like `bitcoin-cli getblock ... false` failed? Are you using pruned mode? That means that clightning hasn't seen all the blocks it needs to and it can't get that block because your node is pruned. If you're just setting up a new node you can `systemctl stop clightning` and wipe your `/var/lib/clightning` directory. Otherwise you need to reindex the Bitcoin node. -* **Q:** My disk space is getting low due to nix. - * **A:** run `nix-collect-garbage -d` -* **Q:** Where is `sudo`??? - * **A:** we replaced sudo with OpenBSD's doas after [CVE-2021-3156](https://www.openwall.com/lists/oss-security/2021/01/26/3). It has greatly reduced complexity, and is therefore less likely to be a source of severe vulnerabilities in the future. +- **Q:** The clightning service is running but when I try to use it (f.e. by running + `lightning-cli getinfo` as user operator) all I get is `lightning-cli: Connecting + to 'lightning-rpc': Connection refused`.\ + **A:** Check your clightning logs with `journalctl -eu clightning`. Do you see + something like `bitcoin-cli getblock ... false` failed? Are you using pruned mode? + That means that clightning hasn't seen all the blocks it needs to and it can't get + that block because your node is pruned. \ + If you're just setting up a new node you can `systemctl stop clightning` and wipe + your `/var/lib/clightning` directory. Otherwise you need to reindex the Bitcoin + node. + +- **Q:** My disk space is getting low due to nix.\ + **A:** run `nix-collect-garbage -d` + +- **Q:** Where is `sudo`?\ + **A:** After [CVE-2021-3156](https://www.openwall.com/lists/oss-security/2021/01/26/3), + we've replaced `sudo` with OpenBSD's `doas` for users of the `secure-node.nix` template. + It has greatly reduced complexity and is therefore less likely to be a source of + severe vulnerabilities in the future. From 8cc7b83da1077f68f7323a26717212b506f45ef9 Mon Sep 17 00:00:00 2001 From: Erik Arvstedt Date: Fri, 26 Nov 2021 15:13:40 +0100 Subject: [PATCH 13/17] usage.md: convert to '#' heading syntax Like in other docs. --- docs/usage.md | 30 ++++++++++-------------------- 1 file changed, 10 insertions(+), 20 deletions(-) diff --git a/docs/usage.md b/docs/usage.md index bb9aa50..5d290a5 100644 --- a/docs/usage.md +++ b/docs/usage.md @@ -1,5 +1,4 @@ -Updating ---- +# Updating In your deployment directory, enter the nix shell with `nix-shell` and run the following to update `nix-bitcoin-release.nix`: @@ -7,12 +6,10 @@ following to update `nix-bitcoin-release.nix`: update-nix-bitcoin ``` -Nodeinfo ---- +# Nodeinfo Run `nodeinfo` to see onion addresses and local addresses for enabled services. -Connect to RTL ---- +# Connect to RTL Normally you would connect to RTL via SSH tunneling with a command like this ``` @@ -29,8 +26,7 @@ Otherwise, you can access it via Tor Browser at `http://`. You can find the `` with command `nodeinfo`. The default password location is `/secrets/rtl-password`. -Connect to spark-wallet ---- +# Connect to spark-wallet ### Requirements * Android phone * [Orbot](https://guardianproject.info/apps/orbot/) installed from [F-Droid](https://guardianproject.info/fdroid) (recommended) or [Google Play](https://play.google.com/store/apps/details?id=org.torproject.android&hl=en) @@ -73,8 +69,7 @@ Connect to spark-wallet Done ``` -Connect to LND with Zeus ---- +# Connect to LND with Zeus ### Requirements * Android phone * [Orbot](https://guardianproject.info/apps/orbot/) installed from @@ -110,8 +105,7 @@ Connect to LND with Zeus 5. Scan the QR code with your Zeus wallet and start sending Satoshis privately -Connect to electrs ---- +# Connect to electrs ### Requirements Android * Android phone * [Orbot](https://guardianproject.info/apps/orbot/) installed from [F-Droid](https://guardianproject.info/fdroid) (recommended) or [Google Play](https://play.google.com/store/apps/details?id=org.torproject.android&hl=en) @@ -158,8 +152,7 @@ Connect to electrs Network > Server: :t ``` -Connect to nix-bitcoin node through the SSH onion service ---- +# Connect to nix-bitcoin node through the SSH onion service 1. Get the SSH onion address (excluding the port suffix) ``` @@ -195,8 +188,7 @@ Connect to nix-bitcoin node through the SSH onion service 6. After deploying the new configuration, it will connect through the SSH tunnel you established in step iv. This also allows you to do more complex SSH setups that some deployment tools don't support. An example would be authenticating with [Trezor's SSH agent](https://github.com/romanz/trezor-agent), which provides extra security. -Initialize a Trezor for Bitcoin Core's Hardware Wallet Interface ---- +# Initialize a Trezor for Bitcoin Core's Hardware Wallet Interface 1. Enable Trezor in `configuration.nix` @@ -258,8 +250,7 @@ Initialize a Trezor for Bitcoin Core's Hardware Wallet Interface 8. Follow Bitcoin Core's instructions on [Using Bitcoin Core with Hardware Wallets](https://github.com/bitcoin-core/HWI/blob/master/docs/bitcoin-core-usage.md) to use your Trezor with `bitcoin-cli` on your nix-bitcoin node -JoinMarket ---- +# JoinMarket ## Diff to regular JoinMarket usage @@ -380,8 +371,7 @@ See [here](https://github.com/JoinMarket-Org/joinmarket-clientserver/blob/master 3. Profit -clightning ---- +# clightning ## Plugins From 94aee8174d291a7f1265834c8e515a64451841eb Mon Sep 17 00:00:00 2001 From: Erik Arvstedt Date: Fri, 26 Nov 2021 15:13:41 +0100 Subject: [PATCH 14/17] usage.md: add section `Managing services` --- docs/usage.md | 25 +++++++++++++++++++++++++ 1 file changed, 25 insertions(+) diff --git a/docs/usage.md b/docs/usage.md index 5d290a5..08ba40b 100644 --- a/docs/usage.md +++ b/docs/usage.md @@ -9,6 +9,31 @@ update-nix-bitcoin # Nodeinfo Run `nodeinfo` to see onion addresses and local addresses for enabled services. +# Managing services + +NixOS uses the [systemd](https://wiki.archlinux.org/title/systemd) service manager. + +Usage: +```shell +# Show service status +systemctl status bitcoind + +# Show the last 100 log messages +journalctl -u bitcoind -n 100 +# Show all log messages since the last system boot +journalctl -b -u bitcoind + +# These commands require root permissions +systemctl stop bitcoind +systemctl start bitcoind +systemctl restart bitcoind + +# Show the service definition +systemctl cat bitcoind +# Show all service parameters +systemctl show bitcoind +``` + # Connect to RTL Normally you would connect to RTL via SSH tunneling with a command like this From f52059ce3c3729fd68245d6781e7c4f13ffd0a6b Mon Sep 17 00:00:00 2001 From: Erik Arvstedt Date: Sun, 28 Nov 2021 21:27:33 +0100 Subject: [PATCH 15/17] docs: add doc 'Configuration and maintenance' - Move section `updating` from `usage.md` to `configuration.md` and rename `usage.md` -> `services.md`. `services.md` documents how enable and interact with node services. - README: Move `docs` below `Get started`. The `docs` section is short and should be easily accessible. --- README.md | 15 ++- docs/configuration.md | 240 +++++++++++++++++++++++++++++++++ docs/install.md | 5 +- docs/{usage.md => services.md} | 8 -- 4 files changed, 252 insertions(+), 16 deletions(-) create mode 100644 docs/configuration.md rename docs/{usage.md => services.md} (98%) diff --git a/README.md b/README.md index 8c9d614..e123ea4 100644 --- a/README.md +++ b/README.md @@ -47,6 +47,14 @@ Get started - To add nix-bitcoin to an existing NixOS configuration, see [importable-configuration.nix](examples/importable-configuration.nix) and the [Flake example](examples/flakes/flake.nix). +Docs +--- +* [Hardware Requirements](docs/hardware.md) +* [Installation](docs/install.md) +* [Configuration and maintenance](docs/configuration.md) +* [Using services](docs/services.md) +* [FAQ](docs/faq.md) + Features --- A [configuration preset](modules/presets/secure-node.nix) for setting up a secure node @@ -92,13 +100,6 @@ Security Note that if the machine you're deploying *from* is insecure, there is nothing nix-bitcoin can do to protect itself. -Docs ---- -* [Hardware Requirements](docs/hardware.md) -* [Install instructions](docs/install.md) -* [Usage instructions](docs/usage.md) -* [FAQ](docs/faq.md) - Troubleshooting --- If you are having problems with nix-bitcoin check the [FAQ](docs/faq.md) or submit an issue.\ diff --git a/docs/configuration.md b/docs/configuration.md new file mode 100644 index 0000000..fa872d5 --- /dev/null +++ b/docs/configuration.md @@ -0,0 +1,240 @@ +# Managing your deployment + +This section applies to users of the deployment method described in the [installation guide](./install.md). + +## Deployment shell +Run command `nix-shell` in your deployment directory.\ +You now have access to deployment commands: + +- `deploy`\ + Deploy the current configuration to your node. +- `eval-config`\ + Locally evaluate the configuration. This is useful to check for configuration errors. +- `h`, `help`\ + Show help + +## Updating nix-bitcoin +Run `update-nix-bitcoin` from the deployment shell.\ +This fetches the latest release, verifies its signatures and updates `nix-bitcoin-release.nix`. + +# Customizing your configuration + +## Get started with Nix + +See [Nix - A One Pager](https://github.com/tazjin/nix-1p) for a short guide +to Nix, the language used in `configuration.nix`. + +You can follow along this guide by running command `nix repl` which allows you to interactively +evaluate Nix expressions. + +For a general introduction to the Nix and NixOS ecosystem, see [nix.dev](https://nix.dev/). + +## Set options + +All features and services are configurable through options. You can find a list of +supported options at the top of each nix-bitcoin [module](../modules/modules.nix) +(Examples: [bitcoind.nix](../modules/bitcoind.nix), [btcpayserver.nix](../modules/btcpayserver.nix)). + +Example: Set some `bitcoind` options by adding these lines to your `configuration.nix`: +```nix +# Use a custom data dir +services.bitcoind.dataDir = "/my/datadir"; + +# Enable txindex +services.bitcoind.txindex = true; +``` + +You can also use regular [NixOS options](https://search.nixos.org/options) +for configuring your system: +```nix +networking.hostName = "myhost"; +time.timeZone = "UTC"; +``` + +## Debug your configuration + +To print the values of specific options of your config, add the following to your `configuration.nix`: +```nix +system.extraDependencies = let + debugVal = config.networking.firewall.allowedTCPPorts; + # More example options: + # debugVal = config.environment.systemPackages; + # debugVal = config.services.bitcoind.dataDir; +in lib.traceSeqN 3 debugVal []; +``` +and run command `eval-config` from the deployment shell. + +# Allowing external connections to services + +## Allow peer connections to bitcoind + +```nix +services.bitcoind = { + # Accept incoming peer connections + listen = true; + + # Listen to connections on all interfaces + address = "0.0.0.0"; + + # Set this to also add IPv6 connectivity. + extraConfig = '' + bind=:: + ''; + + # If you're using the `secure-node.nix` template, set this to allow non-Tor connections + # to bitcoind + tor.enforce = false; + # Also set this if bitcoind should not use Tor for outgoing peer connections + tor.proxy = false; +}; + +# Open the p2p port in the firewall +networking.firewall.allowedTCPPorts = [ config.services.nix-bitcoin.port ]; +``` + +## Allow bitcoind RPC connections from LAN + +```nix +services.bitcoind = { + # Listen to connections on all interfaces + address = "0.0.0.0"; + + # Allow RPC connections from external addresses + rpc.allowip = [ + "10.10.0.0/24" # Allow a subnet + "10.50.0.3" # Allow a specific address + "0.0.0.0" # Allow all addresses + ]; + + # Set this if you're using the `secure-node.nix` template + tor.enforce = false; +}; + +# Open the RPC port in the firewall +networking.firewall.allowedTCPPorts = [ config.services.nix-bitcoin.rpc.port ]; +``` + +## Allow connections to electrs + +```nix +services.electrs = { + # Listen to connections on all interfaces + address = "0.0.0.0"; + + # Set this if you're using the `secure-node.nix` template + tor.enforce = false; +}; + +# Open the electrs port in the firewall +networking.firewall.allowedTCPPorts = [ config.services.electrs.port ]; +``` + +You can use the same approach to allow connections to other services. + +# Migrate existing services to nix-bitcoin + +## Example: bitcoind + +```shell +# 1. Stop bitcoind on your nodes +ssh root@nix-bitcoin-node 'systemctl stop bitcoind' +# Also stop bitcoind on the node that you'll be copying data from + +# 2. Copy the data to the nix-bitcoin node +# Important: Add a trailing slash to the source path +rsync /path/to/existing/bitcoind-datadir/ root@nix-bitcoin-node:/var/lib/bitcoind + +# 3. Fix data dir permissions on the nix-bitcoin node +ssh root@nix-bitcoin-node 'chown -R bitcoin: /var/lib/bitcoind' + +# 4. Start bitcoind +ssh root@nix-bitcoin-node 'systemctl start bitcoind' +``` + +You can use the same workflow for other services.\ +The default data dir path is `/var/lib/` for all services. + +Some services require extra steps: + +- lnd + + Copy your wallet password to `$secretsDir/lnd-wallet-password` (See: [Secrets dir](#secrets-dir)). + +- btcpayserver + + Copy the postgresql database: + ```shell + # Export (on the other node) + sudo -u postgres pg_dump YOUR_BTCPAYSERVER_DB > export.sql + # Restore (on the nix-bitcoin node) + sudo -u postgres psql btcpaydb < export.sql + ``` + +- joinmarket + + Copy your wallet to `/var/lib/joinmarket/wallets/wallet.jmdat`.\ + Write your wallet password, without a trailing newline, to + `$secretsDir/jm-wallet-password` (See: [Secrets dir](#secrets-dir)). + +# Use bitcoind from another node + +Use a bitcoind instance running on another node within a nix-bitcoin config. + +```nix +services.bitcoind = { + # Address of the other node + address = "10.10.0.2"; + rpc.users = let + # The fully privileged bitcoind RPC username of the other node + name = "myrpcuser"; + in { + privileged.name = name; + public.name = name; + ## Set this if you use btcpayserver + # btcpayserver.name = name; + ## Set this if you use joinmarket-ob-watcher + # joinmarket-ob-watcher.name = name; + }; +}; +# Disable the local bitcoind service +systemd.services.bitcoind.wantedBy = mkForce []; +``` + +Now save the password of the RPC user to the following files on your nix-bitcoin node: +```shell +$secretsDir/bitcoin-rpcpassword-privileged +$secretsDir/bitcoin-rpcpassword-public + +## Only needed when set in the above config snippet +# $secretsDir/bitcoin-rpcpassword-btcpayserver +# $secretsDir/bitcoin-rpcpassword-joinmarket-ob-watcher +``` +See: [Secrets dir](#secrets-dir) + +# Temporarily disable a service + +Sometimes you might want to disable a service without removing the service user and +integration with other services, as it would happen when setting +`services..enable = false`. + +Use the following approach: +``` +systemd.services..wantedBy = mkForce []; +``` +This way, the systemd service still exists, but is not automatically started. + +# Appendix + +## Secrets dir + +The secrets dir is set by option `nix-bitoin.secretsDir` and has the +following default values: + +- If you're using the krops deployment method: `/var/src/secrets` + +- Otherwise: + - `/secrets` (if you're using the `secure-node.nix` template) + - `/etc/nix-bitcoin-secrets` (otherwise) + + `/secrets` only exists to provide backwards compatibility for users of the + `secure-node.nix` template. diff --git a/docs/install.md b/docs/install.md index b3c7fac..4aa2ee8 100644 --- a/docs/install.md +++ b/docs/install.md @@ -329,4 +329,7 @@ You can also build Nix from source by following the instructions at https://nixo For security reasons, all normal system management tasks can and should be performed with the `operator` user. Logging in as `root` should be done as rarely as possible. -See [usage.md](usage.md) for usage instructions, such as how to update. +See also: +- [Migrating existing services to bitcoind](configuration.md#migrate-existing-services-to-nix-bitcoin) +- [Managing your deployment](configuration.md#managing-your-deployment) +- [Using services](services.md) diff --git a/docs/usage.md b/docs/services.md similarity index 98% rename from docs/usage.md rename to docs/services.md index 08ba40b..572bc09 100644 --- a/docs/usage.md +++ b/docs/services.md @@ -1,11 +1,3 @@ -# Updating -In your deployment directory, enter the nix shell with `nix-shell` and run the -following to update `nix-bitcoin-release.nix`: - -``` -update-nix-bitcoin -``` - # Nodeinfo Run `nodeinfo` to see onion addresses and local addresses for enabled services. From 6f37bef2a359ee7f3926e3a253711cb2f04ff95f Mon Sep 17 00:00:00 2001 From: Erik Arvstedt Date: Sun, 28 Nov 2021 21:36:03 +0100 Subject: [PATCH 16/17] netns-isolation: simplify firewall setup Set all allowed INPUT/OUTPUT addresses in a single `iptables` command. --- modules/netns-isolation.nix | 10 ++++------ 1 file changed, 4 insertions(+), 6 deletions(-) diff --git a/modules/netns-isolation.nix b/modules/netns-isolation.nix index 09686d6..61ff001 100644 --- a/modules/netns-isolation.nix +++ b/modules/netns-isolation.nix @@ -156,7 +156,9 @@ in { peer = "nb-veth-br-${toString v.id}"; inherit (v) netnsName; nsenter = "${pkgs.utillinux}/bin/nsenter"; - allowedAddresses = concatMapStringsSep "," (available: netns.${available}.address) v.availableNetns; + allowedNetnsAddresses = map (available: netns.${available}.address) v.availableNetns; + allowedAddresses = concatStringsSep "," + ([ "127.0.0.1,${bridgeIp},${v.address}" ] ++ allowedNetnsAddresses); setup = '' ${ip} netns add ${netnsName} @@ -176,17 +178,13 @@ in { ${ip} route add default via ${bridgeIp} ${iptables} -w -P INPUT DROP - ${iptables} -w -A INPUT -s 127.0.0.1,${bridgeIp},${v.address} -j ACCEPT # allow return traffic to outgoing connections initiated by the service itself ${iptables} -w -A INPUT -m conntrack --ctstate ESTABLISHED -j ACCEPT + ${iptables} -w -A INPUT -s ${allowedAddresses} -j ACCEPT '' + optionalString (config.services.${n}.tor.enforce or false) '' ${iptables} -w -P OUTPUT DROP - ${iptables} -w -A OUTPUT -d 127.0.0.1,${bridgeIp},${v.address} -j ACCEPT - '' + optionalString (v.availableNetns != []) '' - ${iptables} -w -A INPUT -s ${allowedAddresses} -j ACCEPT ${iptables} -w -A OUTPUT -d ${allowedAddresses} -j ACCEPT ''; - script = name: src: pkgs.writers.writeDash name '' set -e ${src} From def64a73b8d87a1c6cb261508b53c9477d3b049f Mon Sep 17 00:00:00 2001 From: Erik Arvstedt Date: Sun, 28 Nov 2021 21:36:04 +0100 Subject: [PATCH 17/17] treewide: use TODO-EXTERNAL Use TODO-EXTERNAL for TODOs that depend on external factors like upstream fixes. --- modules/netns-isolation.nix | 3 ++- modules/nix-bitcoin.nix | 2 +- modules/presets/enable-tor.nix | 1 + pkgs/python-packages/pyln-bolt7/default.nix | 2 +- 4 files changed, 5 insertions(+), 3 deletions(-) diff --git a/modules/netns-isolation.nix b/modules/netns-isolation.nix index 61ff001..471716a 100644 --- a/modules/netns-isolation.nix +++ b/modules/netns-isolation.nix @@ -70,7 +70,8 @@ let # and # availableNetns.clighting = [ "bitcoind" ]; # - # FIXME: Although negligible for our purposes, this calculation's runtime + # TODO-EXTERNAL: + # Although negligible for our purposes, this calculation's runtime # is in the order of (number of connections * number of services), # because attrsets and lists are fully copied on each update with '//' or '++'. # This can only be improved with an update in the nix language. diff --git a/modules/nix-bitcoin.nix b/modules/nix-bitcoin.nix index bad87c1..605c115 100644 --- a/modules/nix-bitcoin.nix +++ b/modules/nix-bitcoin.nix @@ -35,7 +35,7 @@ with lib; runAsUserCmd = mkOption { readOnly = true; default = if config.security.doas.enable - # TODO: Use absolute path until https://github.com/NixOS/nixpkgs/pull/133622 is available. + # TODO-EXTERNAL: Use absolute path until https://github.com/NixOS/nixpkgs/pull/133622 is available. then "/run/wrappers/bin/doas -u" else "sudo -u"; }; diff --git a/modules/presets/enable-tor.nix b/modules/presets/enable-tor.nix index d61341b..a63634c 100644 --- a/modules/presets/enable-tor.nix +++ b/modules/presets/enable-tor.nix @@ -23,6 +23,7 @@ in { lnd = defaultEnableTorProxy; lightning-loop = defaultEnableTorProxy; liquidd = defaultEnableTorProxy; + # TODO-EXTERNAL: # disable Tor enforcement until btcpayserver can fetch rates over Tor # btcpayserver = defaultEnableTorProxy; spark-wallet = defaultEnableTorProxy; diff --git a/pkgs/python-packages/pyln-bolt7/default.nix b/pkgs/python-packages/pyln-bolt7/default.nix index 8433ba0..84cb855 100644 --- a/pkgs/python-packages/pyln-bolt7/default.nix +++ b/pkgs/python-packages/pyln-bolt7/default.nix @@ -13,7 +13,7 @@ buildPythonPackage rec { postUnpack = "sourceRoot=$sourceRoot/contrib/pyln-spec/bolt7"; - # TODO-EXTERNAL + # TODO-EXTERNAL: # Remove when this fix is released # https://github.com/ElementsProject/lightning/pull/4910 postPatch = ''