From c30aa33c15ead7c76768f9180adaed5afe712165 Mon Sep 17 00:00:00 2001 From: Erik Arvstedt Date: Sun, 1 May 2022 15:52:30 +0200 Subject: [PATCH 1/5] cl-rest: rename pkg to clightning-rest --- modules/rtl.nix | 2 +- pkgs/{cl-rest => clightning-rest}/composition.nix | 0 pkgs/{cl-rest => clightning-rest}/default.nix | 0 pkgs/{cl-rest => clightning-rest}/generate.sh | 0 pkgs/{cl-rest => clightning-rest}/node-packages.nix | 0 pkgs/{cl-rest => clightning-rest}/pkg.json | 0 pkgs/default.nix | 2 +- 7 files changed, 2 insertions(+), 2 deletions(-) rename pkgs/{cl-rest => clightning-rest}/composition.nix (100%) rename pkgs/{cl-rest => clightning-rest}/default.nix (100%) rename pkgs/{cl-rest => clightning-rest}/generate.sh (100%) rename pkgs/{cl-rest => clightning-rest}/node-packages.nix (100%) rename pkgs/{cl-rest => clightning-rest}/pkg.json (100%) diff --git a/modules/rtl.nix b/modules/rtl.nix index f40a3f7..3257b8b 100644 --- a/modules/rtl.nix +++ b/modules/rtl.nix @@ -248,7 +248,7 @@ in { StateDirectory = "cl-rest"; # cl-rest reads the config file from the working directory WorkingDirectory = cl-rest.dataDir; - ExecStart = "${nbPkgs.cl-rest}/bin/cl-rest"; + ExecStart = "${nbPkgs.clightning-rest}/bin/cl-rest"; # Show "cl-rest" instead of "node" in the journal SyslogIdentifier = "cl-rest"; User = cfg.user; diff --git a/pkgs/cl-rest/composition.nix b/pkgs/clightning-rest/composition.nix similarity index 100% rename from pkgs/cl-rest/composition.nix rename to pkgs/clightning-rest/composition.nix diff --git a/pkgs/cl-rest/default.nix b/pkgs/clightning-rest/default.nix similarity index 100% rename from pkgs/cl-rest/default.nix rename to pkgs/clightning-rest/default.nix diff --git a/pkgs/cl-rest/generate.sh b/pkgs/clightning-rest/generate.sh similarity index 100% rename from pkgs/cl-rest/generate.sh rename to pkgs/clightning-rest/generate.sh diff --git a/pkgs/cl-rest/node-packages.nix b/pkgs/clightning-rest/node-packages.nix similarity index 100% rename from pkgs/cl-rest/node-packages.nix rename to pkgs/clightning-rest/node-packages.nix diff --git a/pkgs/cl-rest/pkg.json b/pkgs/clightning-rest/pkg.json similarity index 100% rename from pkgs/cl-rest/pkg.json rename to pkgs/clightning-rest/pkg.json diff --git a/pkgs/default.nix b/pkgs/default.nix index e79149e..41fd40a 100644 --- a/pkgs/default.nix +++ b/pkgs/default.nix @@ -6,7 +6,7 @@ in , pkgsUnstable ? import nixpkgsPinned.nixpkgs-unstable { config = {}; overlays = []; } }: let self = { - cl-rest = pkgs.callPackage ./cl-rest { }; + clightning-rest = pkgs.callPackage ./clightning-rest { }; clboss = pkgs.callPackage ./clboss { }; clightning-plugins = pkgs.recurseIntoAttrs (import ./clightning-plugins pkgs self.nbPython3Packages); joinmarket = pkgs.callPackage ./joinmarket { nbPythonPackageOverrides = import ./python-packages self; }; From acf5fe69ad84df2389359f1358f9663e072cb402 Mon Sep 17 00:00:00 2001 From: Erik Arvstedt Date: Thu, 5 May 2022 21:56:16 +0200 Subject: [PATCH 2/5] add standalone `clightning-rest` service - Rename `services.rtl.cl-rest` to `services.clightning-rest`. `clightning-rest` is generally useful for connecting external REST clients to clightning. - Add a dedicated network namespace in netns-isolation. - Add nodeinfo entry. - Add datadir (which contains REST auth data) to backups. --- README.md | 1 + modules/backups.nix | 1 + modules/clightning-rest.nix | 104 +++++++++++++++++++++++++++++++++ modules/modules.nix | 1 + modules/netns-isolation.nix | 17 +++--- modules/nodeinfo.nix | 1 + modules/obsolete-options.nix | 22 ++++++- modules/presets/enable-tor.nix | 1 + modules/rtl.nix | 82 +++----------------------- modules/versioning.nix | 11 ++++ test/tests.nix | 4 ++ test/tests.py | 7 ++- 12 files changed, 166 insertions(+), 86 deletions(-) create mode 100644 modules/clightning-rest.nix diff --git a/README.md b/README.md index a088e54..6808fb4 100644 --- a/README.md +++ b/README.md @@ -73,6 +73,7 @@ NixOS modules ([src](modules/modules.nix)) * [rebalance](https://github.com/lightningd/plugins/tree/master/rebalance): keeps your channels balanced * [summary](https://github.com/lightningd/plugins/tree/master/summary): print a nice summary of the node status * [zmq](https://github.com/lightningd/plugins/tree/master/zmq): publishes notifications via ZeroMQ to configured endpoints + * [clightning-rest](https://github.com/Ride-The-Lightning/c-lightning-REST): REST server for clightning * [lnd](https://github.com/lightningnetwork/lnd) with support for announcing an onion service and [static channel backups](https://github.com/lightningnetwork/lnd/blob/master/docs/recovery.md) * [Lightning Loop](https://github.com/lightninglabs/loop) * [Lightning Pool](https://github.com/lightninglabs/pool) diff --git a/modules/backups.nix b/modules/backups.nix index 21e0b20..bf230c4 100644 --- a/modules/backups.nix +++ b/modules/backups.nix @@ -62,6 +62,7 @@ let ''} ${config.services.bitcoind.dataDir} ${config.services.clightning.dataDir} + ${config.services.clightning-rest.dataDir} ${config.services.lnd.dataDir} ${optionalString (!cfg.with-bulk-data) '' - ${config.services.liquidd.dataDir}/*/blocks diff --git a/modules/clightning-rest.nix b/modules/clightning-rest.nix new file mode 100644 index 0000000..c182a3b --- /dev/null +++ b/modules/clightning-rest.nix @@ -0,0 +1,104 @@ +{ config, lib, pkgs, ... }: + +with lib; +let + options.services.clightning-rest = { + enable = mkEnableOption "lightning-rest"; + port = mkOption { + type = types.port; + default = 3001; + description = "REST server port."; + }; + docPort = mkOption { + type = types.port; + default = 4001; + description = "Swagger API documentation server port."; + }; + dataDir = mkOption { + type = types.path; + default = "/var/lib/clightning-rest"; + description = "The data directory for clightning-rest."; + }; + extraConfig = mkOption { + type = types.attrs; + default = {}; + example = { + DOMAIN = "mynode.org"; + }; + description = '' + Extra config options. + See: https://github.com/Ride-The-Lightning/c-lightning-REST#option-1-via-config-file-cl-rest-configjson + ''; + }; + # Used by ./rtl.nix + group = mkOption { + readOnly = true; + default = clightning.group; + description = "The group under which clightning-rest is run."; + }; + # Rest server address. + # Not configurable. The server always listens on all interfaces: + # https://github.com/Ride-The-Lightning/c-lightning-REST/issues/84 + # Required by netns-isolation. + address = mkOption { + internal = true; + default = "0.0.0.0"; + }; + tor.enforce = nbLib.tor.enforce; + }; + + cfg = config.services.clightning-rest; + nbLib = config.nix-bitcoin.lib; + nbPkgs = config.nix-bitcoin.pkgs; + + inherit (config.services) + bitcoind + clightning; + + configFile = builtins.toFile "clightning-rest-config" (builtins.toJSON ({ + PORT = cfg.port; + DOCPORT = cfg.docPort; + LNRPCPATH = "${clightning.dataDir}/${bitcoind.makeNetworkName "bitcoin" "regtest"}/lightning-rpc"; + EXECMODE = "production"; + PROTOCOL = "https"; + RPCCOMMANDS = ["*"]; + } // cfg.extraConfig)); +in { + inherit options; + + config = mkIf cfg.enable { + services.clightning.enable = true; + + systemd.tmpfiles.rules = [ + "d '${cfg.dataDir}' 0770 ${clightning.user} ${cfg.group} - -" + ]; + + systemd.services.clightning-rest = mkIf cfg.enable { + wantedBy = [ "multi-user.target" ]; + requires = [ "clightning.service" ]; + after = [ "clightning.service" ]; + path = [ pkgs.openssl ]; + environment.CL_REST_STATE_DIR = cfg.dataDir; + preStart = '' + ln -sfn ${configFile} cl-rest-config.json + ''; + postStart = '' + while [[ ! -e '${cfg.dataDir}/certs/access.macaroon' ]]; do + sleep 0.1 + done + ''; + serviceConfig = nbLib.defaultHardening // { + # clightning-rest reads the config file from the working directory + WorkingDirectory = cfg.dataDir; + ExecStart = "${nbPkgs.clightning-rest}/bin/cl-rest"; + # Show "clightning-rest" instead of "node" in the journal + SyslogIdentifier = "clightning-rest"; + User = clightning.user; + Restart = "on-failure"; + RestartSec = "10s"; + ReadWritePaths = cfg.dataDir; + } // nbLib.allowedIPAddresses cfg.tor.enforce + // nbLib.nodejs; + }; + }; +} diff --git a/modules/modules.nix b/modules/modules.nix index a0512f6..0c5fe77 100644 --- a/modules/modules.nix +++ b/modules/modules.nix @@ -12,6 +12,7 @@ ./bitcoind.nix ./clightning.nix ./clightning-plugins + ./clightning-rest.nix ./spark-wallet.nix ./lnd.nix ./lnd-rest-onion-service.nix # Requires onion-addresses.nix diff --git a/modules/netns-isolation.nix b/modules/netns-isolation.nix index 47a837c..8159481 100644 --- a/modules/netns-isolation.nix +++ b/modules/netns-isolation.nix @@ -283,9 +283,13 @@ in { }; rtl = { id = 29; - connections = [] - ++ optional (config.services.rtl.nodes.lnd) "lnd" - ++ optional config.services.rtl.loop "lightning-loop"; + connections = + optional config.services.rtl.nodes.lnd "lnd" ++ + optional config.services.rtl.loop "lightning-loop" ++ + optional config.services.rtl.nodes.clightning "clightning-rest"; + }; + clightning-rest = { + id = 30; }; }; @@ -341,11 +345,8 @@ in { services.lightning-pool.rpcAddress = netns.lightning-pool.address; services.rtl.address = netns.rtl.address; - 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" ]; - }; + + services.clightning-rest.address = netns.clightning-rest.address; } ]); } diff --git a/modules/nodeinfo.nix b/modules/nodeinfo.nix index 1c3d544..b6ed813 100644 --- a/modules/nodeinfo.nix +++ b/modules/nodeinfo.nix @@ -27,6 +27,7 @@ let lnd = mkInfo '' info["nodeid"] = shell("lncli getinfo | jq -r '.identity_pubkey'") ''; + clightning-rest = mkInfo ""; electrs = mkInfo ""; spark-wallet = mkInfo ""; btcpayserver = mkInfo ""; diff --git a/modules/obsolete-options.nix b/modules/obsolete-options.nix index fc79164..c503c1c 100644 --- a/modules/obsolete-options.nix +++ b/modules/obsolete-options.nix @@ -1,4 +1,4 @@ -{ lib, ... }: +{ lib, config, ... }: with lib; let @@ -31,6 +31,8 @@ in { (mkRenamedOptionModule [ "services" "btcpayserver" "bind" ] [ "services" "btcpayserver" "address" ]) (mkRenamedOptionModule [ "services" "liquidd" "bind" ] [ "services" "liquidd" "address" ]) (mkRenamedOptionModule [ "services" "liquidd" "rpcbind" ] [ "services" "liquidd" "rpc" "address" ]) + # 0.0.70 + (mkRenamedOptionModule [ "services" "rtl" "cl-rest" ] [ "services" "clightning-rest" ]) (mkRenamedOptionModule [ "nix-bitcoin" "setup-secrets" ] [ "nix-bitcoin" "setupSecrets" ]) @@ -59,4 +61,22 @@ in { "rtl" "electrs" ]); + + config = { + # Migrate old clightning-rest datadir from nix-bitcoin versions < 0.0.70 + systemd.services.clightning-rest-migrate-datadir = let + inherit (config.services) clightning-rest clightning; + in mkIf config.services.clightning-rest.enable { + requiredBy = [ "clightning-rest.service" ]; + before = [ "clightning-rest.service" ]; + script = '' + if [[ -e /var/lib/cl-rest/certs ]]; then + mv /var/lib/cl-rest/* '${clightning-rest.dataDir}' + chown -R ${clightning.user}: '${clightning-rest.dataDir}' + rm -r /var/lib/cl-rest + fi + ''; + serviceConfig.Type = "oneshot"; + }; + }; } diff --git a/modules/presets/enable-tor.nix b/modules/presets/enable-tor.nix index a63634c..2a0ed02 100644 --- a/modules/presets/enable-tor.nix +++ b/modules/presets/enable-tor.nix @@ -38,6 +38,7 @@ in { rtl = defaultEnforceTor; joinmarket = defaultEnforceTor; joinmarket-ob-watcher = defaultEnforceTor; + clightning-rest = defaultEnforceTor; }; # Add onion services for incoming connections diff --git a/modules/rtl.nix b/modules/rtl.nix index 3257b8b..db5257a 100644 --- a/modules/rtl.nix +++ b/modules/rtl.nix @@ -70,36 +70,6 @@ let 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. This service is required for - clightning support and is automatically enabled. - ''; - }; - address = mkOption { - readOnly = true; - default = "0.0.0.0"; - description = '' - Rest server address. - Not configurable. The server always listens on all interfaces: - https://github.com/Ride-The-Lightning/c-lightning-REST/issues/84 - ''; - }; - port = mkOption { - type = types.port; - default = 3001; - description = "REST server port."; - }; - docPort = mkOption { - type = types.port; - default = 4001; - description = "Swagger API documentation server port."; - }; - }; tor.enforce = nbLib.tor.enforce; }; @@ -119,7 +89,7 @@ let } "macaroonPath": "${if isLnd then "${cfg.dataDir}/macaroons" - else "${cl-rest.dataDir}/certs" + else "${clightning-rest.dataDir}/certs" }" }, "Settings": { @@ -140,7 +110,7 @@ let "lnServerUrl": "https://${ if isLnd then nbLib.addressWithPort lnd.restAddress lnd.restPort - else nbLib.addressWithPort cfg.cl-rest.address cfg.cl-rest.port + else nbLib.addressWithPort clightning-rest.address clightning-rest.port }" } } @@ -165,25 +135,10 @@ let } ''; - cl-rest = { - configFile = builtins.toFile "config" '' - { - "PORT": ${toString cfg.cl-rest.port}, - "DOCPORT": ${toString cfg.cl-rest.docPort}, - "LNRPCPATH": "${clightning.dataDir}/${bitcoind.makeNetworkName "bitcoin" "regtest"}/lightning-rpc", - "PROTOCOL": "https", - "EXECMODE": "production", - "RPCCOMMANDS": ["*"] - } - ''; - # serviceConfig.StateDirectory - dataDir = "/var/lib/cl-rest"; - }; - inherit (config.services) bitcoind lnd - clightning + clightning-rest lightning-loop; in { inherit options; @@ -199,7 +154,7 @@ in { services.lnd.enable = mkIf cfg.nodes.lnd true; services.lightning-loop.enable = mkIf cfg.loop true; - services.clightning.enable = mkIf cfg.nodes.clightning true; + services.clightning-rest.enable = mkIf cfg.nodes.clightning true; systemd.tmpfiles.rules = [ "d '${cfg.dataDir}' 0770 ${cfg.user} ${cfg.group} - -" @@ -209,7 +164,7 @@ in { systemd.services.rtl = rec { wantedBy = [ "multi-user.target" ]; - requires = optional cfg.nodes.clightning "cl-rest.service" ++ + requires = optional cfg.nodes.clightning "clightning-rest.service" ++ optional cfg.nodes.lnd "lnd.service"; after = requires; environment.RTL_CONFIG_PATH = cfg.dataDir; @@ -235,35 +190,12 @@ in { // nbLib.nodejs; }; - systemd.services.cl-rest = mkIf cfg.cl-rest.enable { - wantedBy = [ "multi-user.target" ]; - requires = [ "clightning.service" ]; - after = [ "clightning.service" ]; - path = [ pkgs.openssl ]; - preStart = '' - ln -sfn ${cl-rest.configFile} cl-rest-config.json - ''; - environment.CL_REST_STATE_DIR = cl-rest.dataDir; - serviceConfig = nbLib.defaultHardening // { - StateDirectory = "cl-rest"; - # cl-rest reads the config file from the working directory - WorkingDirectory = cl-rest.dataDir; - ExecStart = "${nbPkgs.clightning-rest}/bin/cl-rest"; - # Show "cl-rest" instead of "node" in the journal - SyslogIdentifier = "cl-rest"; - User = cfg.user; - Restart = "on-failure"; - RestartSec = "10s"; - } // nbLib.allowLocalIPAddresses - // nbLib.nodejs; - }; - users.users.${cfg.user} = { isSystemUser = true; group = cfg.group; extraGroups = - # Enable clightning RPC access for cl-rest - optional cfg.cl-rest.enable clightning.group ++ + # Reads cert and macaroon from the clightning-rest datadir + optional cfg.nodes.clightning clightning-rest.group ++ optional cfg.loop lnd.group; }; users.groups.${cfg.group} = {}; diff --git a/modules/versioning.nix b/modules/versioning.nix index aa9693f..3aab682 100644 --- a/modules/versioning.nix +++ b/modules/versioning.nix @@ -213,6 +213,17 @@ let See also: https://github.com/dgarage/NBXplorer/blob/master/docs/Postgres-Migration.md ''; } + { + version = "0.0.70"; + condition = config.services.clightning-rest.enable; + message = '' + The `cl-rest` service has been renamed to `clightning-rest`. + and is now available as a standalone service (`services.clightning-rest`). + Its data dir has moved to `${config.services.clightning-rest.dataDir}`, + and the service now runs under the clightning user and group. + The data dir migration happens automatically after deploying. + ''; + } ]; mkOnionServiceChange = service: { diff --git a/test/tests.nix b/test/tests.nix index 190616f..0297160 100644 --- a/test/tests.nix +++ b/test/tests.nix @@ -59,6 +59,8 @@ let systemd.services.clightning.serviceConfig.TimeoutStopSec = mkIf config.services.clightning.plugins.clboss.enable "500ms"; + tests.clightning-rest = cfg.clightning-rest.enable; + tests.rtl = cfg.rtl.enable; services.rtl.nodes.lnd = mkDefault true; services.rtl.nodes.clightning = mkDefault true; @@ -163,6 +165,7 @@ let test.features.clightningPlugins = true; services.rtl.enable = true; services.spark-wallet.enable = true; + services.clightning-rest.enable = true; services.lnd.enable = true; services.lnd.restOnionService.enable = true; services.lightning-loop.enable = true; @@ -206,6 +209,7 @@ let imports = [ scenarios.regtestBase ]; services.clightning.enable = true; test.features.clightningPlugins = true; + services.clightning-rest.enable = true; services.liquidd.enable = true; services.rtl.enable = true; services.spark-wallet.enable = true; diff --git a/test/tests.py b/test/tests.py index a90bf03..68fbc34 100644 --- a/test/tests.py +++ b/test/tests.py @@ -211,9 +211,12 @@ def _(): machine.wait_until_succeeds( log_has_string("rtl", "Server is up and running") ) - assert_running("cl-rest") + +@test("clightning-rest") +def _(): + assert_running("clightning-rest") machine.wait_until_succeeds( - log_has_string("cl-rest", "cl-rest api server is ready and listening on port: 3001") + log_has_string("clightning-rest", "cl-rest api server is ready and listening on port: 3001") ) @test("spark-wallet") From e2fee4bf1af66b70ab4a3d279b5eb0a2f7e6a85f Mon Sep 17 00:00:00 2001 From: Erik Arvstedt Date: Thu, 5 May 2022 21:56:17 +0200 Subject: [PATCH 3/5] lnd-rest-onion-service.nix: move to lndconnect-onion.nix, add clightning support Option `services.lnd.restOnionService.package` has been removed. There's not much use in overriding the [lndconnect pkg](https://github.com/LN-Zap/lndconnect). --- README.md | 2 +- examples/configuration.nix | 19 ++++- modules/lnd-rest-onion-service.nix | 54 ------------- modules/lndconnect-onion.nix | 124 +++++++++++++++++++++++++++++ modules/modules.nix | 2 +- modules/obsolete-options.nix | 1 + modules/versioning.nix | 7 ++ test/tests.nix | 6 +- test/tests.py | 10 ++- 9 files changed, 161 insertions(+), 64 deletions(-) delete mode 100644 modules/lnd-rest-onion-service.nix create mode 100644 modules/lndconnect-onion.nix diff --git a/README.md b/README.md index 6808fb4..bcbc6c6 100644 --- a/README.md +++ b/README.md @@ -78,7 +78,7 @@ NixOS modules ([src](modules/modules.nix)) * [Lightning Loop](https://github.com/lightninglabs/loop) * [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 + * [lndconnect](https://github.com/LN-Zap/lndconnect): connect your wallet to lnd or clightning 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) diff --git a/examples/configuration.nix b/examples/configuration.nix index 93b9f14..bc1c990 100644 --- a/examples/configuration.nix +++ b/examples/configuration.nix @@ -53,6 +53,17 @@ # == Plugins # See ../README.md (Features → clightning) for the list of available plugins. # services.clightning.plugins.prometheus.enable = true; + # + # == REST server + # Set this to create a clightning REST onion service. + # This also adds binary `lndconnect-onion-clightning` to the system environment. + # This binary creates QR codes or URLs for connecting applications to clightning + # via the REST onion service (see ../docs/services.md). + # + # services.clightning-rest = { + # enable = true; + # lndconnectOnion.enable = true; + # }; ### LND # Set this to enable lnd, a lightning implementation written in Go. @@ -68,10 +79,10 @@ # nix-bitcoin.onionServices.lnd.public = true; # # Set this to create an lnd REST onion service. - # Adds binary `lndconnect-rest-onion` to the system environment. - # This binary generates QR codes or URIs for connecting applications to lnd via the - # REST onion service. - # services.lnd.restOnionService.enable = true; + # This also adds binary `lndconnect-onion` to the system environment. + # This binary generates QR codes or URLs for connecting applications to lnd via the + # REST onion service (see ../docs/services.md). + # services.lnd.lndconnectOnion.enable = true; # ## WARNING # If you use lnd, you should manually backup your wallet mnemonic diff --git a/modules/lnd-rest-onion-service.nix b/modules/lnd-rest-onion-service.nix deleted file mode 100644 index f2c94d5..0000000 --- a/modules/lnd-rest-onion-service.nix +++ /dev/null @@ -1,54 +0,0 @@ -{ config, lib, pkgs, ... }: - -with lib; -let - options.services.lnd.restOnionService = { - enable = mkOption { - default = false; - type = types.bool; - description = '' - Create an onion service for the lnd REST service. - Add a `lndconnect-rest-onion` binary (https://github.com/LN-Zap/lndconnect) to the system environment. - This binary generates QR codes or URIs for connecting applications to lnd via the REST onion service. - ''; - }; - package = mkOption { - type = types.package; - default = config.nix-bitcoin.pkgs.lndconnect; - defaultText = "config.nix-bitcoin.pkgs.lndconnect"; - description = "The package providing lndconnect binaries."; - }; - }; - - cfg = config.services.lnd.restOnionService; - nbLib = config.nix-bitcoin.lib; - runAsUser = config.nix-bitcoin.runAsUserCmd; - - lnd = config.services.lnd; - - bin = pkgs.writeScriptBin "lndconnect-rest-onion" '' - #!/usr/bin/env -S ${runAsUser} ${lnd.user} ${pkgs.bash}/bin/bash - - exec ${cfg.package}/bin/lndconnect \ - --host=$(cat ${config.nix-bitcoin.onionAddresses.dataDir}/lnd/lnd-rest) \ - --port=${toString lnd.restPort} \ - --lnddir=${lnd.dataDir} \ - --tlscertpath=${lnd.certPath} "$@" - ''; -in { - inherit options; - - config = mkIf cfg.enable { - services.tor = { - enable = true; - relay.onionServices.lnd-rest = nbLib.mkOnionService { - target.addr = nbLib.address lnd.restAddress; - target.port = lnd.restPort; - port = lnd.restPort; - }; - }; - nix-bitcoin.onionAddresses.access.lnd = [ "lnd-rest" ]; - - environment.systemPackages = [ bin ]; - }; -} diff --git a/modules/lndconnect-onion.nix b/modules/lndconnect-onion.nix new file mode 100644 index 0000000..740d4b2 --- /dev/null +++ b/modules/lndconnect-onion.nix @@ -0,0 +1,124 @@ +{ config, lib, pkgs, ... }: + +with lib; +let + options = { + services.lnd.lndconnectOnion.enable = mkOption { + type = types.bool; + default = false; + description = '' + Create an onion service for the lnd REST server. + Add a `lndconnect-onion` binary to the system environment. + See: https://github.com/LN-Zap/lndconnect + + Usage: + ``` + # Print QR code + lndconnect-onion + + # Print URL + lndconnect-onion --url + ``` + ''; + }; + + services.clightning-rest.lndconnectOnion.enable = mkOption { + type = types.bool; + default = false; + description = '' + Create an onion service for clightning-rest. + Add a `lndconnect-onion-clightning` binary to the system environment. + See: https://github.com/LN-Zap/lndconnect + + Usage: + ``` + # Print QR code + lndconnect-onion-clightning + + # Print URL + lndconnect-onion-clightning --url + ``` + ''; + }; + }; + + nbLib = config.nix-bitcoin.lib; + runAsUser = config.nix-bitcoin.runAsUserCmd; + + inherit (config.services) + lnd + clightning + clightning-rest; + + mkLndconnect = { + name, + shebang ? "#!${pkgs.stdenv.shell} -e", + onionService, + port, + certPath, + macaroonPath + }: + # TODO-EXTERNAL: + # lndconnect requires a --configfile argument, although it's unused + # https://github.com/LN-Zap/lndconnect/issues/25 + pkgs.writeScriptBin name '' + ${shebang} + exec ${config.nix-bitcoin.pkgs.lndconnect}/bin/lndconnect \ + --host=$(cat ${config.nix-bitcoin.onionAddresses.dataDir}/${onionService}) \ + --port=${toString port} \ + --tlscertpath='${certPath}' \ + --adminmacaroonpath='${macaroonPath}' \ + --configfile=/dev/null "$@" + ''; +in { + inherit options; + + config = mkMerge [ + (mkIf (lnd.enable && lnd.lndconnectOnion.enable) { + services.tor = { + enable = true; + relay.onionServices.lnd-rest = nbLib.mkOnionService { + target.addr = nbLib.address lnd.restAddress; + target.port = lnd.restPort; + port = lnd.restPort; + }; + }; + nix-bitcoin.onionAddresses.access.${lnd.user} = [ "lnd-rest" ]; + + environment.systemPackages = [( + mkLndconnect { + name = "lndconnect-onion"; + # Run as lnd user because the macaroon and cert are not group-readable + shebang = "#!/usr/bin/env -S ${runAsUser} ${lnd.user} ${pkgs.bash}/bin/bash"; + onionService = "${lnd.user}/lnd-rest"; + port = lnd.restPort; + certPath = lnd.certPath; + macaroonPath = "${lnd.networkDir}/admin.macaroon"; + } + )]; + }) + + (mkIf (clightning-rest.enable && clightning-rest.lndconnectOnion.enable) { + services.tor = { + enable = true; + relay.onionServices.clightning-rest = nbLib.mkOnionService { + target.addr = nbLib.address clightning-rest.address; + target.port = clightning-rest.port; + port = clightning-rest.port; + }; + }; + # This also allows nodeinfo to show the clightning-rest onion address + nix-bitcoin.onionAddresses.access.operator = [ "clightning-rest" ]; + + environment.systemPackages = [( + mkLndconnect { + name = "lndconnect-onion-clightning"; + onionService = "operator/clightning-rest"; + port = clightning-rest.port; + certPath = "${clightning-rest.dataDir}/certs/certificate.pem"; + macaroonPath = "${clightning-rest.dataDir}/certs/access.macaroon"; + } + )]; + }) + ]; +} diff --git a/modules/modules.nix b/modules/modules.nix index 0c5fe77..bf0dbab 100644 --- a/modules/modules.nix +++ b/modules/modules.nix @@ -15,10 +15,10 @@ ./clightning-rest.nix ./spark-wallet.nix ./lnd.nix - ./lnd-rest-onion-service.nix # Requires onion-addresses.nix ./lightning-loop.nix ./lightning-pool.nix ./charge-lnd.nix + ./lndconnect-onion.nix # Requires onion-addresses.nix ./rtl.nix ./electrs.nix ./liquid.nix diff --git a/modules/obsolete-options.nix b/modules/obsolete-options.nix index c503c1c..e07bf30 100644 --- a/modules/obsolete-options.nix +++ b/modules/obsolete-options.nix @@ -33,6 +33,7 @@ in { (mkRenamedOptionModule [ "services" "liquidd" "rpcbind" ] [ "services" "liquidd" "rpc" "address" ]) # 0.0.70 (mkRenamedOptionModule [ "services" "rtl" "cl-rest" ] [ "services" "clightning-rest" ]) + (mkRenamedOptionModule [ "services" "lnd" "restOnionService" "enable" ] [ "services" "lnd" "lndconnectOnion" "enable" ]) (mkRenamedOptionModule [ "nix-bitcoin" "setup-secrets" ] [ "nix-bitcoin" "setupSecrets" ]) diff --git a/modules/versioning.nix b/modules/versioning.nix index 3aab682..ad3bf7d 100644 --- a/modules/versioning.nix +++ b/modules/versioning.nix @@ -224,6 +224,13 @@ let The data dir migration happens automatically after deploying. ''; } + { + version = "0.0.70"; + condition = config.services.lnd.lndconnectOnion.enable; + message = '' + The `lndconnect-rest-onion` binary has been renamed to `lndconnect-onion`. + ''; + } ]; mkOnionServiceChange = service: { diff --git a/test/tests.nix b/test/tests.nix index 0297160..dceb56d 100644 --- a/test/tests.nix +++ b/test/tests.nix @@ -76,7 +76,8 @@ let tests.lnd = cfg.lnd.enable; services.lnd.port = 9736; - tests.lnd-rest-onion-service = cfg.lnd.restOnionService.enable; + tests.lndconnect-onion-lnd = cfg.lnd.lndconnectOnion.enable; + tests.lndconnect-onion-clightning = cfg.clightning-rest.lndconnectOnion.enable; tests.lightning-loop = cfg.lightning-loop.enable; @@ -166,8 +167,9 @@ let services.rtl.enable = true; services.spark-wallet.enable = true; services.clightning-rest.enable = true; + services.clightning-rest.lndconnectOnion.enable = true; services.lnd.enable = true; - services.lnd.restOnionService.enable = true; + services.lnd.lndconnectOnion.enable = true; services.lightning-loop.enable = true; services.lightning-pool.enable = true; services.charge-lnd.enable = true; diff --git a/test/tests.py b/test/tests.py index 68fbc34..3f56bb0 100644 --- a/test/tests.py +++ b/test/tests.py @@ -148,9 +148,15 @@ def _(): assert_matches("runuser -u operator -- lncli getinfo | jq", '"version"') assert_no_failure("lnd") -@test("lnd-rest-onion-service") +@test("lndconnect-onion-lnd") def _(): - assert_matches("runuser -u operator -- lndconnect-rest-onion -j", ".onion") + assert_running("lnd") + assert_matches("runuser -u operator -- lndconnect-onion --url", ".onion") + +@test("lndconnect-onion-clightning") +def _(): + assert_running("clightning-rest") + assert_matches("runuser -u operator -- lndconnect-onion-clightning --url", ".onion") @test("lightning-loop") def _(): From 20c0194ade3910a65cb0087bfff89eb0684421d6 Mon Sep 17 00:00:00 2001 From: Erik Arvstedt Date: Thu, 5 May 2022 21:56:18 +0200 Subject: [PATCH 4/5] readme: add hint about github table of contents button --- README.md | 3 +++ docs/img/github-table-of-contents.svg | 3 +++ 2 files changed, 6 insertions(+) create mode 100755 docs/img/github-table-of-contents.svg diff --git a/README.md b/README.md index bcbc6c6..78847df 100644 --- a/README.md +++ b/README.md @@ -49,6 +49,9 @@ Get started Docs --- +Hint: To show a table of contents, click the button (![Github TOC button](docs/img/github-table-of-contents.svg)) in the +top left corner of the documents. + * [Hardware requirements](docs/hardware.md) * [Installation](docs/install.md) * [Configuration and maintenance](docs/configuration.md) diff --git a/docs/img/github-table-of-contents.svg b/docs/img/github-table-of-contents.svg new file mode 100755 index 0000000..617e385 --- /dev/null +++ b/docs/img/github-table-of-contents.svg @@ -0,0 +1,3 @@ + + + From 8e1ad6e3a85a8b534b0a03fd7760cf62cde0f205 Mon Sep 17 00:00:00 2001 From: Erik Arvstedt Date: Thu, 5 May 2022 21:56:19 +0200 Subject: [PATCH 5/5] docs/services: update Zeus usage section, add clightning The current Zeus version has native tor support, so Orbot is no longer required. --- docs/services.md | 91 +++++++++++++++++++++++++++++------------------- 1 file changed, 55 insertions(+), 36 deletions(-) diff --git a/docs/services.md b/docs/services.md index 28935d6..c2ceda6 100644 --- a/docs/services.md +++ b/docs/services.md @@ -44,6 +44,61 @@ You can find the `` with command `nodeinfo`. The default password location is `$secretsDir/rtl-password`. See: [Secrets dir](./configuration.md#secrets-dir) +# Use LND or clightning with Zeus (smartphone wallet) via Tor +1. Install [Zeus](https://zeusln.app) + +2. Edit your `configuration.nix` + + ##### For lnd + + Add the following config: + ``` + services.lnd.lndconnectOnion.enable = true; + ``` + + ##### For clightning + + Add the following config: + ``` + services.clightning-rest = { + enable = true; + lndconnectOnion.enable = true; + }; + ``` + +3. Deploy your configuration + +3. Run the following command on your node (as user `operator`) to create a QR code + with address and authentication information: + + ##### For lnd + ``` + lndconnect-onion + ``` + + ##### For clightning + ``` + lndconnect-onion-clightning + ``` + +4. Configure Zeus + - Add a new node + - Select `Scan lndconnect config` (at the bottom) and scan the QR code + - For clightning: Set `Node interface` to `c-lightning-REST` + - Click `Save node config` + - Start sending sats privately + +### Additional lndconnect features +Create plain text URLs or QR code images: +``` +lndconnect-onion --url +lndconnect-onion --image +`````` +Create a QR code for a custom hostname: +``` +lndconnect-onion --host=mynode.org +``` + # Connect to spark-wallet ### Requirements * Android phone @@ -87,42 +142,6 @@ See: [Secrets dir](./configuration.md#secrets-dir) Done ``` -# Connect to LND with Zeus -### 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) -* [Zeus](https://zeusln.app/) installed from - [F-Droid](https://f-droid.org/en/packages/app.zeusln.zeus/) (recommended) or - [Google Play](https://play.google.com/store/apps/details?id=app.zeusln.zeus) - -1. Enable `restOnionService` in `configuration.nix` - - Change - ``` - # services.lnd.restOnionService.enable = true; - ``` - to - ``` - services.lnd.restOnionService.enable = true; - ``` - -2. Deploy new `configuration.nix` - -3. Run command `lndconnect-rest-onion` (under `operator` user) to create a QR code for - connecting to LND via the REST onion service. - -4. Enable Orbot VPN for Zeus - ``` - Open Orbot app - Turn on "VPN Mode" - Select Gear icon under "Tor-Enabled Apps" - Toggle checkbox under Zeus icon - ``` - -5. Scan the QR code with your Zeus wallet and start sending Satoshis privately - # Connect to electrs ### Requirements Android * Android phone