Merge fort-nix/nix-bitcoin#575: Improve lndconnect
, support WireGuard
cea69b73d2
nodeinfo: enable required option `nix-bitcoin.operator` (Erik Arvstedt)27d95fda85
nodeinfo/lnd: add `onion_rest_address` (Erik Arvstedt)54a21874ae
nodeinfo/lnd: add `rest_address` (Erik Arvstedt)a4bfefd562
add `presets/wireguard.nix` (Erik Arvstedt)477e1709fb
lndconnect: update to Zeus 0.7.1 (Erik Arvstedt)f996ef37d9
lnd, clightning-rest: remove `lndconnectOnion`, add generic option `lndconnect` (Erik Arvstedt)b4bc621b8c
rename `lndconnect-onion.nix` -> `lndconnect.nix` (Erik Arvstedt)907cfe4f4c
docs/services: improve title, fix numbering (Erik Arvstedt) Pull request description: ACKs for top commit: jonasnick: ACKcea69b73d2
Tree-SHA512: 747d95b49f5c1b63dfaa2c6bc302fb102e3788c36e279cc28266ea230e8daae54973d8bdb51f2a81e7e84eb86b6b1e504fbe8af85c2318525c54d901678b3f55
This commit is contained in:
commit
282c45b746
|
@ -85,7 +85,9 @@ NixOS modules ([src](modules/modules.nix))
|
||||||
* [Lightning Loop](https://github.com/lightninglabs/loop)
|
* [Lightning Loop](https://github.com/lightninglabs/loop)
|
||||||
* [Lightning Pool](https://github.com/lightninglabs/pool)
|
* [Lightning Pool](https://github.com/lightninglabs/pool)
|
||||||
* [charge-lnd](https://github.com/accumulator/charge-lnd): policy-based channel fee manager
|
* [charge-lnd](https://github.com/accumulator/charge-lnd): policy-based channel fee manager
|
||||||
* [lndconnect](https://github.com/LN-Zap/lndconnect): connect your wallet to lnd or clightning via a REST onion service
|
* [lndconnect](https://github.com/LN-Zap/lndconnect): connect your wallet to lnd or
|
||||||
|
clightning [via WireGuard](./docs/services.md#use-zeus-mobile-lightning-wallet-via-wireguard) or
|
||||||
|
[Tor](./docs/services.md#use-zeus-mobile-lightning-wallet-via-tor)
|
||||||
* [Ride The Lightning](https://github.com/Ride-The-Lightning/RTL): web interface for `lnd` and `clightning`
|
* [Ride The Lightning](https://github.com/Ride-The-Lightning/RTL): web interface for `lnd` and `clightning`
|
||||||
* [spark-wallet](https://github.com/shesek/spark-wallet)
|
* [spark-wallet](https://github.com/shesek/spark-wallet)
|
||||||
* [electrs](https://github.com/romanz/electrs): Electrum server
|
* [electrs](https://github.com/romanz/electrs): Electrum server
|
||||||
|
|
|
@ -45,4 +45,34 @@ with lib;
|
||||||
nix-bitcoin.nodeinfo.enable = true;
|
nix-bitcoin.nodeinfo.enable = true;
|
||||||
# test.container.enableWAN = true;
|
# test.container.enableWAN = true;
|
||||||
};
|
};
|
||||||
|
|
||||||
|
wireguard-lndconnect-online = { config, pkgs, lib, ... }: {
|
||||||
|
imports = [
|
||||||
|
../modules/presets/wireguard.nix
|
||||||
|
scenarios.regtestBase
|
||||||
|
];
|
||||||
|
|
||||||
|
# 51820 (default wg port) + 1
|
||||||
|
networking.wireguard.interfaces.wg-nb.listenPort = 51821;
|
||||||
|
test.container.enableWAN = true;
|
||||||
|
# test.container.exposeLocalhost = true;
|
||||||
|
|
||||||
|
services.clightning.extraConfig = "disable-dns";
|
||||||
|
|
||||||
|
services.lnd = {
|
||||||
|
enable = true;
|
||||||
|
lndconnect = {
|
||||||
|
enable = true;
|
||||||
|
onion = true;
|
||||||
|
};
|
||||||
|
};
|
||||||
|
services.clightning-rest = {
|
||||||
|
enable = true;
|
||||||
|
lndconnect = {
|
||||||
|
enable = true;
|
||||||
|
onion = true;
|
||||||
|
};
|
||||||
|
};
|
||||||
|
nix-bitcoin.nodeinfo.enable = true;
|
||||||
|
};
|
||||||
}
|
}
|
||||||
|
|
64
dev/topics/lndconnect-and-wireguard.sh
Normal file
64
dev/topics/lndconnect-and-wireguard.sh
Normal file
|
@ -0,0 +1,64 @@
|
||||||
|
#―――――――――――――――――――――――――――――――――――――――――――――――――――――――――――――――――――――――――――――――
|
||||||
|
# Test Tor and WireGuard connections on a mobile device
|
||||||
|
|
||||||
|
# 1. Run container
|
||||||
|
run-tests.sh -s wireguard-lndconnect-online container
|
||||||
|
|
||||||
|
# 2. Test connecting via Tor
|
||||||
|
# Print QR codes for lnd, clightning-rest connections via Tor
|
||||||
|
c lndconnect
|
||||||
|
c lndconnect-clightning
|
||||||
|
# Add these to Zeus >= 0.7.1.
|
||||||
|
# To explicitly check if the connection is successful, press the node logo in the top
|
||||||
|
# left corner, and then "Node Info".
|
||||||
|
|
||||||
|
# Debug
|
||||||
|
c lndconnect --url
|
||||||
|
c lndconnect-clightning --url
|
||||||
|
|
||||||
|
# 3. Test connecting via WireGuard
|
||||||
|
|
||||||
|
# 3.1 Forward WireGuard port from the container host to the container
|
||||||
|
iptables -t nat -A PREROUTING -p udp --dport 51821 -j DNAT --to-destination 10.225.255.2
|
||||||
|
|
||||||
|
# 3.2. Optional: When your container host has an external firewall,
|
||||||
|
# forward the WireGuard port to the container host:
|
||||||
|
# - Port: 51821
|
||||||
|
# - Protocol: UDP
|
||||||
|
# - Destination: IPv4 of the container host
|
||||||
|
|
||||||
|
# 3.2 Print QR code and setup wireguard on the mobile device
|
||||||
|
c nix-bitcoin-wg-connect
|
||||||
|
c nix-bitcoin-wg-connect --text
|
||||||
|
|
||||||
|
# Print QR codes for lnd, clightning-rest connections via WireGuard
|
||||||
|
c lndconnect-wg
|
||||||
|
c lndconnect-clightning-wg
|
||||||
|
# Add these to Zeus >= 0.7.1.
|
||||||
|
# To explicitly check if the connection is successful, press the node logo in the top
|
||||||
|
# left corner, and then "Node Info".
|
||||||
|
|
||||||
|
# Debug
|
||||||
|
c lndconnect-wg --url
|
||||||
|
c lndconnect-clightning-wg --url
|
||||||
|
|
||||||
|
# 3.3.remove external firewall port forward, remove local port forward:
|
||||||
|
iptables -t nat -D PREROUTING -p udp --dport 51821 -j DNAT --to-destination 10.225.255.2
|
||||||
|
# Now exit the container shell
|
||||||
|
|
||||||
|
#―――――――――――――――――――――――――――――――――――――――――――――――――――――――――――――――――――――――――――――――
|
||||||
|
# Debug lndconnect
|
||||||
|
|
||||||
|
run-tests.sh -s wireguard-lndconnect-online container
|
||||||
|
|
||||||
|
c nodeinfo
|
||||||
|
|
||||||
|
c lndconnect --url
|
||||||
|
c lndconnect-wg --url
|
||||||
|
c lndconnect-clightning --url
|
||||||
|
c lndconnect-clightning-wg --url
|
||||||
|
|
||||||
|
c lndconnect
|
||||||
|
c lndconnect-wg
|
||||||
|
c lndconnect-clightning
|
||||||
|
c lndconnect-clightning-wg
|
136
docs/services.md
136
docs/services.md
|
@ -142,60 +142,154 @@ You can find the `<onion-address>` with command `nodeinfo`.
|
||||||
The default password location is `$secretsDir/rtl-password`.
|
The default password location is `$secretsDir/rtl-password`.
|
||||||
See: [Secrets dir](./configuration.md#secrets-dir)
|
See: [Secrets dir](./configuration.md#secrets-dir)
|
||||||
|
|
||||||
# Use LND or clightning with Zeus (mobile wallet) via Tor
|
# Use Zeus (mobile lightning wallet) via Tor
|
||||||
1. Install [Zeus](https://zeusln.app)
|
1. Install [Zeus](https://zeusln.app) (version ≥ 0.7.1)
|
||||||
|
|
||||||
2. Edit your `configuration.nix`
|
2. Edit your `configuration.nix`
|
||||||
|
|
||||||
##### For lnd
|
##### For lnd
|
||||||
|
|
||||||
Add the following config:
|
Add the following config:
|
||||||
```
|
```nix
|
||||||
services.lnd.lndconnectOnion.enable = true;
|
services.lnd.lndconnect = {
|
||||||
|
enable = true;
|
||||||
|
onion = true;
|
||||||
|
};
|
||||||
```
|
```
|
||||||
|
|
||||||
##### For clightning
|
##### For clightning
|
||||||
|
|
||||||
Add the following config:
|
Add the following config:
|
||||||
```
|
```nix
|
||||||
services.clightning-rest = {
|
services.clightning-rest = {
|
||||||
enable = true;
|
enable = true;
|
||||||
lndconnectOnion.enable = true;
|
lndconnect = {
|
||||||
|
enable = true;
|
||||||
|
onion = true;
|
||||||
|
};
|
||||||
};
|
};
|
||||||
```
|
```
|
||||||
|
|
||||||
3. Deploy your configuration
|
3. Deploy your configuration
|
||||||
|
|
||||||
3. Run the following command on your node (as user `operator`) to create a QR code
|
4. Run the following command on your node (as user `operator`) to create a QR code
|
||||||
with address and authentication information:
|
with address and authentication information:
|
||||||
|
|
||||||
##### For lnd
|
##### For lnd
|
||||||
```
|
```
|
||||||
lndconnect-onion
|
lndconnect
|
||||||
```
|
```
|
||||||
|
|
||||||
##### For clightning
|
##### For clightning
|
||||||
```
|
```
|
||||||
lndconnect-onion-clightning
|
lndconnect-clightning
|
||||||
```
|
```
|
||||||
|
|
||||||
4. Configure Zeus
|
5. Configure Zeus
|
||||||
- Add a new node
|
- Add a new node and scan the QR code
|
||||||
- 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`
|
- Click `Save node config`
|
||||||
- Start sending and stacking sats privately
|
- Start sending and stacking sats privately
|
||||||
|
|
||||||
### Additional lndconnect features
|
### Additional lndconnect features
|
||||||
Create plain text URLs or QR code images:
|
- Create a plain text URL:
|
||||||
```
|
```bash
|
||||||
lndconnect-onion --url
|
lndconnect --url
|
||||||
lndconnect-onion --image
|
```
|
||||||
|
- Set a custom host. By default, `lndconnect` detects the system's external IP and uses it as the host.
|
||||||
|
```bash
|
||||||
|
lndconnect --host myhost
|
||||||
|
```
|
||||||
|
|
||||||
|
# Use Zeus (mobile lightning wallet) via WireGuard
|
||||||
|
|
||||||
|
Connecting Zeus directly to your node is much faster than using Tor, but a bit more complex to setup.
|
||||||
|
|
||||||
|
There are two ways to establish a secure, direct connection:
|
||||||
|
|
||||||
|
- Connecting via TLS. This requires installing your lightning app's
|
||||||
|
TLS Certificate on your mobile device.
|
||||||
|
|
||||||
|
- Connecting via WireGuard. This approach is simpler and more versatile, and is
|
||||||
|
described in this guide.
|
||||||
|
|
||||||
|
1. Install [Zeus](https://zeusln.app) (version ≥ 0.7.1) and
|
||||||
|
[WireGuard](https://www.wireguard.com/install/) on your mobile device.
|
||||||
|
|
||||||
|
2. Add the following to your `configuration.nix`:
|
||||||
|
```nix
|
||||||
|
imports = [
|
||||||
|
# Use this line when using the default deployment method
|
||||||
|
<nix-bitcoin/modules/presets/wireguard.nix>
|
||||||
|
|
||||||
|
# Use this line when using Flakes
|
||||||
|
(nix-bitcoin + /modules/presets/wireguard.nix)
|
||||||
|
]
|
||||||
|
|
||||||
|
# For lnd
|
||||||
|
services.lnd.lndconnect.enable = true;
|
||||||
|
|
||||||
|
# For clightning
|
||||||
|
services.clightning-rest = {
|
||||||
|
enable = true;
|
||||||
|
lndconnect.enable = true;
|
||||||
|
};
|
||||||
|
```
|
||||||
|
3. Deploy your configuration.
|
||||||
|
|
||||||
|
4. If your node is behind an external firewall or NAT, add the following port forwarding
|
||||||
|
rule to the external device:
|
||||||
|
- Port: 51820 (the default value of option `networking.wireguard.interfaces.wg-nb.listenPort`)
|
||||||
|
- Protocol: UDP
|
||||||
|
- Destination: IP of your node
|
||||||
|
|
||||||
|
5. Setup WireGuard on your mobile device.
|
||||||
|
|
||||||
|
Run the following command on your node (as user `operator`) to create a QR code
|
||||||
|
for WireGuard:
|
||||||
|
```bash
|
||||||
|
nix-bitcoin-wg-connect
|
||||||
|
|
||||||
|
# For debugging: Show the WireGuard config as text
|
||||||
|
nix-bitcoin-wg-connect --text
|
||||||
|
```
|
||||||
|
The above commands automatically detect your node's external IP.\
|
||||||
|
To set a custom IP or hostname, run the following:
|
||||||
|
```
|
||||||
|
nix-bitcoin-wg-connect 93.184.216.34
|
||||||
|
nix-bitcoin-wg-connect mynode.org
|
||||||
|
```
|
||||||
|
|
||||||
|
Configure WireGuard:
|
||||||
|
- Press the `+` button in the bottom right corner
|
||||||
|
- Scan the QR code
|
||||||
|
- Add the tunnel
|
||||||
|
|
||||||
|
6. Setup Zeus
|
||||||
|
|
||||||
|
Run the following command on your node (as user `operator`) to create a QR code for Zeus:
|
||||||
|
|
||||||
|
##### For lnd
|
||||||
|
```
|
||||||
|
lndconnect-wg
|
||||||
|
```
|
||||||
|
|
||||||
|
##### For clightning
|
||||||
|
```
|
||||||
|
lndconnect-clightning-wg
|
||||||
|
```
|
||||||
|
|
||||||
|
Configure Zeus:
|
||||||
|
- Add a new node and scan the QR code
|
||||||
|
- Click `Save node config`
|
||||||
|
- On the certificate warning screen, click `I understand, save node config`.\
|
||||||
|
Certificates are not needed when connecting via WireGuard.
|
||||||
|
- Start sending and stacking sats privately
|
||||||
|
|
||||||
|
### Additional lndconnect features
|
||||||
|
Create a plain text URL:
|
||||||
|
```bash
|
||||||
|
lndconnect-wg --url
|
||||||
``````
|
``````
|
||||||
Create a QR code for a custom hostname:
|
|
||||||
```
|
|
||||||
lndconnect-onion --host=mynode.org
|
|
||||||
```
|
|
||||||
|
|
||||||
# Connect to spark-wallet
|
# Connect to spark-wallet
|
||||||
### Requirements
|
### Requirements
|
||||||
|
|
|
@ -56,13 +56,18 @@
|
||||||
#
|
#
|
||||||
# == REST server
|
# == REST server
|
||||||
# Set this to create a clightning REST onion service.
|
# Set this to create a clightning REST onion service.
|
||||||
# This also adds binary `lndconnect-onion-clightning` to the system environment.
|
# This also adds binary `lndconnect-clightning` to the system environment.
|
||||||
# This binary creates QR codes or URLs for connecting applications to clightning
|
# This binary creates QR codes or URLs for connecting applications to clightning
|
||||||
# via the REST onion service (see ../docs/services.md).
|
# via the REST onion service.
|
||||||
|
# You can also connect via WireGuard instead of Tor.
|
||||||
|
# See ../docs/services.md for details.
|
||||||
#
|
#
|
||||||
# services.clightning-rest = {
|
# services.clightning-rest = {
|
||||||
# enable = true;
|
# enable = true;
|
||||||
# lndconnectOnion.enable = true;
|
# lndconnect = {
|
||||||
|
# enable = true;
|
||||||
|
# onion = true;
|
||||||
|
# };
|
||||||
# };
|
# };
|
||||||
|
|
||||||
### LND
|
### LND
|
||||||
|
@ -78,11 +83,17 @@
|
||||||
# The onion service is automatically announced to peers.
|
# The onion service is automatically announced to peers.
|
||||||
# nix-bitcoin.onionServices.lnd.public = true;
|
# nix-bitcoin.onionServices.lnd.public = true;
|
||||||
#
|
#
|
||||||
# Set this to create an lnd REST onion service.
|
# Set this to create a lnd REST onion service.
|
||||||
# This also adds binary `lndconnect-onion` to the system environment.
|
# This also adds binary `lndconnect` to the system environment.
|
||||||
# This binary generates QR codes or URLs for connecting applications to lnd via the
|
# This binary generates QR codes or URLs for connecting applications to lnd via the
|
||||||
# REST onion service (see ../docs/services.md).
|
# REST onion service.
|
||||||
# services.lnd.lndconnectOnion.enable = true;
|
# You can also connect via WireGuard instead of Tor.
|
||||||
|
# See ../docs/services.md for details.
|
||||||
|
#
|
||||||
|
# services.lnd.lndconnect = {
|
||||||
|
# enable = true;
|
||||||
|
# onion = true;
|
||||||
|
# };
|
||||||
#
|
#
|
||||||
## WARNING
|
## WARNING
|
||||||
# If you use lnd, you should manually backup your wallet mnemonic
|
# If you use lnd, you should manually backup your wallet mnemonic
|
||||||
|
|
|
@ -1,126 +0,0 @@
|
||||||
{ config, lib, pkgs, ... }:
|
|
||||||
|
|
||||||
with lib;
|
|
||||||
let
|
|
||||||
options = {
|
|
||||||
services.lnd.lndconnectOnion.enable = mkOption {
|
|
||||||
type = types.bool;
|
|
||||||
default = false;
|
|
||||||
description = mdDoc ''
|
|
||||||
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:
|
|
||||||
```bash
|
|
||||||
# Print QR code
|
|
||||||
lndconnect-onion
|
|
||||||
|
|
||||||
# Print URL
|
|
||||||
lndconnect-onion --url
|
|
||||||
```
|
|
||||||
'';
|
|
||||||
};
|
|
||||||
|
|
||||||
services.clightning-rest.lndconnectOnion.enable = mkOption {
|
|
||||||
type = types.bool;
|
|
||||||
default = false;
|
|
||||||
description = mdDoc ''
|
|
||||||
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:
|
|
||||||
```bash
|
|
||||||
# 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 "$@"
|
|
||||||
'';
|
|
||||||
|
|
||||||
operatorName = config.nix-bitcoin.operator.name;
|
|
||||||
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.${operatorName} = [ "clightning-rest" ];
|
|
||||||
|
|
||||||
environment.systemPackages = [(
|
|
||||||
mkLndconnect {
|
|
||||||
name = "lndconnect-onion-clightning";
|
|
||||||
onionService = "${operatorName}/clightning-rest";
|
|
||||||
port = clightning-rest.port;
|
|
||||||
certPath = "${clightning-rest.dataDir}/certs/certificate.pem";
|
|
||||||
macaroonPath = "${clightning-rest.dataDir}/certs/access.macaroon";
|
|
||||||
}
|
|
||||||
)];
|
|
||||||
})
|
|
||||||
];
|
|
||||||
}
|
|
205
modules/lndconnect.nix
Normal file
205
modules/lndconnect.nix
Normal file
|
@ -0,0 +1,205 @@
|
||||||
|
{ config, lib, pkgs, ... }:
|
||||||
|
|
||||||
|
with lib;
|
||||||
|
let
|
||||||
|
options = {
|
||||||
|
services.lnd.lndconnect = {
|
||||||
|
enable = mkOption {
|
||||||
|
type = types.bool;
|
||||||
|
default = false;
|
||||||
|
description = mdDoc ''
|
||||||
|
Add a `lndconnect` binary to the system environment which prints
|
||||||
|
connection info for lnd clients.
|
||||||
|
See: https://github.com/LN-Zap/lndconnect
|
||||||
|
|
||||||
|
Usage:
|
||||||
|
```bash
|
||||||
|
# Print QR code
|
||||||
|
lndconnect
|
||||||
|
|
||||||
|
# Print URL
|
||||||
|
lndconnect --url
|
||||||
|
```
|
||||||
|
'';
|
||||||
|
};
|
||||||
|
onion = mkOption {
|
||||||
|
type = types.bool;
|
||||||
|
default = false;
|
||||||
|
description = mdDoc ''
|
||||||
|
Create an onion service for the lnd REST server,
|
||||||
|
which is used by lndconnect.
|
||||||
|
'';
|
||||||
|
};
|
||||||
|
};
|
||||||
|
|
||||||
|
|
||||||
|
services.clightning-rest.lndconnect = {
|
||||||
|
enable = mkOption {
|
||||||
|
type = types.bool;
|
||||||
|
default = false;
|
||||||
|
description = mdDoc ''
|
||||||
|
Add a `lndconnect-clightning` binary to the system environment which prints
|
||||||
|
connection info for clightning clients.
|
||||||
|
See: https://github.com/LN-Zap/lndconnect
|
||||||
|
|
||||||
|
Usage:
|
||||||
|
```bash
|
||||||
|
# Print QR code
|
||||||
|
lndconnect-clightning
|
||||||
|
|
||||||
|
# Print URL
|
||||||
|
lndconnect-clightning --url
|
||||||
|
```
|
||||||
|
'';
|
||||||
|
};
|
||||||
|
onion = mkOption {
|
||||||
|
type = types.bool;
|
||||||
|
default = false;
|
||||||
|
description = mdDoc ''
|
||||||
|
Create an onion service for the clightning REST server,
|
||||||
|
which is used by lndconnect.
|
||||||
|
'';
|
||||||
|
};
|
||||||
|
};
|
||||||
|
|
||||||
|
nix-bitcoin.mkLndconnect = mkOption {
|
||||||
|
readOnly = true;
|
||||||
|
default = mkLndconnect;
|
||||||
|
description = mdDoc ''
|
||||||
|
A function to create a lndconnect binary.
|
||||||
|
See the source for further details.
|
||||||
|
'';
|
||||||
|
};
|
||||||
|
};
|
||||||
|
|
||||||
|
nbLib = config.nix-bitcoin.lib;
|
||||||
|
runAsUser = config.nix-bitcoin.runAsUserCmd;
|
||||||
|
|
||||||
|
inherit (config.services)
|
||||||
|
lnd
|
||||||
|
clightning-rest;
|
||||||
|
|
||||||
|
mkLndconnect = {
|
||||||
|
name,
|
||||||
|
shebang ? "#!${pkgs.stdenv.shell} -e",
|
||||||
|
isClightning ? false,
|
||||||
|
port,
|
||||||
|
macaroonPath,
|
||||||
|
enableOnion,
|
||||||
|
onionService ? null,
|
||||||
|
certPath ? null
|
||||||
|
}:
|
||||||
|
# TODO-EXTERNAL:
|
||||||
|
# lndconnect requires a --configfile argument, although it's unused
|
||||||
|
# https://github.com/LN-Zap/lndconnect/issues/25
|
||||||
|
pkgs.hiPrio (pkgs.writeScriptBin name ''
|
||||||
|
${shebang}
|
||||||
|
url=$(
|
||||||
|
${getExe config.nix-bitcoin.pkgs.lndconnect} --url \
|
||||||
|
${optionalString enableOnion "--host=$(cat ${config.nix-bitcoin.onionAddresses.dataDir}/${onionService})"} \
|
||||||
|
--port=${toString port} \
|
||||||
|
${if enableOnion || certPath == null then "--nocert" else "--tlscertpath='${certPath}'"} \
|
||||||
|
--adminmacaroonpath='${macaroonPath}' \
|
||||||
|
--configfile=/dev/null "$@"
|
||||||
|
)
|
||||||
|
|
||||||
|
${optionalString isClightning
|
||||||
|
# - Change URL procotcol to c-lightning-rest
|
||||||
|
# - Encode macaroon as hex (in uppercase) instead of base 64.
|
||||||
|
# Because `macaroon` is always the last URL fragment, the
|
||||||
|
# sed replacement below works correctly.
|
||||||
|
''
|
||||||
|
macaroonHex=$(${getExe pkgs.xxd} -p -u -c 99999 '${macaroonPath}')
|
||||||
|
url=$(
|
||||||
|
echo "$url" | ${getExe pkgs.gnused} "
|
||||||
|
s|^lndconnect|c-lightning-rest|
|
||||||
|
s|macaroon=.*|macaroon=$macaroonHex|
|
||||||
|
";
|
||||||
|
)
|
||||||
|
''
|
||||||
|
}
|
||||||
|
|
||||||
|
# If --url is in args
|
||||||
|
if [[ " $* " =~ " --url " ]]; then
|
||||||
|
echo "$url"
|
||||||
|
else
|
||||||
|
# This UTF-8 encoding yields a smaller, more convenient output format
|
||||||
|
# compared to the native lndconnect output
|
||||||
|
echo -n "$url" | ${getExe pkgs.qrencode} -t UTF8 -o -
|
||||||
|
fi
|
||||||
|
'');
|
||||||
|
|
||||||
|
operatorName = config.nix-bitcoin.operator.name;
|
||||||
|
in {
|
||||||
|
inherit options;
|
||||||
|
|
||||||
|
config = mkMerge [
|
||||||
|
(mkIf (lnd.enable && lnd.lndconnect.enable)
|
||||||
|
(mkMerge [
|
||||||
|
{
|
||||||
|
environment.systemPackages = [(
|
||||||
|
mkLndconnect {
|
||||||
|
name = "lndconnect";
|
||||||
|
# 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";
|
||||||
|
enableOnion = lnd.lndconnect.onion;
|
||||||
|
onionService = "${lnd.user}/lnd-rest";
|
||||||
|
port = lnd.restPort;
|
||||||
|
certPath = lnd.certPath;
|
||||||
|
macaroonPath = "${lnd.networkDir}/admin.macaroon";
|
||||||
|
}
|
||||||
|
)];
|
||||||
|
|
||||||
|
services.lnd.restAddress = mkIf (!lnd.lndconnect.onion) "0.0.0.0";
|
||||||
|
}
|
||||||
|
|
||||||
|
(mkIf lnd.lndconnect.onion {
|
||||||
|
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" ];
|
||||||
|
${operatorName} = [ "lnd-rest" ];
|
||||||
|
};
|
||||||
|
})
|
||||||
|
]))
|
||||||
|
|
||||||
|
(mkIf (clightning-rest.enable && clightning-rest.lndconnect.enable)
|
||||||
|
(mkMerge [
|
||||||
|
{
|
||||||
|
environment.systemPackages = [(
|
||||||
|
mkLndconnect {
|
||||||
|
name = "lndconnect-clightning";
|
||||||
|
isClightning = true;
|
||||||
|
enableOnion = clightning-rest.lndconnect.onion;
|
||||||
|
onionService = "${operatorName}/clightning-rest";
|
||||||
|
port = clightning-rest.port;
|
||||||
|
certPath = "${clightning-rest.dataDir}/certs/certificate.pem";
|
||||||
|
macaroonPath = "${clightning-rest.dataDir}/certs/access.macaroon";
|
||||||
|
}
|
||||||
|
)];
|
||||||
|
|
||||||
|
# clightning-rest always binds to all interfaces
|
||||||
|
}
|
||||||
|
|
||||||
|
(mkIf clightning-rest.lndconnect.onion {
|
||||||
|
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.${operatorName} = [ "clightning-rest" ];
|
||||||
|
})
|
||||||
|
])
|
||||||
|
)
|
||||||
|
];
|
||||||
|
}
|
|
@ -19,7 +19,7 @@
|
||||||
./lightning-loop.nix
|
./lightning-loop.nix
|
||||||
./lightning-pool.nix
|
./lightning-pool.nix
|
||||||
./charge-lnd.nix
|
./charge-lnd.nix
|
||||||
./lndconnect-onion.nix # Requires onion-addresses.nix
|
./lndconnect.nix # Requires onion-addresses.nix
|
||||||
./rtl.nix
|
./rtl.nix
|
||||||
./electrs.nix
|
./electrs.nix
|
||||||
./fulcrum.nix
|
./fulcrum.nix
|
||||||
|
|
|
@ -63,7 +63,7 @@ let
|
||||||
infos = OrderedDict()
|
infos = OrderedDict()
|
||||||
operator = "${config.nix-bitcoin.operator.name}"
|
operator = "${config.nix-bitcoin.operator.name}"
|
||||||
|
|
||||||
def set_onion_address(info, name, port):
|
def get_onion_address(name, port):
|
||||||
path = f"/var/lib/onion-addresses/{operator}/{name}"
|
path = f"/var/lib/onion-addresses/{operator}/{name}"
|
||||||
try:
|
try:
|
||||||
with open(path, "r") as f:
|
with open(path, "r") as f:
|
||||||
|
@ -71,7 +71,7 @@ let
|
||||||
except OSError:
|
except OSError:
|
||||||
print(f"error reading file {path}", file=sys.stderr)
|
print(f"error reading file {path}", file=sys.stderr)
|
||||||
return
|
return
|
||||||
info["onion_address"] = f"{onion_address}:{port}"
|
return f"{onion_address}:{port}"
|
||||||
|
|
||||||
def add_service(service, make_info, systemd_service = None):
|
def add_service(service, make_info, systemd_service = None):
|
||||||
systemd_service = systemd_service or service
|
systemd_service = systemd_service or service
|
||||||
|
@ -106,7 +106,7 @@ let
|
||||||
add_service("${name}", """
|
add_service("${name}", """
|
||||||
info["local_address"] = "${nbLib.addressWithPort cfg.address cfg.port}"
|
info["local_address"] = "${nbLib.addressWithPort cfg.address cfg.port}"
|
||||||
'' + mkIfOnionPort name (onionPort: ''
|
'' + mkIfOnionPort name (onionPort: ''
|
||||||
set_onion_address(info, "${name}", ${onionPort})
|
info["onion_address"] = get_onion_address("${name}", ${onionPort})
|
||||||
'') + extraCode + ''
|
'') + extraCode + ''
|
||||||
|
|
||||||
""", "${systemdServiceName}")
|
""", "${systemdServiceName}")
|
||||||
|
@ -123,8 +123,10 @@ let
|
||||||
in {
|
in {
|
||||||
inherit options;
|
inherit options;
|
||||||
|
|
||||||
config = {
|
config = mkIf cfg.enable {
|
||||||
environment.systemPackages = optional cfg.enable script;
|
environment.systemPackages = [ script ];
|
||||||
|
|
||||||
|
nix-bitcoin.operator.enable = true;
|
||||||
|
|
||||||
nix-bitcoin.nodeinfo.services = with nodeinfoLib; {
|
nix-bitcoin.nodeinfo.services = with nodeinfoLib; {
|
||||||
bitcoind = mkInfo "";
|
bitcoind = mkInfo "";
|
||||||
|
@ -133,9 +135,13 @@ in {
|
||||||
if 'onion_address' in info:
|
if 'onion_address' in info:
|
||||||
info["id"] = f"{info['nodeid']}@{info['onion_address']}"
|
info["id"] = f"{info['nodeid']}@{info['onion_address']}"
|
||||||
'';
|
'';
|
||||||
lnd = mkInfo ''
|
lnd = name: cfg: mkInfo (''
|
||||||
|
info["rest_address"] = "${nbLib.addressWithPort cfg.restAddress cfg.restPort}"
|
||||||
|
'' + mkIfOnionPort "lnd-rest" (onionPort: ''
|
||||||
|
info["onion_rest_address"] = get_onion_address("lnd-rest", ${onionPort})
|
||||||
|
'') + ''
|
||||||
info["nodeid"] = shell("lncli getinfo | jq -r '.identity_pubkey'")
|
info["nodeid"] = shell("lncli getinfo | jq -r '.identity_pubkey'")
|
||||||
'';
|
'') name cfg;
|
||||||
clightning-rest = mkInfo "";
|
clightning-rest = mkInfo "";
|
||||||
electrs = mkInfo "";
|
electrs = mkInfo "";
|
||||||
fulcrum = mkInfo "";
|
fulcrum = mkInfo "";
|
||||||
|
@ -146,7 +152,7 @@ in {
|
||||||
rtl = mkInfo "";
|
rtl = mkInfo "";
|
||||||
# Only add sshd when it has an onion service
|
# Only add sshd when it has an onion service
|
||||||
sshd = name: cfg: mkIfOnionPort "sshd" (onionPort: ''
|
sshd = name: cfg: mkIfOnionPort "sshd" (onionPort: ''
|
||||||
add_service("sshd", """set_onion_address(info, "sshd", ${onionPort})""")
|
add_service("sshd", """info["onion_address"] = get_onion_address("sshd", ${onionPort})""")
|
||||||
'');
|
'');
|
||||||
};
|
};
|
||||||
};
|
};
|
||||||
|
|
|
@ -33,7 +33,6 @@ in {
|
||||||
(mkRenamedOptionModule [ "services" "liquidd" "rpcbind" ] [ "services" "liquidd" "rpc" "address" ])
|
(mkRenamedOptionModule [ "services" "liquidd" "rpcbind" ] [ "services" "liquidd" "rpc" "address" ])
|
||||||
# 0.0.70
|
# 0.0.70
|
||||||
(mkRenamedOptionModule [ "services" "rtl" "cl-rest" ] [ "services" "clightning-rest" ])
|
(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" ])
|
(mkRenamedOptionModule [ "nix-bitcoin" "setup-secrets" ] [ "nix-bitcoin" "setupSecrets" ])
|
||||||
|
|
||||||
|
@ -46,6 +45,28 @@ in {
|
||||||
bitcoin peer connections for syncing blocks. This performs well on low and high
|
bitcoin peer connections for syncing blocks. This performs well on low and high
|
||||||
memory systems.
|
memory systems.
|
||||||
'')
|
'')
|
||||||
|
# 0.0.86
|
||||||
|
(mkRemovedOptionModule [ "services" "lnd" "restOnionService" "enable" ] ''
|
||||||
|
Set the following options instead:
|
||||||
|
services.lnd.lndconnect = {
|
||||||
|
enable = true;
|
||||||
|
onion = true;
|
||||||
|
}
|
||||||
|
'')
|
||||||
|
(mkRemovedOptionModule [ "services" "lnd" "lndconnect-onion" ] ''
|
||||||
|
Set the following options instead:
|
||||||
|
services.lnd.lndconnect = {
|
||||||
|
enable = true;
|
||||||
|
onion = true;
|
||||||
|
}
|
||||||
|
'')
|
||||||
|
(mkRemovedOptionModule [ "services" "clightning-rest" "lndconnect-onion" ] ''
|
||||||
|
Set the following options instead:
|
||||||
|
services.clightning-rest.lndconnect = {
|
||||||
|
enable = true;
|
||||||
|
onion = true;
|
||||||
|
}
|
||||||
|
'')
|
||||||
] ++
|
] ++
|
||||||
# 0.0.59
|
# 0.0.59
|
||||||
(map mkSplitEnforceTorOption [
|
(map mkSplitEnforceTorOption [
|
||||||
|
|
214
modules/presets/wireguard.nix
Normal file
214
modules/presets/wireguard.nix
Normal file
|
@ -0,0 +1,214 @@
|
||||||
|
{ config, pkgs, lib, ... }:
|
||||||
|
|
||||||
|
# Create a WireGuard server with a single peer.
|
||||||
|
# Private/public keys are created via the secrets system.
|
||||||
|
# Add helper binaries `nix-bitcoin-wg-connect` and optionally `lndconnect-wg`, `lndconnect-clightning-wg`.
|
||||||
|
|
||||||
|
# See ../../docs/services.md ("Use Zeus (mobile lightning wallet) via WireGuard")
|
||||||
|
# for usage instructions.
|
||||||
|
|
||||||
|
# This is a rather opinionated implementation that lacks the flexibility offered by
|
||||||
|
# other nix-bitcoin modules, so ship this as a `preset`.
|
||||||
|
# Some users will prefer to use `lndconnect` with their existing WireGuard or Tailscale setup.
|
||||||
|
|
||||||
|
with lib;
|
||||||
|
let
|
||||||
|
options.nix-bitcoin.wireguard = {
|
||||||
|
subnet = mkOption {
|
||||||
|
type = types.str;
|
||||||
|
default = "10.10.0";
|
||||||
|
description = mdDoc "The /24 subnet of the wireguard network.";
|
||||||
|
};
|
||||||
|
restrictPeer = mkOption {
|
||||||
|
type = types.bool;
|
||||||
|
default = true;
|
||||||
|
description = mdDoc ''
|
||||||
|
Prevent the peer from connecting to any addresses except for the WireGuard server address.
|
||||||
|
'';
|
||||||
|
};
|
||||||
|
};
|
||||||
|
|
||||||
|
cfg = config.nix-bitcoin.wireguard;
|
||||||
|
wgSubnet = cfg.subnet;
|
||||||
|
inherit (config.networking.wireguard.interfaces) wg-nb;
|
||||||
|
inherit (config.services)
|
||||||
|
lnd
|
||||||
|
clightning-rest;
|
||||||
|
|
||||||
|
lndconnect = lnd.enable && lnd.lndconnect.enable;
|
||||||
|
lndconnect-clightning = clightning-rest.enable && clightning-rest.lndconnect.enable;
|
||||||
|
|
||||||
|
serverAddress = "${wgSubnet}.1";
|
||||||
|
peerAddress = "${wgSubnet}.2";
|
||||||
|
|
||||||
|
secretsDir = config.nix-bitcoin.secretsDir;
|
||||||
|
|
||||||
|
wgConnectUser = if config.nix-bitcoin.operator.enable
|
||||||
|
then config.nix-bitcoin.operator.name
|
||||||
|
else "root";
|
||||||
|
|
||||||
|
# A script that prints a QR code to connect a peer to the server.
|
||||||
|
# The QR code encodes a wg-quick config that can be imported by the wireguard
|
||||||
|
# mobile app.
|
||||||
|
wgConnect = pkgs.writers.writeBashBin "nix-bitcoin-wg-connect" ''
|
||||||
|
set -euo pipefail
|
||||||
|
text=
|
||||||
|
host=
|
||||||
|
for arg in "$@"; do
|
||||||
|
case $arg in
|
||||||
|
--text)
|
||||||
|
text=1
|
||||||
|
;;
|
||||||
|
*)
|
||||||
|
host=$arg
|
||||||
|
;;
|
||||||
|
esac
|
||||||
|
done
|
||||||
|
|
||||||
|
if [[ ! $host ]]; then
|
||||||
|
# Use lndconnect to fetch the external ip.
|
||||||
|
# This internally uses https://github.com/GlenDC/go-external-ip, which
|
||||||
|
# queries a set of external ip providers.
|
||||||
|
host=$(
|
||||||
|
${getExe config.nix-bitcoin.pkgs.lndconnect} --url --nocert \
|
||||||
|
--configfile=/dev/null --adminmacaroonpath=/dev/null \
|
||||||
|
| sed -nE 's|.*?/(.*?):.*|\1|p'
|
||||||
|
)
|
||||||
|
fi
|
||||||
|
|
||||||
|
config="[Interface]
|
||||||
|
PrivateKey = $(cat ${secretsDir}/wg-peer-private-key)
|
||||||
|
Address = ${peerAddress}/24
|
||||||
|
|
||||||
|
[Peer]
|
||||||
|
PublicKey = $(cat ${secretsDir}/wg-server-public-key)
|
||||||
|
AllowedIPs = ${wgSubnet}.0/24
|
||||||
|
Endpoint = $host:${toString wg-nb.listenPort}
|
||||||
|
PersistentKeepalive = 25
|
||||||
|
"
|
||||||
|
|
||||||
|
if [[ $text ]]; then
|
||||||
|
echo "$config"
|
||||||
|
else
|
||||||
|
echo "$config" | ${getExe pkgs.qrencode} -t UTF8 -o -
|
||||||
|
fi
|
||||||
|
'';
|
||||||
|
in {
|
||||||
|
inherit options;
|
||||||
|
|
||||||
|
config = {
|
||||||
|
assertions = [
|
||||||
|
{
|
||||||
|
# Don't support `netns-isolation` for now to keep things simple
|
||||||
|
assertion = !(config.nix-bitcoin.netns-isolation.enable or false);
|
||||||
|
message = "`nix-bitcoin.wireguard` is not compatible with `netns-isolation`.";
|
||||||
|
}
|
||||||
|
];
|
||||||
|
|
||||||
|
networking.wireguard.interfaces.wg-nb = {
|
||||||
|
ips = [ "${serverAddress}/24" ];
|
||||||
|
listenPort = mkDefault 51820;
|
||||||
|
privateKeyFile = "${secretsDir}/wg-server-private-key";
|
||||||
|
allowedIPsAsRoutes = false;
|
||||||
|
peers = [
|
||||||
|
{
|
||||||
|
# To use the actual public key from the secrets file, use dummy pubkey
|
||||||
|
# `peer0` and replace it via `getPubkeyFromFile` (see further below)
|
||||||
|
# at peer service runtime.
|
||||||
|
publicKey = "peer0";
|
||||||
|
allowedIPs = [ "${peerAddress}/32" ];
|
||||||
|
}
|
||||||
|
];
|
||||||
|
};
|
||||||
|
|
||||||
|
systemd.services = {
|
||||||
|
wireguard-wg-nb = rec {
|
||||||
|
wants = [ "nix-bitcoin-secrets.target" ];
|
||||||
|
after = wants;
|
||||||
|
};
|
||||||
|
|
||||||
|
# HACK: Modify start/stop scripts of the peer setup service to read
|
||||||
|
# the pubkey from a secrets file.
|
||||||
|
wireguard-wg-nb-peer-peer0 = let
|
||||||
|
getPubkeyFromFile = mkBefore ''
|
||||||
|
if [[ ! -v inPatchedSrc ]]; then
|
||||||
|
export inPatchedSrc=1
|
||||||
|
publicKey=$(cat "${secretsDir}/wg-peer-public-key")
|
||||||
|
<"''${BASH_SOURCE[0]}" sed "s|\bpeer0\b|$publicKey|g" | ${pkgs.bash}/bin/bash -s
|
||||||
|
exit
|
||||||
|
fi
|
||||||
|
'';
|
||||||
|
in {
|
||||||
|
script = getPubkeyFromFile;
|
||||||
|
postStop = getPubkeyFromFile;
|
||||||
|
};
|
||||||
|
};
|
||||||
|
|
||||||
|
environment.systemPackages = [
|
||||||
|
wgConnect
|
||||||
|
] ++ (optional lndconnect
|
||||||
|
(pkgs.writers.writeBashBin "lndconnect-wg" ''
|
||||||
|
exec lndconnect --host "${serverAddress}" --nocert "$@"
|
||||||
|
'')
|
||||||
|
) ++ (optional lndconnect-clightning
|
||||||
|
(pkgs.writers.writeBashBin "lndconnect-clightning-wg" ''
|
||||||
|
exec lndconnect-clightning --host "${serverAddress}" --nocert "$@"
|
||||||
|
'')
|
||||||
|
);
|
||||||
|
|
||||||
|
networking.firewall = let
|
||||||
|
restrictPeerRule = "-s ${peerAddress} ! -d ${serverAddress} -j REJECT";
|
||||||
|
in {
|
||||||
|
allowedUDPPorts = [ wg-nb.listenPort ];
|
||||||
|
|
||||||
|
extraCommands =
|
||||||
|
optionalString lndconnect ''
|
||||||
|
iptables -w -A nixos-fw -p tcp -s ${wgSubnet}.0/24 --dport ${toString lnd.restPort} -j nixos-fw-accept
|
||||||
|
''
|
||||||
|
+ optionalString lndconnect-clightning ''
|
||||||
|
iptables -w -A nixos-fw -p tcp -s ${wgSubnet}.0/24 --dport ${toString clightning-rest.port} -j nixos-fw-accept
|
||||||
|
''
|
||||||
|
+ optionalString cfg.restrictPeer ''
|
||||||
|
iptables -w -A nixos-fw ${restrictPeerRule}
|
||||||
|
iptables -w -A FORWARD ${restrictPeerRule}
|
||||||
|
'';
|
||||||
|
|
||||||
|
extraStopCommands =
|
||||||
|
# Rules added to chain `nixos-fw` are automatically removed when restarting
|
||||||
|
# the NixOS firewall service.
|
||||||
|
mkIf cfg.restrictPeer ''
|
||||||
|
iptables -w -D FORWARD ${restrictPeerRule} || :
|
||||||
|
'';
|
||||||
|
};
|
||||||
|
|
||||||
|
# Listen on all addresses, including `serverAddress`.
|
||||||
|
# This is safe because the listen ports are secured by the firewall.
|
||||||
|
services.lnd.restAddress = mkIf lndconnect "0.0.0.0";
|
||||||
|
# clightning-rest always listens on "0.0.0.0"
|
||||||
|
|
||||||
|
nix-bitcoin.secrets = {
|
||||||
|
wg-server-private-key = {};
|
||||||
|
wg-server-public-key = { user = wgConnectUser; group = "root"; };
|
||||||
|
wg-peer-private-key = { user = wgConnectUser; group = "root"; };
|
||||||
|
wg-peer-public-key = {};
|
||||||
|
};
|
||||||
|
|
||||||
|
nix-bitcoin.generateSecretsCmds.wireguard = let
|
||||||
|
wg = "${pkgs.wireguard-tools}/bin/wg";
|
||||||
|
in ''
|
||||||
|
makeWireguardKey() {
|
||||||
|
local name=$1
|
||||||
|
local priv=wg-$name-private-key
|
||||||
|
local pub=wg-$name-public-key
|
||||||
|
if [[ ! -e $priv ]]; then
|
||||||
|
${wg} genkey > $priv
|
||||||
|
fi
|
||||||
|
if [[ $priv -nt $pub ]]; then
|
||||||
|
${wg} pubkey < $priv > $pub
|
||||||
|
fi
|
||||||
|
}
|
||||||
|
makeWireguardKey server
|
||||||
|
makeWireguardKey peer
|
||||||
|
'';
|
||||||
|
};
|
||||||
|
}
|
|
@ -228,7 +228,7 @@ let
|
||||||
version = "0.0.70";
|
version = "0.0.70";
|
||||||
condition = config.services.lnd.lndconnectOnion.enable;
|
condition = config.services.lnd.lndconnectOnion.enable;
|
||||||
message = ''
|
message = ''
|
||||||
The `lndconnect-rest-onion` binary has been renamed to `lndconnect-onion`.
|
The `lndconnect-rest-onion` binary has been renamed to `lndconnect`.
|
||||||
'';
|
'';
|
||||||
}
|
}
|
||||||
{
|
{
|
||||||
|
|
|
@ -274,6 +274,7 @@ buildable=(
|
||||||
hardened
|
hardened
|
||||||
clightning-replication
|
clightning-replication
|
||||||
lndPruned
|
lndPruned
|
||||||
|
wireguard-lndconnect
|
||||||
)
|
)
|
||||||
buildable() { buildTests buildable "$@"; }
|
buildable() { buildTests buildable "$@"; }
|
||||||
|
|
||||||
|
|
|
@ -86,8 +86,8 @@ let
|
||||||
|
|
||||||
nix-bitcoin.onionServices.lnd.public = true;
|
nix-bitcoin.onionServices.lnd.public = true;
|
||||||
|
|
||||||
tests.lndconnect-onion-lnd = cfg.lnd.lndconnectOnion.enable;
|
tests.lndconnect-onion-lnd = with cfg.lnd.lndconnect; enable && onion;
|
||||||
tests.lndconnect-onion-clightning = cfg.clightning-rest.lndconnectOnion.enable;
|
tests.lndconnect-onion-clightning = with cfg.clightning-rest.lndconnect; enable && onion;
|
||||||
|
|
||||||
tests.lightning-loop = cfg.lightning-loop.enable;
|
tests.lightning-loop = cfg.lightning-loop.enable;
|
||||||
services.lightning-loop.certificate.extraIPs = [ "20.0.0.1" ];
|
services.lightning-loop.certificate.extraIPs = [ "20.0.0.1" ];
|
||||||
|
@ -187,9 +187,9 @@ let
|
||||||
services.rtl.enable = true;
|
services.rtl.enable = true;
|
||||||
services.spark-wallet.enable = true;
|
services.spark-wallet.enable = true;
|
||||||
services.clightning-rest.enable = true;
|
services.clightning-rest.enable = true;
|
||||||
services.clightning-rest.lndconnectOnion.enable = true;
|
services.clightning-rest.lndconnect = { enable = true; onion = true; };
|
||||||
services.lnd.enable = true;
|
services.lnd.enable = true;
|
||||||
services.lnd.lndconnectOnion.enable = true;
|
services.lnd.lndconnect = { enable = true; onion = true; };
|
||||||
services.lightning-loop.enable = true;
|
services.lightning-loop.enable = true;
|
||||||
services.lightning-pool.enable = true;
|
services.lightning-pool.enable = true;
|
||||||
services.charge-lnd.enable = true;
|
services.charge-lnd.enable = true;
|
||||||
|
@ -405,6 +405,7 @@ in {
|
||||||
in
|
in
|
||||||
{
|
{
|
||||||
clightning-replication = import ./clightning-replication.nix makeTestVM pkgs;
|
clightning-replication = import ./clightning-replication.nix makeTestVM pkgs;
|
||||||
|
wireguard-lndconnect = import ./wireguard-lndconnect.nix makeTestVM pkgs;
|
||||||
} // mainTests;
|
} // mainTests;
|
||||||
|
|
||||||
tests = makeTests scenarios;
|
tests = makeTests scenarios;
|
||||||
|
|
|
@ -177,12 +177,12 @@ def _():
|
||||||
@test("lndconnect-onion-lnd")
|
@test("lndconnect-onion-lnd")
|
||||||
def _():
|
def _():
|
||||||
assert_running("lnd")
|
assert_running("lnd")
|
||||||
assert_matches("runuser -u operator -- lndconnect-onion --url", ".onion")
|
assert_matches("runuser -u operator -- lndconnect --url", ".onion")
|
||||||
|
|
||||||
@test("lndconnect-onion-clightning")
|
@test("lndconnect-onion-clightning")
|
||||||
def _():
|
def _():
|
||||||
assert_running("clightning-rest")
|
assert_running("clightning-rest")
|
||||||
assert_matches("runuser -u operator -- lndconnect-onion-clightning --url", ".onion")
|
assert_matches("runuser -u operator -- lndconnect-clightning --url", ".onion")
|
||||||
|
|
||||||
@test("lightning-loop")
|
@test("lightning-loop")
|
||||||
def _():
|
def _():
|
||||||
|
|
103
test/wireguard-lndconnect.nix
Normal file
103
test/wireguard-lndconnect.nix
Normal file
|
@ -0,0 +1,103 @@
|
||||||
|
# You can run this test via `run-tests.sh -s wireguard-lndconnect`
|
||||||
|
|
||||||
|
makeTestVM: pkgs:
|
||||||
|
with pkgs.lib;
|
||||||
|
|
||||||
|
makeTestVM {
|
||||||
|
name = "wireguard-lndconnect";
|
||||||
|
|
||||||
|
nodes = {
|
||||||
|
server = {
|
||||||
|
imports = [
|
||||||
|
../modules/modules.nix
|
||||||
|
../modules/presets/wireguard.nix
|
||||||
|
];
|
||||||
|
|
||||||
|
nixpkgs.pkgs = pkgs;
|
||||||
|
|
||||||
|
nix-bitcoin.generateSecrets = true;
|
||||||
|
nix-bitcoin.operator.enable = true;
|
||||||
|
|
||||||
|
services.clightning-rest = {
|
||||||
|
enable = true;
|
||||||
|
lndconnect.enable = true;
|
||||||
|
};
|
||||||
|
# TODO-EXTERNAL:
|
||||||
|
# When WAN is disabled, DNS bootstrapping slows down service startup by ~15 s.
|
||||||
|
services.clightning.extraConfig = "disable-dns";
|
||||||
|
|
||||||
|
services.lnd = {
|
||||||
|
enable = true;
|
||||||
|
lndconnect.enable = true;
|
||||||
|
port = 9736;
|
||||||
|
};
|
||||||
|
};
|
||||||
|
|
||||||
|
client = {
|
||||||
|
nixpkgs.pkgs = pkgs;
|
||||||
|
|
||||||
|
environment.systemPackages = with pkgs; [
|
||||||
|
wireguard-tools
|
||||||
|
];
|
||||||
|
};
|
||||||
|
};
|
||||||
|
|
||||||
|
testScript = ''
|
||||||
|
import base64
|
||||||
|
import urllib.parse as Url
|
||||||
|
from types import SimpleNamespace
|
||||||
|
|
||||||
|
def parse_lndconnect_url(url):
|
||||||
|
u = Url.urlparse(url)
|
||||||
|
queries = Url.parse_qs(u.query)
|
||||||
|
macaroon = queries['macaroon'][0]
|
||||||
|
is_clightning = url.startswith("c-lightning-rest")
|
||||||
|
|
||||||
|
return SimpleNamespace(
|
||||||
|
host = u.hostname,
|
||||||
|
port = u.port,
|
||||||
|
macaroon_hex =
|
||||||
|
macaroon if is_clightning else base64.urlsafe_b64decode(macaroon + '===').hex().upper()
|
||||||
|
)
|
||||||
|
|
||||||
|
client.start()
|
||||||
|
server.connect()
|
||||||
|
|
||||||
|
if not "is_interactive" in vars():
|
||||||
|
|
||||||
|
with subtest("connect client to server via WireGuard"):
|
||||||
|
server.wait_for_unit("wireguard-wg-nb-peer-peer0.service")
|
||||||
|
|
||||||
|
# Get WireGuard config from server and save it to `/tmp/wireguard.conf` on the client
|
||||||
|
wg_config = server.succeed("runuser -u operator -- nix-bitcoin-wg-connect server --text")
|
||||||
|
# Encode to base64
|
||||||
|
b64 = base64.b64encode(wg_config.encode('utf-8')).decode()
|
||||||
|
client.succeed(f"install -m 400 <(echo -n {b64} | base64 -d) /tmp/wireguard.conf")
|
||||||
|
|
||||||
|
# Connect to server via WireGuard
|
||||||
|
client.succeed("wg-quick up /tmp/wireguard.conf")
|
||||||
|
|
||||||
|
# Ping server from client
|
||||||
|
print(client.succeed("ping -c 1 -W 0.5 10.10.0.1"))
|
||||||
|
|
||||||
|
with subtest("lndconnect-wg"):
|
||||||
|
server.wait_for_unit("lnd.service")
|
||||||
|
lndconnect_url = server.succeed("runuser -u operator -- lndconnect-wg --url")
|
||||||
|
api = parse_lndconnect_url(lndconnect_url)
|
||||||
|
# Make lnd REST API call
|
||||||
|
client.succeed(
|
||||||
|
f"curl -fsS --max-time 3 --insecure --header 'Grpc-Metadata-macaroon: {api.macaroon_hex}' "
|
||||||
|
f"-X GET https://{api.host}:{api.port}/v1/getinfo"
|
||||||
|
)
|
||||||
|
|
||||||
|
with subtest("lndconnect-clightning-wg"):
|
||||||
|
server.wait_for_unit("clightning-rest.service")
|
||||||
|
lndconnect_url = server.succeed("runuser -u operator -- lndconnect-clightning-wg --url")
|
||||||
|
api = parse_lndconnect_url(lndconnect_url)
|
||||||
|
# Make clightning-rest API call
|
||||||
|
client.succeed(
|
||||||
|
f"curl -fsS --max-time 3 --insecure --header 'macaroon: {api.macaroon_hex}' "
|
||||||
|
f"--header 'encodingtype: hex' -X GET https://{api.host}:{api.port}/v1/getinfo"
|
||||||
|
)
|
||||||
|
'';
|
||||||
|
}
|
Loading…
Reference in New Issue
Block a user