Merge #293: Module refactorings, onionServices
e2922eb4ce
move rpc thread count setting to lightning modules (Erik Arvstedt)352fc4e8fe
liquid: remove insecure and redundant option 'rpcpassword' (Erik Arvstedt)757a66b9bd
liquid: move rpcuser definition to module (Erik Arvstedt)0e00c39d47
secure-node: improve layout (Erik Arvstedt)5f7a7962f7
backups: remove redundant option 'program' (Erik Arvstedt)04d8560f86
secure-node: remove qrencode, tor from systemPackages (Erik Arvstedt)323a431aba
improve nodeinfo (Erik Arvstedt)f6b883a9ac
remove webindex (Erik Arvstedt)2a240d6f4a
enable-tor: disable default onion services for clightning, lnd, btcpayserver (Erik Arvstedt)18c7842e1a
modules: show warnings for obsolete options (Erik Arvstedt)45c40c4eb9
versioning: simplify assertion evaluation (Erik Arvstedt)bed00fe937
lnd: use onionServices for address announcing (Erik Arvstedt)3980cd5a41
clightning: use onionServices for address announcing (Erik Arvstedt)bd2a46cb73
spark-wallet: use onionServices (Erik Arvstedt)87fb9f246b
add 'enable-tor' preset (Erik Arvstedt)05b5402bb1
add nix-bitcoin.onionServices (Erik Arvstedt)fffe988248
onionAddresses: add readonly option 'dataDir' (Erik Arvstedt)5f34b094d3
onionAddresses: improve script (Erik Arvstedt)b266f23251
onionAddresses: use service 'script' option (Erik Arvstedt)6d13b26d0a
onionAddresses: add more precise type for option 'access' (Erik Arvstedt)93562f76dd
onionAddresses: remove redundant option 'enable' (Erik Arvstedt)43c247e3fe
onionAddresses: use StateDirectory instead of tmpfiles (Erik Arvstedt)5c6977b006
rename onion-chef -> nix-bitcoin.onionAddresses (Erik Arvstedt)55073eee70
remove nix-bitcoin.pkgs.lib (Erik Arvstedt)09e0042aa8
spark-wallet: add consistent address options (Erik Arvstedt)39f16c0b4a
liquidd: add consistent address options (Erik Arvstedt)b5d76ba1b3
electrs: add consistent address options (Erik Arvstedt)8fa32b7f91
btcpayserver: add consistent address options (Erik Arvstedt)e78a609687
clightning: add consistent address options (Erik Arvstedt)b41a720c28
lnd: add consistent address options (Erik Arvstedt)dd4a0238f9
bitcoind: group rpc options under parent option 'rpc' (Erik Arvstedt)5b7e0d09b2
bitcoind: add consistent address options (Erik Arvstedt) Pull request description: ACKs for top commit: nixbitcoin: ACKe2922eb4ce
jonasnick: ACKe2922eb4ce
Tree-SHA512: a85b33efe66048f06699b3997f83c9427f70f278fa66d30ee9a29c91f50723ff8bd1ffb9d968d7f08818742c8c6afb0b40dbfc14b95a4b8c3302caf9bede4198
This commit is contained in:
commit
c6c14889eb
@ -48,8 +48,7 @@ See the [examples directory](examples/README.md).
|
|||||||
Features
|
Features
|
||||||
---
|
---
|
||||||
A [configuration preset](modules/presets/secure-node.nix) for setting up a secure node
|
A [configuration preset](modules/presets/secure-node.nix) for setting up a secure node
|
||||||
* All applications use Tor for outbound connections and accept inbound connections via onion services.
|
* All applications use Tor for outbound connections and support accepting inbound connections via onion services.
|
||||||
* Includes a [nodeinfo](modules/nodeinfo.nix) script which prints basic info about the node.
|
|
||||||
|
|
||||||
NixOS modules
|
NixOS modules
|
||||||
* Application services
|
* Application services
|
||||||
@ -74,9 +73,9 @@ NixOS modules
|
|||||||
* [bitcoin-core-hwi](https://github.com/bitcoin-core/HWI)
|
* [bitcoin-core-hwi](https://github.com/bitcoin-core/HWI)
|
||||||
* Helper
|
* Helper
|
||||||
* [netns-isolation](modules/netns-isolation.nix): isolates applications on the network-level via network namespaces
|
* [netns-isolation](modules/netns-isolation.nix): isolates applications on the network-level via network namespaces
|
||||||
|
* [nodeinfo](modules/nodeinfo.nix): script which prints info about the node's services
|
||||||
* [backups](modules/backups.nix): daily duplicity backups of all your node's important files
|
* [backups](modules/backups.nix): daily duplicity backups of all your node's important files
|
||||||
* [operator](modules/operator.nix): adds non-root user `operator` who has access to client tools (e.g. `bitcoin-cli`, `lightning-cli`)
|
* [operator](modules/operator.nix): adds non-root user `operator` who has access to client tools (e.g. `bitcoin-cli`, `lightning-cli`)
|
||||||
* [nix-bitcoin webindex](modules/nix-bitcoin-webindex.nix): a local website to display node information
|
|
||||||
|
|
||||||
Security
|
Security
|
||||||
---
|
---
|
||||||
|
@ -8,7 +8,7 @@ fetch-release > nix-bitcoin-release.nix
|
|||||||
|
|
||||||
Nodeinfo
|
Nodeinfo
|
||||||
---
|
---
|
||||||
Run `nodeinfo` to see your onion addresses for the webindex, spark, etc. if they are enabled.
|
Run `nodeinfo` to see onion addresses and local addresses for enabled services.
|
||||||
|
|
||||||
Connect to spark-wallet
|
Connect to spark-wallet
|
||||||
---
|
---
|
||||||
@ -86,10 +86,10 @@ Connect to electrs
|
|||||||
nixops deploy -d bitcoin-node
|
nixops deploy -d bitcoin-node
|
||||||
```
|
```
|
||||||
|
|
||||||
3. Get electrs onion address
|
3. Get electrs onion address with format `<onion-address>:<port>`
|
||||||
|
|
||||||
```
|
```
|
||||||
nodeinfo | grep 'ELECTRS_ONION'
|
nodeinfo | jq -r .electrs.onion_address
|
||||||
```
|
```
|
||||||
|
|
||||||
4. Connect to electrs
|
4. Connect to electrs
|
||||||
@ -98,7 +98,7 @@ Connect to electrs
|
|||||||
|
|
||||||
On Desktop
|
On Desktop
|
||||||
```
|
```
|
||||||
electrum --oneserver -1 -s "<ELECTRS_ONION>:50001:t" -p socks5:localhost:9050
|
electrum --oneserver -1 -s "<electrs onion address>:t" -p socks5:localhost:9050
|
||||||
```
|
```
|
||||||
|
|
||||||
On Android
|
On Android
|
||||||
@ -107,16 +107,16 @@ Connect to electrs
|
|||||||
Network > Proxy mode: socks5, Host: 127.0.0.1, Port: 9050
|
Network > Proxy mode: socks5, Host: 127.0.0.1, Port: 9050
|
||||||
Network > Auto-connect: OFF
|
Network > Auto-connect: OFF
|
||||||
Network > One-server mode: ON
|
Network > One-server mode: ON
|
||||||
Network > Server: <ELECTRS_ONION>:50001:t
|
Network > Server: <electrs onion address>:t
|
||||||
```
|
```
|
||||||
|
|
||||||
Connect to nix-bitcoin node through ssh Tor Hidden Service
|
Connect to nix-bitcoin node through the SSH onion service
|
||||||
---
|
---
|
||||||
1. Run `nodeinfo` on your nix-bitcoin node and note the `SSHD_ONION`
|
1. Get the SSH onion address (excluding the port suffix)
|
||||||
|
|
||||||
```
|
```
|
||||||
nixops ssh operator@bitcoin-node
|
nixops ssh operator@bitcoin-node
|
||||||
nodeinfo | grep 'SSHD_ONION'
|
nodeinfo | jq -r .sshd.onion_address | sed 's/:.*//'
|
||||||
```
|
```
|
||||||
|
|
||||||
2. Create a SSH key
|
2. Create a SSH key
|
||||||
@ -131,14 +131,14 @@ Connect to nix-bitcoin node through ssh Tor Hidden Service
|
|||||||
# FIXME: Add your SSH pubkey
|
# FIXME: Add your SSH pubkey
|
||||||
services.openssh.enable = true;
|
services.openssh.enable = true;
|
||||||
users.users.root = {
|
users.users.root = {
|
||||||
openssh.authorizedKeys.keys = [ "[contents of ~/.ssh/id_ed25519.pub]" ];
|
openssh.authorizedKeys.keys = [ "<contents of ~/.ssh/id_ed25519.pub>" ];
|
||||||
};
|
};
|
||||||
```
|
```
|
||||||
|
|
||||||
4. Connect to your nix-bitcoin node's ssh Tor Hidden Service, forwarding a local port to the nix-bitcoin node's ssh server
|
4. Connect to your nix-bitcoin node's SSH onion service, forwarding a local port to the nix-bitcoin node's SSH server
|
||||||
|
|
||||||
```
|
```
|
||||||
ssh -i ~/.ssh/id_ed25519 -L [random port of your choosing]:localhost:22 root@[your SSHD_ONION]
|
ssh -i ~/.ssh/id_ed25519 -L <random port of your choosing>:localhost:22 root@<SSH onion address>
|
||||||
```
|
```
|
||||||
|
|
||||||
5. Edit your `network-nixos.nix` to look like this
|
5. Edit your `network-nixos.nix` to look like this
|
||||||
@ -148,12 +148,12 @@ Connect to nix-bitcoin node through ssh Tor Hidden Service
|
|||||||
bitcoin-node =
|
bitcoin-node =
|
||||||
{ config, pkgs, ... }:
|
{ config, pkgs, ... }:
|
||||||
{ deployment.targetHost = "127.0.0.1";
|
{ deployment.targetHost = "127.0.0.1";
|
||||||
deployment.targetPort = [random port of your choosing];
|
deployment.targetPort = <random port of your choosing>;
|
||||||
};
|
};
|
||||||
}
|
}
|
||||||
```
|
```
|
||||||
|
|
||||||
6. Now you can run `nixops deploy -d bitcoin-node` and it will connect through the ssh tunnel you established in step iv. This also allows you to do more complex ssh setups that `nixops ssh` doesn't support. An example would be authenticating with [Trezor's ssh agent](https://github.com/romanz/trezor-agent), which provides extra security.
|
6. Now you can run `nixops deploy -d bitcoin-node` and it will connect through the SSH tunnel you established in step iv. This also allows you to do more complex SSH setups that `nixops ssh` doesn'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
|
||||||
---
|
---
|
||||||
@ -263,7 +263,7 @@ you. If however, you want to manually initialize your wallet, follow these steps
|
|||||||
## Run the tumbler
|
## Run the tumbler
|
||||||
|
|
||||||
The tumbler needs to be able to run in the background for a long time, use screen
|
The tumbler needs to be able to run in the background for a long time, use screen
|
||||||
to run it accross ssh sessions. You can also use tmux in the same fashion.
|
to run it accross SSH sessions. You can also use tmux in the same fashion.
|
||||||
|
|
||||||
1. Add screen to your `environment.systemPackages`, for example
|
1. Add screen to your `environment.systemPackages`, for example
|
||||||
|
|
||||||
|
@ -11,7 +11,7 @@ nix-shell
|
|||||||
|
|
||||||
The following example scripts set up a nix-bitcoin node according to [`configuration.nix`](configuration.nix) and then
|
The following example scripts set up a nix-bitcoin node according to [`configuration.nix`](configuration.nix) and then
|
||||||
shut down immediately. They leave no traces (outside of `/nix/store`) on the host system.\
|
shut down immediately. They leave no traces (outside of `/nix/store`) on the host system.\
|
||||||
By default, [`configuration.nix`](configuration.nix) enables `bitcoind` and `clightning` (with an onion service).
|
By default, [`configuration.nix`](configuration.nix) enables `bitcoind` and `clightning`.
|
||||||
|
|
||||||
- [`./deploy-container.sh`](deploy-container.sh) creates a [NixOS container](https://github.com/erikarvstedt/extra-container).\
|
- [`./deploy-container.sh`](deploy-container.sh) creates a [NixOS container](https://github.com/erikarvstedt/extra-container).\
|
||||||
This is the fastest way to set up a node.\
|
This is the fastest way to set up a node.\
|
||||||
|
@ -37,11 +37,12 @@
|
|||||||
# Enable this module to use clightning, a Lightning Network implementation
|
# Enable this module to use clightning, a Lightning Network implementation
|
||||||
# in C.
|
# in C.
|
||||||
services.clightning.enable = true;
|
services.clightning.enable = true;
|
||||||
# == TOR
|
#
|
||||||
# Enable this option to announce our Tor Hidden Service. By default clightning
|
# Set this to create an onion service by which clightning can accept incoming connections
|
||||||
# offers outgoing functionality, but doesn't announce the Tor Hidden Service
|
# via Tor.
|
||||||
# under which peers can reach us.
|
# The onion service is automatically announced to peers.
|
||||||
# services.clightning.announce-tor = true;
|
# nix-bitcoin.onionServices.clightning.public = true;
|
||||||
|
#
|
||||||
# == Plugins
|
# == Plugins
|
||||||
# See ../docs/usage.md for the list of available plugins.
|
# See ../docs/usage.md for the list of available plugins.
|
||||||
# services.clightning.plugins.prometheus.enable = true;
|
# services.clightning.plugins.prometheus.enable = true;
|
||||||
@ -49,13 +50,15 @@
|
|||||||
### LND
|
### LND
|
||||||
# Uncomment the following line in order to enable lnd, a lightning
|
# Uncomment the following line in order to enable lnd, a lightning
|
||||||
# implementation written in Go. In order to avoid collisions with clightning
|
# implementation written in Go. In order to avoid collisions with clightning
|
||||||
# you must disable clightning or change the services.clightning.bindport or
|
# you must disable clightning or change the services.clightning.port or
|
||||||
# services.lnd.listenPort to a port other than 9735.
|
# services.lnd.port to a port other than 9735.
|
||||||
# services.lnd.enable = true;
|
# services.lnd.enable = true;
|
||||||
# Enable this option to announce our Tor Hidden Service. By default lnd
|
#
|
||||||
# offers outgoing functionality, but doesn't announce the Tor Hidden Service
|
# Set this to create an onion service by which lnd can accept incoming connections
|
||||||
# under which peers can reach us.
|
# via Tor.
|
||||||
# services.lnd.announce-tor = true;
|
# The onion service is automatically announced to peers.
|
||||||
|
# nix-bitcoin.onionServices.lnd.public = 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
|
||||||
# seed. This will allow you to recover on-chain funds. You can run the
|
# seed. This will allow you to recover on-chain funds. You can run the
|
||||||
@ -93,6 +96,12 @@
|
|||||||
# The lightning backend service automatically enabled.
|
# The lightning backend service automatically enabled.
|
||||||
# Afterwards you need to go into Store > General Settings > Lightning Nodes
|
# Afterwards you need to go into Store > General Settings > Lightning Nodes
|
||||||
# and click to use "the internal lightning node of this BTCPay Server".
|
# and click to use "the internal lightning node of this BTCPay Server".
|
||||||
|
#
|
||||||
|
# Set this to create an onion service to make the btcpayserver web interface
|
||||||
|
# accessible via Tor.
|
||||||
|
# Security WARNING: Create a btcpayserver administrator account before allowing
|
||||||
|
# public access to the web interface.
|
||||||
|
# nix-bitcoin.onionServices.btcpayserver.enable = true;
|
||||||
|
|
||||||
### LIQUIDD
|
### LIQUIDD
|
||||||
# Enable this module to use Liquid, a sidechain for an inter-exchange
|
# Enable this module to use Liquid, a sidechain for an inter-exchange
|
||||||
@ -101,11 +110,6 @@
|
|||||||
# tool run as user operator.
|
# tool run as user operator.
|
||||||
# services.liquidd.enable = true;
|
# services.liquidd.enable = true;
|
||||||
|
|
||||||
### WEBINDEX
|
|
||||||
# Enable this module to use the nix-bitcoin-webindex, a simple website
|
|
||||||
# displaying your node information. Only available if clightning is enabled.
|
|
||||||
# services.nix-bitcoin-webindex.enable = true;
|
|
||||||
|
|
||||||
### RECURRING-DONATIONS
|
### RECURRING-DONATIONS
|
||||||
# Enable this module to send recurring donations. This is EXPERIMENTAL; it's
|
# Enable this module to send recurring donations. This is EXPERIMENTAL; it's
|
||||||
# not guaranteed that payments are succeeding or that you will notice payment
|
# not guaranteed that payments are succeeding or that you will notice payment
|
||||||
@ -203,5 +207,5 @@
|
|||||||
# The nix-bitcoin release version that your config is compatible with.
|
# The nix-bitcoin release version that your config is compatible with.
|
||||||
# When upgrading to a backwards-incompatible release, nix-bitcoin will display an
|
# When upgrading to a backwards-incompatible release, nix-bitcoin will display an
|
||||||
# an error and provide hints for migrating your config to the new release.
|
# an error and provide hints for migrating your config to the new release.
|
||||||
nix-bitcoin.configVersion = "0.0.26";
|
nix-bitcoin.configVersion = "0.0.30";
|
||||||
}
|
}
|
||||||
|
@ -31,13 +31,6 @@ let
|
|||||||
in {
|
in {
|
||||||
options.services.backups = {
|
options.services.backups = {
|
||||||
enable = mkEnableOption "Backups service";
|
enable = mkEnableOption "Backups service";
|
||||||
program = mkOption {
|
|
||||||
type = types.enum [ "duplicity" ];
|
|
||||||
default = "duplicity";
|
|
||||||
description = ''
|
|
||||||
Program with which to do backups.
|
|
||||||
'';
|
|
||||||
};
|
|
||||||
with-bulk-data = mkOption {
|
with-bulk-data = mkOption {
|
||||||
type = types.bool;
|
type = types.bool;
|
||||||
default = false;
|
default = false;
|
||||||
@ -69,7 +62,7 @@ in {
|
|||||||
};
|
};
|
||||||
};
|
};
|
||||||
|
|
||||||
config = mkIf (cfg.enable && cfg.program == "duplicity") (mkMerge [
|
config = mkIf cfg.enable (mkMerge [
|
||||||
{
|
{
|
||||||
environment.systemPackages = [ pkgs.duplicity ];
|
environment.systemPackages = [ pkgs.duplicity ];
|
||||||
|
|
||||||
|
@ -22,16 +22,18 @@ let
|
|||||||
${optionalString (cfg.assumevalid != null) "assumevalid=${cfg.assumevalid}"}
|
${optionalString (cfg.assumevalid != null) "assumevalid=${cfg.assumevalid}"}
|
||||||
|
|
||||||
# Connection options
|
# Connection options
|
||||||
${optionalString cfg.listen "bind=${cfg.bind}"}
|
${optionalString cfg.listen "bind=${cfg.address}"}
|
||||||
${optionalString (cfg.port != null) "port=${toString cfg.port}"}
|
port=${toString cfg.port}
|
||||||
${optionalString (cfg.proxy != null) "proxy=${cfg.proxy}"}
|
${optionalString (cfg.proxy != null) "proxy=${cfg.proxy}"}
|
||||||
listen=${if cfg.listen then "1" else "0"}
|
listen=${if cfg.listen then "1" else "0"}
|
||||||
${optionalString (cfg.discover != null) "discover=${if cfg.discover then "1" else "0"}"}
|
${optionalString (cfg.discover != null) "discover=${if cfg.discover then "1" else "0"}"}
|
||||||
${lib.concatMapStrings (node: "addnode=${node}\n") cfg.addnodes}
|
${lib.concatMapStrings (node: "addnode=${node}\n") cfg.addnodes}
|
||||||
|
|
||||||
# RPC server options
|
# RPC server options
|
||||||
${optionalString (cfg.rpcthreads != null) "rpcthreads=${toString cfg.rpcthreads}"}
|
rpcbind=${cfg.rpc.address}
|
||||||
rpcport=${toString cfg.rpc.port}
|
rpcport=${toString cfg.rpc.port}
|
||||||
|
rpcconnect=${cfg.rpc.address}
|
||||||
|
${optionalString (cfg.rpc.threads != null) "rpcthreads=${toString cfg.rpc.threads}"}
|
||||||
rpcwhitelistdefault=0
|
rpcwhitelistdefault=0
|
||||||
${concatMapStrings (user: ''
|
${concatMapStrings (user: ''
|
||||||
${optionalString (!user.passwordHMACFromFile) "rpcauth=${user.name}:${passwordHMAC}"}
|
${optionalString (!user.passwordHMACFromFile) "rpcauth=${user.name}:${passwordHMAC}"}
|
||||||
@ -39,9 +41,7 @@ let
|
|||||||
"rpcwhitelist=${user.name}:${lib.strings.concatStringsSep "," user.rpcwhitelist}"}
|
"rpcwhitelist=${user.name}:${lib.strings.concatStringsSep "," user.rpcwhitelist}"}
|
||||||
'') (builtins.attrValues cfg.rpc.users)
|
'') (builtins.attrValues cfg.rpc.users)
|
||||||
}
|
}
|
||||||
rpcbind=${cfg.rpcbind}
|
${lib.concatMapStrings (rpcallowip: "rpcallowip=${rpcallowip}\n") cfg.rpc.allowip}
|
||||||
rpcconnect=${cfg.rpcbind}
|
|
||||||
${lib.concatMapStrings (rpcallowip: "rpcallowip=${rpcallowip}\n") cfg.rpcallowip}
|
|
||||||
|
|
||||||
# Wallet options
|
# Wallet options
|
||||||
${optionalString (cfg.addresstype != null) "addresstype=${cfg.addresstype}"}
|
${optionalString (cfg.addresstype != null) "addresstype=${cfg.addresstype}"}
|
||||||
@ -57,6 +57,16 @@ in {
|
|||||||
options = {
|
options = {
|
||||||
services.bitcoind = {
|
services.bitcoind = {
|
||||||
enable = mkEnableOption "Bitcoin daemon";
|
enable = mkEnableOption "Bitcoin daemon";
|
||||||
|
address = mkOption {
|
||||||
|
type = types.str;
|
||||||
|
default = "127.0.0.1";
|
||||||
|
description = "Address to listen for peer connections.";
|
||||||
|
};
|
||||||
|
port = mkOption {
|
||||||
|
type = types.port;
|
||||||
|
default = 8333;
|
||||||
|
description = "Port to listen for peer connections.";
|
||||||
|
};
|
||||||
package = mkOption {
|
package = mkOption {
|
||||||
type = types.package;
|
type = types.package;
|
||||||
default = config.nix-bitcoin.pkgs.bitcoind;
|
default = config.nix-bitcoin.pkgs.bitcoind;
|
||||||
@ -77,13 +87,6 @@ in {
|
|||||||
default = "/var/lib/bitcoind";
|
default = "/var/lib/bitcoind";
|
||||||
description = "The data directory for bitcoind.";
|
description = "The data directory for bitcoind.";
|
||||||
};
|
};
|
||||||
bind = mkOption {
|
|
||||||
type = types.str;
|
|
||||||
default = "127.0.0.1";
|
|
||||||
description = ''
|
|
||||||
Bind to given address and always listen on it.
|
|
||||||
'';
|
|
||||||
};
|
|
||||||
user = mkOption {
|
user = mkOption {
|
||||||
type = types.str;
|
type = types.str;
|
||||||
default = "bitcoin";
|
default = "bitcoin";
|
||||||
@ -95,10 +98,29 @@ in {
|
|||||||
description = "The group as which to run bitcoind.";
|
description = "The group as which to run bitcoind.";
|
||||||
};
|
};
|
||||||
rpc = {
|
rpc = {
|
||||||
|
address = mkOption {
|
||||||
|
type = types.str;
|
||||||
|
default = "127.0.0.1";
|
||||||
|
description = ''
|
||||||
|
Address to listen for JSON-RPC connections.
|
||||||
|
'';
|
||||||
|
};
|
||||||
port = mkOption {
|
port = mkOption {
|
||||||
type = types.port;
|
type = types.port;
|
||||||
default = 8332;
|
default = 8332;
|
||||||
description = "Port on which to listen for JSON-RPC connections.";
|
description = "Port to listen for JSON-RPC connections.";
|
||||||
|
};
|
||||||
|
threads = mkOption {
|
||||||
|
type = types.nullOr types.ints.u16;
|
||||||
|
default = null;
|
||||||
|
description = "The number of threads to service RPC calls.";
|
||||||
|
};
|
||||||
|
allowip = mkOption {
|
||||||
|
type = types.listOf types.str;
|
||||||
|
default = [ "127.0.0.1" ];
|
||||||
|
description = ''
|
||||||
|
Allow JSON-RPC connections from specified sources.
|
||||||
|
'';
|
||||||
};
|
};
|
||||||
users = mkOption {
|
users = mkOption {
|
||||||
default = {};
|
default = {};
|
||||||
@ -144,25 +166,6 @@ in {
|
|||||||
'';
|
'';
|
||||||
};
|
};
|
||||||
};
|
};
|
||||||
rpcthreads = mkOption {
|
|
||||||
type = types.nullOr types.ints.u16;
|
|
||||||
default = null;
|
|
||||||
description = "Set the number of threads to service RPC calls";
|
|
||||||
};
|
|
||||||
rpcbind = mkOption {
|
|
||||||
type = types.str;
|
|
||||||
default = "127.0.0.1";
|
|
||||||
description = ''
|
|
||||||
Bind to given address to listen for JSON-RPC connections.
|
|
||||||
'';
|
|
||||||
};
|
|
||||||
rpcallowip = mkOption {
|
|
||||||
type = types.listOf types.str;
|
|
||||||
default = [ "127.0.0.1" ];
|
|
||||||
description = ''
|
|
||||||
Allow JSON-RPC connections from specified source.
|
|
||||||
'';
|
|
||||||
};
|
|
||||||
regtest = mkOption {
|
regtest = mkOption {
|
||||||
type = types.bool;
|
type = types.bool;
|
||||||
default = false;
|
default = false;
|
||||||
@ -176,11 +179,6 @@ in {
|
|||||||
readOnly = true;
|
readOnly = true;
|
||||||
default = mainnet: regtest: if cfg.regtest then regtest else mainnet;
|
default = mainnet: regtest: if cfg.regtest then regtest else mainnet;
|
||||||
};
|
};
|
||||||
port = mkOption {
|
|
||||||
type = types.nullOr types.port;
|
|
||||||
default = null;
|
|
||||||
description = "Override the default port on which to listen for connections.";
|
|
||||||
};
|
|
||||||
proxy = mkOption {
|
proxy = mkOption {
|
||||||
type = types.nullOr types.str;
|
type = types.nullOr types.str;
|
||||||
default = if cfg.enforceTor then config.services.tor.client.socksListenAddress else null;
|
default = if cfg.enforceTor then config.services.tor.client.socksListenAddress else null;
|
||||||
|
@ -14,6 +14,16 @@ in {
|
|||||||
default = nbPkgs.nbxplorer;
|
default = nbPkgs.nbxplorer;
|
||||||
description = "The package providing nbxplorer binaries.";
|
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 {
|
dataDir = mkOption {
|
||||||
type = types.path;
|
type = types.path;
|
||||||
default = "/var/lib/nbxplorer";
|
default = "/var/lib/nbxplorer";
|
||||||
@ -29,16 +39,6 @@ in {
|
|||||||
default = cfg.nbxplorer.user;
|
default = cfg.nbxplorer.user;
|
||||||
description = "The group as which to run nbxplorer.";
|
description = "The group as which to run nbxplorer.";
|
||||||
};
|
};
|
||||||
bind = mkOption {
|
|
||||||
type = types.str;
|
|
||||||
default = "127.0.0.1";
|
|
||||||
description = "The address on which to bind.";
|
|
||||||
};
|
|
||||||
port = mkOption {
|
|
||||||
type = types.port;
|
|
||||||
default = 24444;
|
|
||||||
description = "Port on which to bind.";
|
|
||||||
};
|
|
||||||
enable = mkOption {
|
enable = mkOption {
|
||||||
# This option is only used by netns-isolation
|
# This option is only used by netns-isolation
|
||||||
internal = true;
|
internal = true;
|
||||||
@ -49,6 +49,16 @@ in {
|
|||||||
|
|
||||||
btcpayserver = {
|
btcpayserver = {
|
||||||
enable = mkEnableOption "btcpayserver";
|
enable = mkEnableOption "btcpayserver";
|
||||||
|
address = mkOption {
|
||||||
|
type = types.str;
|
||||||
|
default = "127.0.0.1";
|
||||||
|
description = "Address to listen on.";
|
||||||
|
};
|
||||||
|
port = mkOption {
|
||||||
|
type = types.port;
|
||||||
|
default = 23000;
|
||||||
|
description = "Port to listen on.";
|
||||||
|
};
|
||||||
package = mkOption {
|
package = mkOption {
|
||||||
type = types.package;
|
type = types.package;
|
||||||
default = nbPkgs.btcpayserver;
|
default = nbPkgs.btcpayserver;
|
||||||
@ -69,16 +79,6 @@ in {
|
|||||||
default = cfg.btcpayserver.user;
|
default = cfg.btcpayserver.user;
|
||||||
description = "The group as which to run btcpayserver.";
|
description = "The group as which to run btcpayserver.";
|
||||||
};
|
};
|
||||||
bind = mkOption {
|
|
||||||
type = types.str;
|
|
||||||
default = "127.0.0.1";
|
|
||||||
description = "The address on which to bind.";
|
|
||||||
};
|
|
||||||
port = mkOption {
|
|
||||||
type = types.port;
|
|
||||||
default = 23000;
|
|
||||||
description = "Port on which to bind.";
|
|
||||||
};
|
|
||||||
lightningBackend = mkOption {
|
lightningBackend = mkOption {
|
||||||
type = types.nullOr (types.enum [ "clightning" "lnd" ]);
|
type = types.nullOr (types.enum [ "clightning" "lnd" ]);
|
||||||
default = null;
|
default = null;
|
||||||
@ -117,9 +117,9 @@ in {
|
|||||||
configFile = builtins.toFile "config" ''
|
configFile = builtins.toFile "config" ''
|
||||||
network=${config.services.bitcoind.network}
|
network=${config.services.bitcoind.network}
|
||||||
btcrpcuser=${cfg.bitcoind.rpc.users.btcpayserver.name}
|
btcrpcuser=${cfg.bitcoind.rpc.users.btcpayserver.name}
|
||||||
btcrpcurl=http://${config.services.bitcoind.rpcbind}:${toString cfg.bitcoind.rpc.port}
|
btcrpcurl=http://${config.services.bitcoind.rpc.address}:${toString cfg.bitcoind.rpc.port}
|
||||||
btcnodeendpoint=${config.services.bitcoind.bind}:8333
|
btcnodeendpoint=${config.services.bitcoind.address}:${toString config.services.bitcoind.port}
|
||||||
bind=${cfg.nbxplorer.bind}
|
bind=${cfg.nbxplorer.address}
|
||||||
port=${toString cfg.nbxplorer.port}
|
port=${toString cfg.nbxplorer.port}
|
||||||
'';
|
'';
|
||||||
in {
|
in {
|
||||||
@ -153,9 +153,9 @@ in {
|
|||||||
network=${config.services.bitcoind.network}
|
network=${config.services.bitcoind.network}
|
||||||
postgres=User ID=${cfg.btcpayserver.user};Host=/run/postgresql;Database=btcpaydb
|
postgres=User ID=${cfg.btcpayserver.user};Host=/run/postgresql;Database=btcpaydb
|
||||||
socksendpoint=${cfg.tor.client.socksListenAddress}
|
socksendpoint=${cfg.tor.client.socksListenAddress}
|
||||||
btcexplorerurl=http://${cfg.nbxplorer.bind}:${toString cfg.nbxplorer.port}/
|
btcexplorerurl=http://${cfg.nbxplorer.address}:${toString cfg.nbxplorer.port}/
|
||||||
btcexplorercookiefile=${cfg.nbxplorer.dataDir}/${config.services.bitcoind.makeNetworkName "Main" "RegTest"}/.cookie
|
btcexplorercookiefile=${cfg.nbxplorer.dataDir}/${config.services.bitcoind.makeNetworkName "Main" "RegTest"}/.cookie
|
||||||
bind=${cfg.btcpayserver.bind}
|
bind=${cfg.btcpayserver.address}
|
||||||
${optionalString (cfg.btcpayserver.rootpath != null) "rootpath=${cfg.btcpayserver.rootpath}"}
|
${optionalString (cfg.btcpayserver.rootpath != null) "rootpath=${cfg.btcpayserver.rootpath}"}
|
||||||
port=${toString cfg.btcpayserver.port}
|
port=${toString cfg.btcpayserver.port}
|
||||||
'' + optionalString (cfg.btcpayserver.lightningBackend == "clightning") ''
|
'' + optionalString (cfg.btcpayserver.lightningBackend == "clightning") ''
|
||||||
@ -163,7 +163,7 @@ in {
|
|||||||
'');
|
'');
|
||||||
lndConfig =
|
lndConfig =
|
||||||
"btclightning=type=lnd-rest;" +
|
"btclightning=type=lnd-rest;" +
|
||||||
"server=https://${toString cfg.lnd.listen}:${toString cfg.lnd.restPort}/;" +
|
"server=https://${cfg.lnd.restAddress}:${toString cfg.lnd.restPort}/;" +
|
||||||
"macaroonfilepath=/run/lnd/btcpayserver.macaroon;" +
|
"macaroonfilepath=/run/lnd/btcpayserver.macaroon;" +
|
||||||
"certthumbprint=";
|
"certthumbprint=";
|
||||||
in let self = {
|
in let self = {
|
||||||
|
@ -6,15 +6,14 @@ let
|
|||||||
cfg = config.services.clightning;
|
cfg = config.services.clightning;
|
||||||
inherit (config) nix-bitcoin-services;
|
inherit (config) nix-bitcoin-services;
|
||||||
nbPkgs = config.nix-bitcoin.pkgs;
|
nbPkgs = config.nix-bitcoin.pkgs;
|
||||||
onion-chef-service = (if cfg.announce-tor then [ "onion-chef.service" ] else []);
|
|
||||||
network = config.services.bitcoind.makeNetworkName "bitcoin" "regtest";
|
network = config.services.bitcoind.makeNetworkName "bitcoin" "regtest";
|
||||||
configFile = pkgs.writeText "config" ''
|
configFile = pkgs.writeText "config" ''
|
||||||
network=${network}
|
network=${network}
|
||||||
bitcoin-datadir=${config.services.bitcoind.dataDir}
|
bitcoin-datadir=${config.services.bitcoind.dataDir}
|
||||||
${optionalString (cfg.proxy != null) "proxy=${cfg.proxy}"}
|
${optionalString (cfg.proxy != null) "proxy=${cfg.proxy}"}
|
||||||
always-use-proxy=${if cfg.always-use-proxy then "true" else "false"}
|
always-use-proxy=${if cfg.always-use-proxy then "true" else "false"}
|
||||||
bind-addr=${cfg.bind-addr}:${toString cfg.bindport}
|
bind-addr=${cfg.address}:${toString cfg.port}
|
||||||
bitcoin-rpcconnect=${config.services.bitcoind.rpcbind}
|
bitcoin-rpcconnect=${config.services.bitcoind.rpc.address}
|
||||||
bitcoin-rpcport=${toString config.services.bitcoind.rpc.port}
|
bitcoin-rpcport=${toString config.services.bitcoind.rpc.port}
|
||||||
bitcoin-rpcuser=${config.services.bitcoind.rpc.users.public.name}
|
bitcoin-rpcuser=${config.services.bitcoind.rpc.users.public.name}
|
||||||
rpc-file-mode=0660
|
rpc-file-mode=0660
|
||||||
@ -29,13 +28,15 @@ in {
|
|||||||
If enabled, the clightning service will be installed.
|
If enabled, the clightning service will be installed.
|
||||||
'';
|
'';
|
||||||
};
|
};
|
||||||
autolisten = mkOption {
|
address = mkOption {
|
||||||
type = types.bool;
|
type = types.str;
|
||||||
default = false;
|
default = "127.0.0.1";
|
||||||
description = ''
|
description = "IP address or UNIX domain socket to listen for peer connections.";
|
||||||
Bind (and maybe announce) on IPv4 and IPv6 interfaces if no addr,
|
};
|
||||||
bind-addr or announce-addr options are specified.
|
port = mkOption {
|
||||||
'';
|
type = types.port;
|
||||||
|
default = 9735;
|
||||||
|
description = "Port to listen for peer connections.";
|
||||||
};
|
};
|
||||||
proxy = mkOption {
|
proxy = mkOption {
|
||||||
type = types.nullOr types.str;
|
type = types.nullOr types.str;
|
||||||
@ -49,21 +50,6 @@ in {
|
|||||||
Always use the *proxy*, even to connect to normal IP addresses (you can still connect to Unix domain sockets manually). This also disables all DNS lookups, to avoid leaking information.
|
Always use the *proxy*, even to connect to normal IP addresses (you can still connect to Unix domain sockets manually). This also disables all DNS lookups, to avoid leaking information.
|
||||||
'';
|
'';
|
||||||
};
|
};
|
||||||
bind-addr = mkOption {
|
|
||||||
type = nbPkgs.lib.ipv4Address;
|
|
||||||
default = "127.0.0.1";
|
|
||||||
description = "Set an IP address or UNIX domain socket to listen to";
|
|
||||||
};
|
|
||||||
bindport = mkOption {
|
|
||||||
type = types.port;
|
|
||||||
default = 9735;
|
|
||||||
description = "Set a Port to listen to locally";
|
|
||||||
};
|
|
||||||
announce-tor = mkOption {
|
|
||||||
type = types.bool;
|
|
||||||
default = false;
|
|
||||||
description = "Announce clightning Tor Hidden Service";
|
|
||||||
};
|
|
||||||
dataDir = mkOption {
|
dataDir = mkOption {
|
||||||
type = types.path;
|
type = types.path;
|
||||||
default = "/var/lib/clightning";
|
default = "/var/lib/clightning";
|
||||||
@ -97,11 +83,24 @@ in {
|
|||||||
'';
|
'';
|
||||||
description = "Binary to connect with the clightning instance.";
|
description = "Binary to connect with the clightning instance.";
|
||||||
};
|
};
|
||||||
enforceTor = nix-bitcoin-services.enforceTor;
|
getPublicAddressCmd = mkOption {
|
||||||
|
type = types.str;
|
||||||
|
default = "";
|
||||||
|
description = ''
|
||||||
|
Bash expression which outputs the public service address to announce to peers.
|
||||||
|
If left empty, no address is announced.
|
||||||
|
'';
|
||||||
|
};
|
||||||
|
inherit (nix-bitcoin-services) enforceTor;
|
||||||
};
|
};
|
||||||
|
|
||||||
config = mkIf cfg.enable {
|
config = mkIf cfg.enable {
|
||||||
services.bitcoind.enable = true;
|
services.bitcoind = {
|
||||||
|
enable = true;
|
||||||
|
# Increase rpc thread count due to reports that lightning implementations fail
|
||||||
|
# under high bitcoind rpc load
|
||||||
|
rpc.threads = 16;
|
||||||
|
};
|
||||||
|
|
||||||
environment.systemPackages = [ nbPkgs.clightning (hiPrio cfg.cli) ];
|
environment.systemPackages = [ nbPkgs.clightning (hiPrio cfg.cli) ];
|
||||||
users.users.${cfg.user} = {
|
users.users.${cfg.user} = {
|
||||||
@ -116,21 +115,25 @@ in {
|
|||||||
"d '${cfg.dataDir}' 0770 ${cfg.user} ${cfg.group} - -"
|
"d '${cfg.dataDir}' 0770 ${cfg.user} ${cfg.group} - -"
|
||||||
];
|
];
|
||||||
|
|
||||||
services.onion-chef.access.clightning = if cfg.announce-tor then [ "clightning" ] else [];
|
|
||||||
systemd.services.clightning = {
|
systemd.services.clightning = {
|
||||||
description = "Run clightningd";
|
description = "Run clightningd";
|
||||||
path = [ nbPkgs.bitcoind ];
|
path = [ nbPkgs.bitcoind ];
|
||||||
wantedBy = [ "multi-user.target" ];
|
wantedBy = [ "multi-user.target" ];
|
||||||
requires = [ "bitcoind.service" ] ++ onion-chef-service;
|
requires = [ "bitcoind.service" ];
|
||||||
after = [ "bitcoind.service" ] ++ onion-chef-service;
|
after = [ "bitcoind.service" ];
|
||||||
preStart = ''
|
preStart = ''
|
||||||
cp ${configFile} ${cfg.dataDir}/config
|
cp ${configFile} ${cfg.dataDir}/config
|
||||||
chown -R '${cfg.user}:${cfg.group}' '${cfg.dataDir}'
|
chown -R '${cfg.user}:${cfg.group}' '${cfg.dataDir}'
|
||||||
# The RPC socket has to be removed otherwise we might have stale sockets
|
# The RPC socket has to be removed otherwise we might have stale sockets
|
||||||
rm -f ${cfg.networkDir}/lightning-rpc
|
rm -f ${cfg.networkDir}/lightning-rpc
|
||||||
chmod 640 ${cfg.dataDir}/config
|
chmod 640 ${cfg.dataDir}/config
|
||||||
echo "bitcoin-rpcpassword=$(cat ${config.nix-bitcoin.secretsDir}/bitcoin-rpcpassword-public)" >> '${cfg.dataDir}/config'
|
{
|
||||||
${optionalString cfg.announce-tor "echo announce-addr=$(cat /var/lib/onion-chef/clightning/clightning) >> '${cfg.dataDir}/config'"}
|
echo "bitcoin-rpcpassword=$(cat ${config.nix-bitcoin.secretsDir}/bitcoin-rpcpassword-public)"
|
||||||
|
${optionalString (cfg.getPublicAddressCmd != "") ''
|
||||||
|
echo "announce-addr=$(${cfg.getPublicAddressCmd})"
|
||||||
|
''}
|
||||||
|
} >> '${cfg.dataDir}/config'
|
||||||
|
|
||||||
'';
|
'';
|
||||||
serviceConfig = nix-bitcoin-services.defaultHardening // {
|
serviceConfig = nix-bitcoin-services.defaultHardening // {
|
||||||
ExecStart = "${nbPkgs.clightning}/bin/lightningd --lightning-dir=${cfg.dataDir}";
|
ExecStart = "${nbPkgs.clightning}/bin/lightningd --lightning-dir=${cfg.dataDir}";
|
||||||
|
@ -6,7 +6,6 @@
|
|||||||
electrs = ./electrs.nix;
|
electrs = ./electrs.nix;
|
||||||
liquid = ./liquid.nix;
|
liquid = ./liquid.nix;
|
||||||
presets.secure-node = ./presets/secure-node.nix;
|
presets.secure-node = ./presets/secure-node.nix;
|
||||||
nix-bitcoin-webindex = ./nix-bitcoin-webindex.nix;
|
|
||||||
spark-wallet = ./spark-wallet.nix;
|
spark-wallet = ./spark-wallet.nix;
|
||||||
recurring-donations = ./recurring-donations.nix;
|
recurring-donations = ./recurring-donations.nix;
|
||||||
lnd = ./lnd.nix;
|
lnd = ./lnd.nix;
|
||||||
|
@ -9,6 +9,16 @@ let
|
|||||||
in {
|
in {
|
||||||
options.services.electrs = {
|
options.services.electrs = {
|
||||||
enable = mkEnableOption "electrs";
|
enable = mkEnableOption "electrs";
|
||||||
|
address = mkOption {
|
||||||
|
type = types.str;
|
||||||
|
default = "127.0.0.1";
|
||||||
|
description = "Address to listen for RPC connections.";
|
||||||
|
};
|
||||||
|
port = mkOption {
|
||||||
|
type = types.port;
|
||||||
|
default = 50001;
|
||||||
|
description = "RPC port.";
|
||||||
|
};
|
||||||
dataDir = mkOption {
|
dataDir = mkOption {
|
||||||
type = types.path;
|
type = types.path;
|
||||||
default = "/var/lib/electrs";
|
default = "/var/lib/electrs";
|
||||||
@ -31,16 +41,6 @@ in {
|
|||||||
If enabled, the electrs service will sync faster on high-memory systems (≥ 8GB).
|
If enabled, the electrs service will sync faster on high-memory systems (≥ 8GB).
|
||||||
'';
|
'';
|
||||||
};
|
};
|
||||||
address = mkOption {
|
|
||||||
type = types.str;
|
|
||||||
default = "127.0.0.1";
|
|
||||||
description = "RPC and monitoring listening address.";
|
|
||||||
};
|
|
||||||
port = mkOption {
|
|
||||||
type = types.port;
|
|
||||||
default = 50001;
|
|
||||||
description = "RPC port.";
|
|
||||||
};
|
|
||||||
monitoringPort = mkOption {
|
monitoringPort = mkOption {
|
||||||
type = types.port;
|
type = types.port;
|
||||||
default = 4224;
|
default = 4224;
|
||||||
@ -95,7 +95,7 @@ in {
|
|||||||
--daemon-dir='${bitcoind.dataDir}' \
|
--daemon-dir='${bitcoind.dataDir}' \
|
||||||
--electrum-rpc-addr=${cfg.address}:${toString cfg.port} \
|
--electrum-rpc-addr=${cfg.address}:${toString cfg.port} \
|
||||||
--monitoring-addr=${cfg.address}:${toString cfg.monitoringPort} \
|
--monitoring-addr=${cfg.address}:${toString cfg.monitoringPort} \
|
||||||
--daemon-rpc-addr=${bitcoind.rpcbind}:${toString bitcoind.rpc.port} \
|
--daemon-rpc-addr=${bitcoind.rpc.address}:${toString bitcoind.rpc.port} \
|
||||||
${cfg.extraArgs}
|
${cfg.extraArgs}
|
||||||
'';
|
'';
|
||||||
User = cfg.user;
|
User = cfg.user;
|
||||||
|
@ -21,7 +21,7 @@ let
|
|||||||
[BLOCKCHAIN]
|
[BLOCKCHAIN]
|
||||||
blockchain_source = bitcoin-rpc
|
blockchain_source = bitcoin-rpc
|
||||||
network = ${bitcoind.network}
|
network = ${bitcoind.network}
|
||||||
rpc_host = ${bitcoind.rpcbind}
|
rpc_host = ${bitcoind.rpc.address}
|
||||||
rpc_port = ${toString bitcoind.rpc.port}
|
rpc_port = ${toString bitcoind.rpc.port}
|
||||||
rpc_user = ${bitcoind.rpc.users.privileged.name}
|
rpc_user = ${bitcoind.rpc.users.privileged.name}
|
||||||
@@RPC_PASSWORD@@
|
@@RPC_PASSWORD@@
|
||||||
|
@ -17,7 +17,7 @@ let
|
|||||||
tlscertpath=${secretsDir}/loop-cert
|
tlscertpath=${secretsDir}/loop-cert
|
||||||
tlskeypath=${secretsDir}/loop-key
|
tlskeypath=${secretsDir}/loop-key
|
||||||
|
|
||||||
lnd.host=${config.services.lnd.rpclisten}:${toString config.services.lnd.rpcPort}
|
lnd.host=${config.services.lnd.rpcAddress}:${toString config.services.lnd.rpcPort}
|
||||||
lnd.macaroondir=${config.services.lnd.networkDir}
|
lnd.macaroondir=${config.services.lnd.networkDir}
|
||||||
lnd.tlspath=${secretsDir}/lnd-cert
|
lnd.tlspath=${secretsDir}/lnd-cert
|
||||||
|
|
||||||
|
@ -16,23 +16,22 @@ let
|
|||||||
${optionalString (cfg.validatepegin != null) "validatepegin=${if cfg.validatepegin then "1" else "0"}"}
|
${optionalString (cfg.validatepegin != null) "validatepegin=${if cfg.validatepegin then "1" else "0"}"}
|
||||||
|
|
||||||
# Connection options
|
# Connection options
|
||||||
${optionalString cfg.listen "bind=${cfg.bind}"}
|
${optionalString cfg.listen "bind=${cfg.address}"}
|
||||||
${optionalString (cfg.port != null) "port=${toString cfg.port}"}
|
port=${toString cfg.port}
|
||||||
${optionalString (cfg.proxy != null) "proxy=${cfg.proxy}"}
|
${optionalString (cfg.proxy != null) "proxy=${cfg.proxy}"}
|
||||||
listen=${if cfg.listen then "1" else "0"}
|
listen=${if cfg.listen then "1" else "0"}
|
||||||
|
|
||||||
# RPC server options
|
# RPC server options
|
||||||
${optionalString (cfg.rpc.port != null) "rpcport=${toString cfg.rpc.port}"}
|
rpcport=${toString cfg.rpc.port}
|
||||||
${concatMapStringsSep "\n"
|
${concatMapStringsSep "\n"
|
||||||
(rpcUser: "rpcauth=${rpcUser.name}:${rpcUser.passwordHMAC}")
|
(rpcUser: "rpcauth=${rpcUser.name}:${rpcUser.passwordHMAC}")
|
||||||
(attrValues cfg.rpc.users)
|
(attrValues cfg.rpc.users)
|
||||||
}
|
}
|
||||||
rpcbind=${cfg.rpcbind}
|
rpcbind=${cfg.rpc.address}
|
||||||
rpcconnect=${cfg.rpcbind}
|
rpcconnect=${cfg.rpc.address}
|
||||||
${lib.concatMapStrings (rpcallowip: "rpcallowip=${rpcallowip}\n") cfg.rpcallowip}
|
${lib.concatMapStrings (rpcallowip: "rpcallowip=${rpcallowip}\n") cfg.rpcallowip}
|
||||||
${optionalString (cfg.rpcuser != null) "rpcuser=${cfg.rpcuser}"}
|
rpcuser=${cfg.rpcuser}
|
||||||
${optionalString (cfg.rpcpassword != null) "rpcpassword=${cfg.rpcpassword}"}
|
mainchainrpchost=${config.services.bitcoind.rpc.address}
|
||||||
mainchainrpchost=${config.services.bitcoind.rpcbind}
|
|
||||||
mainchainrpcport=${toString config.services.bitcoind.rpc.port}
|
mainchainrpcport=${toString config.services.bitcoind.rpc.port}
|
||||||
mainchainrpcuser=${config.services.bitcoind.rpc.users.public.name}
|
mainchainrpcuser=${config.services.bitcoind.rpc.users.public.name}
|
||||||
|
|
||||||
@ -71,7 +70,16 @@ in {
|
|||||||
|
|
||||||
services.liquidd = {
|
services.liquidd = {
|
||||||
enable = mkEnableOption "Liquid sidechain";
|
enable = mkEnableOption "Liquid sidechain";
|
||||||
|
address = mkOption {
|
||||||
|
type = types.str;
|
||||||
|
default = "127.0.0.1";
|
||||||
|
description = "Address to listen for peer connections.";
|
||||||
|
};
|
||||||
|
port = mkOption {
|
||||||
|
type = types.port;
|
||||||
|
default = 7042;
|
||||||
|
description = "Override the default port on which to listen for connections.";
|
||||||
|
};
|
||||||
extraConfig = mkOption {
|
extraConfig = mkOption {
|
||||||
type = types.lines;
|
type = types.lines;
|
||||||
default = "";
|
default = "";
|
||||||
@ -88,14 +96,6 @@ in {
|
|||||||
default = "/var/lib/liquidd";
|
default = "/var/lib/liquidd";
|
||||||
description = "The data directory for liquidd.";
|
description = "The data directory for liquidd.";
|
||||||
};
|
};
|
||||||
bind = mkOption {
|
|
||||||
type = types.str;
|
|
||||||
default = "127.0.0.1";
|
|
||||||
description = ''
|
|
||||||
Bind to given address and always listen on it.
|
|
||||||
'';
|
|
||||||
};
|
|
||||||
|
|
||||||
user = mkOption {
|
user = mkOption {
|
||||||
type = types.str;
|
type = types.str;
|
||||||
default = "liquid";
|
default = "liquid";
|
||||||
@ -106,12 +106,16 @@ in {
|
|||||||
default = cfg.user;
|
default = cfg.user;
|
||||||
description = "The group as which to run liquidd.";
|
description = "The group as which to run liquidd.";
|
||||||
};
|
};
|
||||||
|
|
||||||
rpc = {
|
rpc = {
|
||||||
|
address = mkOption {
|
||||||
|
type = types.str;
|
||||||
|
default = "127.0.0.1";
|
||||||
|
description = "Address to listen for JSON-RPC connections.";
|
||||||
|
};
|
||||||
port = mkOption {
|
port = mkOption {
|
||||||
type = types.nullOr types.port;
|
type = types.port;
|
||||||
default = null;
|
default = 7041;
|
||||||
description = "Override the default port on which to listen for JSON-RPC connections.";
|
description = "Port to listen for JSON-RPC connections.";
|
||||||
};
|
};
|
||||||
users = mkOption {
|
users = mkOption {
|
||||||
default = {};
|
default = {};
|
||||||
@ -125,14 +129,6 @@ in {
|
|||||||
'';
|
'';
|
||||||
};
|
};
|
||||||
};
|
};
|
||||||
|
|
||||||
rpcbind = mkOption {
|
|
||||||
type = types.str;
|
|
||||||
default = "127.0.0.1";
|
|
||||||
description = ''
|
|
||||||
Bind to given address to listen for JSON-RPC connections.
|
|
||||||
'';
|
|
||||||
};
|
|
||||||
rpcallowip = mkOption {
|
rpcallowip = mkOption {
|
||||||
type = types.listOf types.str;
|
type = types.listOf types.str;
|
||||||
default = [ "127.0.0.1" ];
|
default = [ "127.0.0.1" ];
|
||||||
@ -141,25 +137,15 @@ in {
|
|||||||
'';
|
'';
|
||||||
};
|
};
|
||||||
rpcuser = mkOption {
|
rpcuser = mkOption {
|
||||||
type = types.nullOr types.str;
|
type = types.str;
|
||||||
default = null;
|
default = "liquidrpc";
|
||||||
description = "Username for JSON-RPC connections";
|
description = "Username for JSON-RPC connections";
|
||||||
};
|
};
|
||||||
rpcpassword = mkOption {
|
|
||||||
type = types.nullOr types.str;
|
|
||||||
default = null;
|
|
||||||
description = "Password for JSON-RPC connections";
|
|
||||||
};
|
|
||||||
testnet = mkOption {
|
testnet = mkOption {
|
||||||
type = types.bool;
|
type = types.bool;
|
||||||
default = false;
|
default = false;
|
||||||
description = "Whether to use the test chain.";
|
description = "Whether to use the test chain.";
|
||||||
};
|
};
|
||||||
port = mkOption {
|
|
||||||
type = types.nullOr types.port;
|
|
||||||
default = null;
|
|
||||||
description = "Override the default port on which to listen for connections.";
|
|
||||||
};
|
|
||||||
proxy = mkOption {
|
proxy = mkOption {
|
||||||
type = types.nullOr types.str;
|
type = types.nullOr types.str;
|
||||||
default = if cfg.enforceTor then config.services.tor.client.socksListenAddress else null;
|
default = if cfg.enforceTor then config.services.tor.client.socksListenAddress else null;
|
||||||
|
@ -8,8 +8,7 @@ let
|
|||||||
secretsDir = config.nix-bitcoin.secretsDir;
|
secretsDir = config.nix-bitcoin.secretsDir;
|
||||||
|
|
||||||
bitcoind = config.services.bitcoind;
|
bitcoind = config.services.bitcoind;
|
||||||
bitcoindRpcAddress = bitcoind.rpcbind;
|
bitcoindRpcAddress = bitcoind.rpc.address;
|
||||||
onion-chef-service = (if cfg.announce-tor then [ "onion-chef.service" ] else []);
|
|
||||||
networkDir = "${cfg.dataDir}/chain/bitcoin/${bitcoind.network}";
|
networkDir = "${cfg.dataDir}/chain/bitcoin/${bitcoind.network}";
|
||||||
configFile = pkgs.writeText "lnd.conf" ''
|
configFile = pkgs.writeText "lnd.conf" ''
|
||||||
datadir=${cfg.dataDir}
|
datadir=${cfg.dataDir}
|
||||||
@ -17,9 +16,9 @@ let
|
|||||||
tlscertpath=${secretsDir}/lnd-cert
|
tlscertpath=${secretsDir}/lnd-cert
|
||||||
tlskeypath=${secretsDir}/lnd-key
|
tlskeypath=${secretsDir}/lnd-key
|
||||||
|
|
||||||
listen=${toString cfg.listen}:${toString cfg.listenPort}
|
listen=${toString cfg.address}:${toString cfg.port}
|
||||||
rpclisten=${cfg.rpclisten}:${toString cfg.rpcPort}
|
rpclisten=${cfg.rpcAddress}:${toString cfg.rpcPort}
|
||||||
restlisten=${cfg.restlisten}:${toString cfg.restPort}
|
restlisten=${cfg.restAddress}:${toString cfg.restPort}
|
||||||
|
|
||||||
bitcoin.${bitcoind.network}=1
|
bitcoin.${bitcoind.network}=1
|
||||||
bitcoin.active=1
|
bitcoin.active=1
|
||||||
@ -55,50 +54,43 @@ in {
|
|||||||
default = networkDir;
|
default = networkDir;
|
||||||
description = "The network data directory.";
|
description = "The network data directory.";
|
||||||
};
|
};
|
||||||
listen = mkOption {
|
address = mkOption {
|
||||||
type = config.nix-bitcoin.pkgs.lib.ipv4Address;
|
type = types.str;
|
||||||
default = "localhost";
|
default = "localhost";
|
||||||
description = "Bind to given address to listen to peer connections";
|
description = "Address to listen for peer connections";
|
||||||
};
|
};
|
||||||
listenPort = mkOption {
|
port = mkOption {
|
||||||
type = types.port;
|
type = types.port;
|
||||||
default = 9735;
|
default = 9735;
|
||||||
description = "Bind to given port to listen to peer connections";
|
description = "Port to listen for peer connections";
|
||||||
};
|
};
|
||||||
rpclisten = mkOption {
|
rpcAddress = mkOption {
|
||||||
type = types.str;
|
type = types.str;
|
||||||
default = "localhost";
|
default = "localhost";
|
||||||
description = ''
|
description = "Address to listen for RPC connections.";
|
||||||
Bind to given address to listen to RPC connections.
|
|
||||||
'';
|
|
||||||
};
|
|
||||||
restlisten = mkOption {
|
|
||||||
type = types.str;
|
|
||||||
default = "localhost";
|
|
||||||
description = ''
|
|
||||||
Bind to given address to listen to REST connections.
|
|
||||||
'';
|
|
||||||
};
|
};
|
||||||
rpcPort = mkOption {
|
rpcPort = mkOption {
|
||||||
type = types.port;
|
type = types.port;
|
||||||
default = 10009;
|
default = 10009;
|
||||||
description = "Port on which to listen for gRPC connections.";
|
description = "Port to listen for gRPC connections.";
|
||||||
|
};
|
||||||
|
restAddress = mkOption {
|
||||||
|
type = types.str;
|
||||||
|
default = "localhost";
|
||||||
|
description = ''
|
||||||
|
Address to listen for REST connections.
|
||||||
|
'';
|
||||||
};
|
};
|
||||||
restPort = mkOption {
|
restPort = mkOption {
|
||||||
type = types.port;
|
type = types.port;
|
||||||
default = 8080;
|
default = 8080;
|
||||||
description = "Port on which to listen for REST connections.";
|
description = "Port to listen for REST connections.";
|
||||||
};
|
};
|
||||||
tor-socks = mkOption {
|
tor-socks = mkOption {
|
||||||
type = types.nullOr types.str;
|
type = types.nullOr types.str;
|
||||||
default = if cfg.enforceTor then config.services.tor.client.socksListenAddress else null;
|
default = if cfg.enforceTor then config.services.tor.client.socksListenAddress else null;
|
||||||
description = "Set a socks proxy to use to connect to Tor nodes";
|
description = "Set a socks proxy to use to connect to Tor nodes";
|
||||||
};
|
};
|
||||||
announce-tor = mkOption {
|
|
||||||
type = types.bool;
|
|
||||||
default = false;
|
|
||||||
description = "Announce LND Tor Hidden Service";
|
|
||||||
};
|
|
||||||
macaroons = mkOption {
|
macaroons = mkOption {
|
||||||
default = {};
|
default = {};
|
||||||
type = with types; attrsOf (submodule {
|
type = with types; attrsOf (submodule {
|
||||||
@ -138,13 +130,21 @@ in {
|
|||||||
# Switch user because lnd makes datadir contents readable by user only
|
# Switch user because lnd makes datadir contents readable by user only
|
||||||
''
|
''
|
||||||
sudo -u lnd ${cfg.package}/bin/lncli \
|
sudo -u lnd ${cfg.package}/bin/lncli \
|
||||||
--rpcserver ${cfg.rpclisten}:${toString cfg.rpcPort} \
|
--rpcserver ${cfg.rpcAddress}:${toString cfg.rpcPort} \
|
||||||
--tlscertpath '${secretsDir}/lnd-cert' \
|
--tlscertpath '${secretsDir}/lnd-cert' \
|
||||||
--macaroonpath '${networkDir}/admin.macaroon' "$@"
|
--macaroonpath '${networkDir}/admin.macaroon' "$@"
|
||||||
'';
|
'';
|
||||||
description = "Binary to connect with the lnd instance.";
|
description = "Binary to connect with the lnd instance.";
|
||||||
};
|
};
|
||||||
enforceTor = nix-bitcoin-services.enforceTor;
|
getPublicAddressCmd = mkOption {
|
||||||
|
type = types.str;
|
||||||
|
default = "";
|
||||||
|
description = ''
|
||||||
|
Bash expression which outputs the public service address to announce to peers.
|
||||||
|
If left empty, no address is announced.
|
||||||
|
'';
|
||||||
|
};
|
||||||
|
inherit (nix-bitcoin-services) enforceTor;
|
||||||
};
|
};
|
||||||
|
|
||||||
config = mkIf cfg.enable {
|
config = mkIf cfg.enable {
|
||||||
@ -154,7 +154,12 @@ in {
|
|||||||
}
|
}
|
||||||
];
|
];
|
||||||
|
|
||||||
services.bitcoind.enable = true;
|
services.bitcoind = {
|
||||||
|
enable = true;
|
||||||
|
# Increase rpc thread count due to reports that lightning implementations fail
|
||||||
|
# under high bitcoind rpc load
|
||||||
|
rpc.threads = 16;
|
||||||
|
};
|
||||||
|
|
||||||
environment.systemPackages = [ cfg.package (hiPrio cfg.cli) ];
|
environment.systemPackages = [ cfg.package (hiPrio cfg.cli) ];
|
||||||
|
|
||||||
@ -167,16 +172,19 @@ in {
|
|||||||
zmqpubrawtx = "tcp://${bitcoindRpcAddress}:28333";
|
zmqpubrawtx = "tcp://${bitcoindRpcAddress}:28333";
|
||||||
};
|
};
|
||||||
|
|
||||||
services.onion-chef.access.lnd = if cfg.announce-tor then [ "lnd" ] else [];
|
|
||||||
systemd.services.lnd = {
|
systemd.services.lnd = {
|
||||||
description = "Run LND";
|
description = "Run LND";
|
||||||
wantedBy = [ "multi-user.target" ];
|
wantedBy = [ "multi-user.target" ];
|
||||||
requires = [ "bitcoind.service" ] ++ onion-chef-service;
|
requires = [ "bitcoind.service" ];
|
||||||
after = [ "bitcoind.service" ] ++ onion-chef-service;
|
after = [ "bitcoind.service" ];
|
||||||
preStart = ''
|
preStart = ''
|
||||||
install -m600 ${configFile} '${cfg.dataDir}/lnd.conf'
|
install -m600 ${configFile} '${cfg.dataDir}/lnd.conf'
|
||||||
echo "bitcoind.rpcpass=$(cat ${secretsDir}/bitcoin-rpcpassword-public)" >> '${cfg.dataDir}/lnd.conf'
|
{
|
||||||
${optionalString cfg.announce-tor "echo externalip=$(cat /var/lib/onion-chef/lnd/lnd) >> '${cfg.dataDir}/lnd.conf'"}
|
echo "bitcoind.rpcpass=$(cat ${secretsDir}/bitcoin-rpcpassword-public)"
|
||||||
|
${optionalString (cfg.getPublicAddressCmd != "") ''
|
||||||
|
echo "externalip=$(${cfg.getPublicAddressCmd})"
|
||||||
|
''}
|
||||||
|
} >> '${cfg.dataDir}/lnd.conf'
|
||||||
'';
|
'';
|
||||||
serviceConfig = nix-bitcoin-services.defaultHardening // {
|
serviceConfig = nix-bitcoin-services.defaultHardening // {
|
||||||
RuntimeDirectory = "lnd"; # Only used to store custom macaroons
|
RuntimeDirectory = "lnd"; # Only used to store custom macaroons
|
||||||
@ -187,12 +195,12 @@ in {
|
|||||||
RestartSec = "10s";
|
RestartSec = "10s";
|
||||||
ReadWritePaths = "${cfg.dataDir}";
|
ReadWritePaths = "${cfg.dataDir}";
|
||||||
ExecStartPost = let
|
ExecStartPost = let
|
||||||
restUrl = "https://${cfg.restlisten}:${toString cfg.restPort}/v1";
|
restUrl = "https://${cfg.restAddress}:${toString cfg.restPort}/v1";
|
||||||
in [
|
in [
|
||||||
# Run fully privileged for secrets dir write access
|
# Run fully privileged for secrets dir write access
|
||||||
"+${nix-bitcoin-services.script ''
|
"+${nix-bitcoin-services.script ''
|
||||||
attempts=250
|
attempts=250
|
||||||
while ! { exec 3>/dev/tcp/${cfg.restlisten}/${toString cfg.restPort} && exec 3>&-; } &>/dev/null; do
|
while ! { exec 3>/dev/tcp/${cfg.restAddress}/${toString cfg.restPort} && exec 3>&-; } &>/dev/null; do
|
||||||
((attempts-- == 0)) && { echo "lnd REST service unreachable"; exit 1; }
|
((attempts-- == 0)) && { echo "lnd REST service unreachable"; exit 1; }
|
||||||
sleep 0.1
|
sleep 0.1
|
||||||
done
|
done
|
||||||
@ -234,7 +242,7 @@ in {
|
|||||||
fi
|
fi
|
||||||
|
|
||||||
# Wait until the RPC port is open
|
# Wait until the RPC port is open
|
||||||
while ! { exec 3>/dev/tcp/${cfg.rpclisten}/${toString cfg.rpcPort}; } &>/dev/null; do
|
while ! { exec 3>/dev/tcp/${cfg.rpcAddress}/${toString cfg.rpcPort}; } &>/dev/null; do
|
||||||
sleep 0.1
|
sleep 0.1
|
||||||
done
|
done
|
||||||
|
|
||||||
|
@ -24,9 +24,11 @@ with lib;
|
|||||||
# Support features
|
# Support features
|
||||||
./versioning.nix
|
./versioning.nix
|
||||||
./security.nix
|
./security.nix
|
||||||
|
./onion-addresses.nix
|
||||||
|
./onion-services.nix
|
||||||
./netns-isolation.nix
|
./netns-isolation.nix
|
||||||
|
./nodeinfo.nix
|
||||||
./backups.nix
|
./backups.nix
|
||||||
./onion-chef.nix
|
|
||||||
];
|
];
|
||||||
|
|
||||||
disabledModules = [ "services/networking/bitcoind.nix" ];
|
disabledModules = [ "services/networking/bitcoind.nix" ];
|
||||||
@ -58,11 +60,11 @@ with lib;
|
|||||||
|
|
||||||
config = {
|
config = {
|
||||||
assertions = [
|
assertions = [
|
||||||
{ assertion = (config.services.lnd.enable -> ( !config.services.clightning.enable || config.services.clightning.bindport != config.services.lnd.listenPort));
|
{ assertion = (config.services.lnd.enable -> ( !config.services.clightning.enable || config.services.clightning.port != config.services.lnd.port));
|
||||||
message = ''
|
message = ''
|
||||||
LND and clightning can't both bind to lightning port 9735. Either
|
LND and clightning can't both bind to lightning port 9735. Either
|
||||||
disable LND/clightning or change services.clightning.bindPort or
|
disable LND/clightning or change services.clightning.bindPort or
|
||||||
services.lnd.listenPort to a port other than 9735.
|
services.lnd.port to a port other than 9735.
|
||||||
'';
|
'';
|
||||||
}
|
}
|
||||||
];
|
];
|
||||||
|
@ -245,26 +245,26 @@ in {
|
|||||||
};
|
};
|
||||||
|
|
||||||
services.bitcoind = {
|
services.bitcoind = {
|
||||||
bind = netns.bitcoind.address;
|
address = netns.bitcoind.address;
|
||||||
rpcbind = netns.bitcoind.address;
|
rpc.address = netns.bitcoind.address;
|
||||||
rpcallowip = [
|
rpc.allowip = [
|
||||||
bridgeIp # For operator user
|
bridgeIp # For operator user
|
||||||
netns.bitcoind.address
|
netns.bitcoind.address
|
||||||
] ++ map (n: netns.${n}.address) netns.bitcoind.availableNetns;
|
] ++ map (n: netns.${n}.address) netns.bitcoind.availableNetns;
|
||||||
};
|
};
|
||||||
systemd.services.bitcoind-import-banlist.serviceConfig.NetworkNamespacePath = "/var/run/netns/nb-bitcoind";
|
systemd.services.bitcoind-import-banlist.serviceConfig.NetworkNamespacePath = "/var/run/netns/nb-bitcoind";
|
||||||
|
|
||||||
services.clightning.bind-addr = netns.clightning.address;
|
services.clightning.address = netns.clightning.address;
|
||||||
|
|
||||||
services.lnd = {
|
services.lnd = {
|
||||||
listen = netns.lnd.address;
|
address = netns.lnd.address;
|
||||||
rpclisten = netns.lnd.address;
|
rpcAddress = netns.lnd.address;
|
||||||
restlisten = netns.lnd.address;
|
restAddress = netns.lnd.address;
|
||||||
};
|
};
|
||||||
|
|
||||||
services.liquidd = {
|
services.liquidd = {
|
||||||
bind = netns.liquidd.address;
|
address = netns.liquidd.address;
|
||||||
rpcbind = netns.liquidd.address;
|
rpc.address = netns.liquidd.address;
|
||||||
rpcallowip = [
|
rpcallowip = [
|
||||||
bridgeIp # For operator user
|
bridgeIp # For operator user
|
||||||
netns.liquidd.address
|
netns.liquidd.address
|
||||||
@ -274,14 +274,14 @@ in {
|
|||||||
services.electrs.address = netns.electrs.address;
|
services.electrs.address = netns.electrs.address;
|
||||||
|
|
||||||
services.spark-wallet = {
|
services.spark-wallet = {
|
||||||
host = netns.spark-wallet.address;
|
address = netns.spark-wallet.address;
|
||||||
extraArgs = "--no-tls";
|
extraArgs = "--no-tls";
|
||||||
};
|
};
|
||||||
|
|
||||||
services.lightning-loop.rpcAddress = netns.lightning-loop.address;
|
services.lightning-loop.rpcAddress = netns.lightning-loop.address;
|
||||||
|
|
||||||
services.nbxplorer.bind = netns.nbxplorer.address;
|
services.nbxplorer.address = netns.nbxplorer.address;
|
||||||
services.btcpayserver.bind = netns.btcpayserver.address;
|
services.btcpayserver.address = netns.btcpayserver.address;
|
||||||
|
|
||||||
services.joinmarket.cliExec = mkCliExec "joinmarket";
|
services.joinmarket.cliExec = mkCliExec "joinmarket";
|
||||||
systemd.services.joinmarket-yieldgenerator.serviceConfig.NetworkNamespacePath = "/var/run/netns/nb-joinmarket";
|
systemd.services.joinmarket-yieldgenerator.serviceConfig.NetworkNamespacePath = "/var/run/netns/nb-joinmarket";
|
||||||
|
@ -1,105 +0,0 @@
|
|||||||
{ config, lib, pkgs, ... }:
|
|
||||||
|
|
||||||
with lib;
|
|
||||||
|
|
||||||
let
|
|
||||||
cfg = config.services.nix-bitcoin-webindex;
|
|
||||||
inherit (config) nix-bitcoin-services;
|
|
||||||
indexFile = pkgs.writeText "index.html" ''
|
|
||||||
<html>
|
|
||||||
<body>
|
|
||||||
<p>
|
|
||||||
<h1>
|
|
||||||
nix-bitcoin
|
|
||||||
</h1>
|
|
||||||
</p>
|
|
||||||
<p>
|
|
||||||
<h3>
|
|
||||||
lightning node: CLIGHTNING_ID
|
|
||||||
</h3>
|
|
||||||
</p>
|
|
||||||
</body>
|
|
||||||
</html>
|
|
||||||
'';
|
|
||||||
createWebIndex = pkgs.writeText "make-index.sh" ''
|
|
||||||
set -e
|
|
||||||
cp ${indexFile} /var/www/index.html
|
|
||||||
chown -R nginx:nginx /var/www/
|
|
||||||
nodeinfo
|
|
||||||
. <(nodeinfo)
|
|
||||||
sed -i "s/CLIGHTNING_ID/$CLIGHTNING_ID/g" /var/www/index.html
|
|
||||||
'';
|
|
||||||
in {
|
|
||||||
options.services.nix-bitcoin-webindex = {
|
|
||||||
enable = mkOption {
|
|
||||||
type = types.bool;
|
|
||||||
default = false;
|
|
||||||
description = ''
|
|
||||||
If enabled, the webindex service will be installed.
|
|
||||||
'';
|
|
||||||
};
|
|
||||||
host = mkOption {
|
|
||||||
type = types.str;
|
|
||||||
default = if config.nix-bitcoin.netns-isolation.enable then
|
|
||||||
config.nix-bitcoin.netns-isolation.netns.nginx.address
|
|
||||||
else
|
|
||||||
"localhost";
|
|
||||||
description = "HTTP server listen address.";
|
|
||||||
};
|
|
||||||
enforceTor = nix-bitcoin-services.enforceTor;
|
|
||||||
};
|
|
||||||
|
|
||||||
config = mkIf cfg.enable {
|
|
||||||
assertions = [
|
|
||||||
{ assertion = config.services.clightning.enable;
|
|
||||||
message = "nix-bitcoin-webindex requires clightning.";
|
|
||||||
}
|
|
||||||
];
|
|
||||||
|
|
||||||
systemd.tmpfiles.rules = [
|
|
||||||
"d /var/www 0755 nginx nginx - -"
|
|
||||||
];
|
|
||||||
|
|
||||||
services.nginx = {
|
|
||||||
enable = true;
|
|
||||||
virtualHosts."_" = {
|
|
||||||
root = "/var/www";
|
|
||||||
};
|
|
||||||
};
|
|
||||||
services.tor.hiddenServices.nginx = {
|
|
||||||
map = [{
|
|
||||||
port = 80; toHost = cfg.host;
|
|
||||||
} {
|
|
||||||
port = 443; toHost = cfg.host;
|
|
||||||
}];
|
|
||||||
version = 3;
|
|
||||||
};
|
|
||||||
|
|
||||||
# create-web-index
|
|
||||||
systemd.services.create-web-index = {
|
|
||||||
description = "Get node info";
|
|
||||||
wantedBy = [ "multi-user.target" ];
|
|
||||||
path = with pkgs; [
|
|
||||||
config.programs.nodeinfo
|
|
||||||
jq
|
|
||||||
sudo
|
|
||||||
] ++ optional config.services.lnd.enable config.services.lnd.cli
|
|
||||||
++ optional config.services.clightning.enable config.services.clightning.cli;
|
|
||||||
serviceConfig = nix-bitcoin-services.defaultHardening // {
|
|
||||||
ExecStart="${pkgs.bash}/bin/bash ${createWebIndex}";
|
|
||||||
User = "root";
|
|
||||||
Type = "simple";
|
|
||||||
RemainAfterExit="yes";
|
|
||||||
Restart = "on-failure";
|
|
||||||
RestartSec = "10s";
|
|
||||||
PrivateNetwork = "true"; # This service needs no network access
|
|
||||||
PrivateUsers = "false";
|
|
||||||
ReadWritePaths = "/var/www";
|
|
||||||
CapabilityBoundingSet = "CAP_SETUID CAP_SETGID CAP_SETPCAP CAP_SYS_ADMIN CAP_CHOWN CAP_FSETID CAP_SETFCAP CAP_DAC_OVERRIDE CAP_DAC_READ_SEARCH CAP_FOWNER CAP_IPC_OWNER";
|
|
||||||
} // (if cfg.enforceTor
|
|
||||||
then nix-bitcoin-services.allowTor
|
|
||||||
else nix-bitcoin-services.allowAnyIP
|
|
||||||
);
|
|
||||||
};
|
|
||||||
};
|
|
||||||
}
|
|
@ -1,74 +1,117 @@
|
|||||||
{ config, lib, pkgs, ... }:
|
{ config, lib, pkgs, ... }:
|
||||||
|
|
||||||
with lib;
|
with lib;
|
||||||
|
|
||||||
let
|
let
|
||||||
operatorName = config.nix-bitcoin.operator.name;
|
cfg = config.nix-bitcoin.nodeinfo;
|
||||||
|
|
||||||
|
# Services included in the output
|
||||||
|
services = {
|
||||||
|
bitcoind = mkInfo "";
|
||||||
|
clightning = mkInfo ''
|
||||||
|
info["nodeid"] = shell("lightning-cli getinfo | jq -r '.id'")
|
||||||
|
if 'onion_address' in info:
|
||||||
|
info["id"] = f"{info['nodeid']}@{info['onion_address']}"
|
||||||
|
'';
|
||||||
|
lnd = mkInfo ''
|
||||||
|
info["nodeid"] = shell("lightning-cli getinfo | jq -r '.id'")
|
||||||
|
'';
|
||||||
|
electrs = mkInfo "";
|
||||||
|
spark-wallet = mkInfo "";
|
||||||
|
btcpayserver = mkInfo "";
|
||||||
|
liquidd = mkInfo "";
|
||||||
|
# Only add sshd when it has an onion service
|
||||||
|
sshd = name: cfg: mkIfOnionPort "sshd" (onionPort: ''
|
||||||
|
add_service("sshd", """set_onion_address(info, "sshd", ${onionPort})""")
|
||||||
|
'');
|
||||||
|
};
|
||||||
|
|
||||||
script = pkgs.writeScriptBin "nodeinfo" ''
|
script = pkgs.writeScriptBin "nodeinfo" ''
|
||||||
set -eo pipefail
|
#!${pkgs.python3}/bin/python
|
||||||
|
|
||||||
BITCOIND_ONION="$(cat /var/lib/onion-chef/${operatorName}/bitcoind)"
|
import json
|
||||||
echo BITCOIND_ONION="$BITCOIND_ONION"
|
import subprocess
|
||||||
|
from collections import OrderedDict
|
||||||
|
|
||||||
if systemctl is-active --quiet clightning; then
|
def success(*args):
|
||||||
CLIGHTNING_NODEID=$(lightning-cli getinfo | jq -r '.id')
|
return subprocess.call(args, stdout=subprocess.DEVNULL, stderr=subprocess.DEVNULL) == 0
|
||||||
CLIGHTNING_ONION="$(cat /var/lib/onion-chef/${operatorName}/clightning)"
|
|
||||||
CLIGHTNING_ID="$CLIGHTNING_NODEID@$CLIGHTNING_ONION:9735"
|
|
||||||
echo CLIGHTNING_NODEID="$CLIGHTNING_NODEID"
|
|
||||||
echo CLIGHTNING_ONION="$CLIGHTNING_ONION"
|
|
||||||
echo CLIGHTNING_ID="$CLIGHTNING_ID"
|
|
||||||
fi
|
|
||||||
|
|
||||||
if systemctl is-active --quiet lnd; then
|
def is_active(unit):
|
||||||
LND_NODEID=$(lncli getinfo | jq -r '.uris[0]')
|
return success("systemctl", "is-active", "--quiet", unit)
|
||||||
echo LND_NODEID="$LND_NODEID"
|
|
||||||
fi
|
|
||||||
|
|
||||||
NGINX_ONION_FILE=/var/lib/onion-chef/${operatorName}/nginx
|
def is_enabled(unit):
|
||||||
if [ -e "$NGINX_ONION_FILE" ]; then
|
return success("systemctl", "is-enabled", "--quiet", unit)
|
||||||
NGINX_ONION="$(cat $NGINX_ONION_FILE)"
|
|
||||||
echo NGINX_ONION="$NGINX_ONION"
|
|
||||||
fi
|
|
||||||
|
|
||||||
LIQUIDD_ONION_FILE=/var/lib/onion-chef/${operatorName}/liquidd
|
def cmd(*args):
|
||||||
if [ -e "$LIQUIDD_ONION_FILE" ]; then
|
return subprocess.run(args, stdout=subprocess.PIPE).stdout.decode('utf-8')
|
||||||
LIQUIDD_ONION="$(cat $LIQUIDD_ONION_FILE)"
|
|
||||||
echo LIQUIDD_ONION="$LIQUIDD_ONION"
|
|
||||||
fi
|
|
||||||
|
|
||||||
SPARKWALLET_ONION_FILE=/var/lib/onion-chef/${operatorName}/spark-wallet
|
def shell(*args):
|
||||||
if [ -e "$SPARKWALLET_ONION_FILE" ]; then
|
return cmd("bash", "-c", *args).strip()
|
||||||
SPARKWALLET_ONION="$(cat $SPARKWALLET_ONION_FILE)"
|
|
||||||
echo SPARKWALLET_ONION="http://$SPARKWALLET_ONION"
|
|
||||||
fi
|
|
||||||
|
|
||||||
ELECTRS_ONION_FILE=/var/lib/onion-chef/${operatorName}/electrs
|
infos = OrderedDict()
|
||||||
if [ -e "$ELECTRS_ONION_FILE" ]; then
|
operator = "${config.nix-bitcoin.operator.name}"
|
||||||
ELECTRS_ONION="$(cat $ELECTRS_ONION_FILE)"
|
|
||||||
echo ELECTRS_ONION="$ELECTRS_ONION"
|
|
||||||
fi
|
|
||||||
|
|
||||||
BTCPAYSERVER_ONION_FILE=/var/lib/onion-chef/${operatorName}/btcpayserver
|
def set_onion_address(info, name, port):
|
||||||
if [ -e "$BTCPAYSERVER_ONION_FILE" ]; then
|
path = f"/var/lib/onion-addresses/{operator}/{name}"
|
||||||
BTCPAYSERVER_ONION="$(cat $BTCPAYSERVER_ONION_FILE)"
|
try:
|
||||||
echo BTCPAYSERVER_ONION="$BTCPAYSERVER_ONION"
|
with open(path, "r") as f:
|
||||||
fi
|
onion_address = f.read().strip()
|
||||||
|
except OSError:
|
||||||
|
print(f"error reading file {path}", file=sys.stderr)
|
||||||
|
return
|
||||||
|
info["onion_address"] = f"{onion_address}:{port}"
|
||||||
|
|
||||||
SSHD_ONION_FILE=/var/lib/onion-chef/${operatorName}/sshd
|
def add_service(service, make_info):
|
||||||
if [ -e "$SSHD_ONION_FILE" ]; then
|
if not is_active(service):
|
||||||
SSHD_ONION="$(cat $SSHD_ONION_FILE)"
|
infos[service] = "service is not running"
|
||||||
echo SSHD_ONION="$SSHD_ONION"
|
else:
|
||||||
fi
|
info = OrderedDict()
|
||||||
|
exec(make_info, globals(), locals())
|
||||||
|
infos[service] = info
|
||||||
|
|
||||||
|
if is_enabled("onion-adresses") and not is_active("onion-adresses"):
|
||||||
|
print("error: service 'onion-adresses' is not running")
|
||||||
|
exit(1)
|
||||||
|
|
||||||
|
${concatStrings infos}
|
||||||
|
|
||||||
|
print(json.dumps(infos, indent=2))
|
||||||
'';
|
'';
|
||||||
|
|
||||||
|
infos = map (service:
|
||||||
|
let cfg = config.services.${service};
|
||||||
|
in optionalString cfg.enable (services.${service} service cfg)
|
||||||
|
) (builtins.attrNames services);
|
||||||
|
|
||||||
|
mkInfo = extraCode: name: cfg:
|
||||||
|
''
|
||||||
|
add_service("${name}", """
|
||||||
|
info["local_address"] = "${cfg.address}:${toString cfg.port}"
|
||||||
|
'' + mkIfOnionPort name (onionPort: ''
|
||||||
|
set_onion_address(info, "${name}", ${onionPort})
|
||||||
|
'') + extraCode + ''
|
||||||
|
|
||||||
|
""")
|
||||||
|
'';
|
||||||
|
|
||||||
|
mkIfOnionPort = name: fn:
|
||||||
|
if hiddenServices ? ${name} then
|
||||||
|
fn (toString (builtins.elemAt hiddenServices.${name}.map 0).port)
|
||||||
|
else
|
||||||
|
"";
|
||||||
|
|
||||||
|
inherit (config.services.tor) hiddenServices;
|
||||||
in {
|
in {
|
||||||
options = {
|
options = {
|
||||||
programs.nodeinfo = mkOption {
|
nix-bitcoin.nodeinfo = {
|
||||||
readOnly = true;
|
enable = mkEnableOption "nodeinfo";
|
||||||
default = script;
|
program = mkOption {
|
||||||
|
readOnly = true;
|
||||||
|
default = script;
|
||||||
|
};
|
||||||
};
|
};
|
||||||
};
|
};
|
||||||
|
|
||||||
config = {
|
config = {
|
||||||
environment.systemPackages = [ script ];
|
environment.systemPackages = optional cfg.enable script;
|
||||||
};
|
};
|
||||||
}
|
}
|
||||||
|
28
modules/obsolete-options.nix
Normal file
28
modules/obsolete-options.nix
Normal file
@ -0,0 +1,28 @@
|
|||||||
|
{ lib, ... }:
|
||||||
|
|
||||||
|
with lib;
|
||||||
|
let
|
||||||
|
mkRenamedAnnounceTorOption = service:
|
||||||
|
# use mkRemovedOptionModule because mkRenamedOptionModule fails with an infinite recursion error
|
||||||
|
mkRemovedOptionModule [ "services" service "announce-tor" ] ''
|
||||||
|
Use option `nix-bitcoin.onionServices.${service}.public` instead.
|
||||||
|
'';
|
||||||
|
in {
|
||||||
|
imports = [
|
||||||
|
(mkRenamedOptionModule [ "services" "bitcoind" "bind" ] [ "services" "bitcoind" "address" ])
|
||||||
|
(mkRenamedOptionModule [ "services" "bitcoind" "rpcallowip" ] [ "services" "bitcoind" "rpc" "allowip" ])
|
||||||
|
(mkRenamedOptionModule [ "services" "bitcoind" "rpcthreads" ] [ "services" "bitcoind" "rpc" "threads" ])
|
||||||
|
(mkRenamedOptionModule [ "services" "clightning" "bind-addr" ] [ "services" "clightning" "address" ])
|
||||||
|
(mkRenamedOptionModule [ "services" "clightning" "bindport" ] [ "services" "clightning" "port" ])
|
||||||
|
(mkRenamedOptionModule [ "services" "spark-wallet" "host" ] [ "services" "spark-wallet" "address" ])
|
||||||
|
(mkRenamedOptionModule [ "services" "lnd" "rpclisten" ] [ "services" "lnd" "rpcAddress" ])
|
||||||
|
(mkRenamedOptionModule [ "services" "lnd" "listen" ] [ "services" "lnd" "address" ])
|
||||||
|
(mkRenamedOptionModule [ "services" "lnd" "listenPort" ] [ "services" "lnd" "port" ])
|
||||||
|
(mkRenamedOptionModule [ "services" "btcpayserver" "bind" ] [ "services" "btcpayserver" "address" ])
|
||||||
|
(mkRenamedOptionModule [ "services" "liquidd" "bind" ] [ "services" "liquidd" "address" ])
|
||||||
|
(mkRenamedOptionModule [ "services" "liquidd" "rpcbind" ] [ "services" "liquidd" "rpc" "address" ])
|
||||||
|
|
||||||
|
(mkRenamedAnnounceTorOption "clightning")
|
||||||
|
(mkRenamedAnnounceTorOption "lnd")
|
||||||
|
];
|
||||||
|
}
|
76
modules/onion-addresses.nix
Normal file
76
modules/onion-addresses.nix
Normal file
@ -0,0 +1,76 @@
|
|||||||
|
# This module enables unprivileged users to read onion addresses.
|
||||||
|
# By default, onion addresses in /var/lib/tor/onion are only readable by the
|
||||||
|
# tor user.
|
||||||
|
# The included service copies onion addresses to /var/lib/onion-addresses/<user>/
|
||||||
|
# and sets permissions according to option 'access'.
|
||||||
|
|
||||||
|
{ config, lib, ... }:
|
||||||
|
|
||||||
|
with lib;
|
||||||
|
|
||||||
|
let
|
||||||
|
cfg = config.nix-bitcoin.onionAddresses;
|
||||||
|
inherit (config) nix-bitcoin-services;
|
||||||
|
in {
|
||||||
|
options.nix-bitcoin.onionAddresses = {
|
||||||
|
access = mkOption {
|
||||||
|
type = with types; attrsOf (listOf str);
|
||||||
|
default = {};
|
||||||
|
description = ''
|
||||||
|
This option controls who is allowed to access onion addresses.
|
||||||
|
For example, the following allows user 'myuser' to access bitcoind
|
||||||
|
and clightning onion addresses:
|
||||||
|
{
|
||||||
|
"myuser" = [ "bitcoind" "clightning" ];
|
||||||
|
};
|
||||||
|
The onion hostnames can then be read from
|
||||||
|
/var/lib/onion-addresses/myuser.
|
||||||
|
'';
|
||||||
|
};
|
||||||
|
dataDir = mkOption {
|
||||||
|
readOnly = true;
|
||||||
|
default = "/var/lib/onion-addresses";
|
||||||
|
};
|
||||||
|
};
|
||||||
|
|
||||||
|
config = mkIf (cfg.access != {}) {
|
||||||
|
systemd.services.onion-addresses = {
|
||||||
|
wantedBy = [ "tor.service" ];
|
||||||
|
bindsTo = [ "tor.service" ];
|
||||||
|
after = [ "tor.service" ];
|
||||||
|
serviceConfig = nix-bitcoin-services.defaultHardening // {
|
||||||
|
Type = "oneshot";
|
||||||
|
RemainAfterExit = true;
|
||||||
|
StateDirectory = "onion-addresses";
|
||||||
|
PrivateNetwork = "true"; # This service needs no network access
|
||||||
|
PrivateUsers = "false";
|
||||||
|
CapabilityBoundingSet = "CAP_CHOWN CAP_FSETID CAP_SETFCAP CAP_DAC_OVERRIDE CAP_DAC_READ_SEARCH CAP_FOWNER CAP_IPC_OWNER";
|
||||||
|
};
|
||||||
|
script = ''
|
||||||
|
# Wait until tor is up
|
||||||
|
until [[ -e /var/lib/tor/state ]]; do sleep 0.1; done
|
||||||
|
|
||||||
|
cd ${cfg.dataDir}
|
||||||
|
rm -rf *
|
||||||
|
|
||||||
|
${concatMapStrings
|
||||||
|
(user: ''
|
||||||
|
mkdir -p -m 0700 ${user}
|
||||||
|
chown ${user} ${user}
|
||||||
|
${concatMapStrings
|
||||||
|
(service: ''
|
||||||
|
onionFile=/var/lib/tor/onion/${service}/hostname
|
||||||
|
if [[ -e $onionFile ]]; then
|
||||||
|
cp $onionFile ${user}/${service}
|
||||||
|
chown ${user} ${user}/${service}
|
||||||
|
fi
|
||||||
|
'')
|
||||||
|
cfg.access.${user}
|
||||||
|
}
|
||||||
|
'')
|
||||||
|
(builtins.attrNames cfg.access)
|
||||||
|
}
|
||||||
|
'';
|
||||||
|
};
|
||||||
|
};
|
||||||
|
}
|
@ -1,90 +0,0 @@
|
|||||||
# The onion chef module allows unprivileged users to read onion hostnames.
|
|
||||||
# By default the onion hostnames in /var/lib/tor/onion are only readable by the
|
|
||||||
# tor user. The onion chef copies the onion hostnames into into
|
|
||||||
# /var/lib/onion-chef and sets permissions according to the access option.
|
|
||||||
|
|
||||||
{ config, lib, pkgs, ... }:
|
|
||||||
|
|
||||||
with lib;
|
|
||||||
|
|
||||||
let
|
|
||||||
cfg = config.services.onion-chef;
|
|
||||||
inherit (config) nix-bitcoin-services;
|
|
||||||
dataDir = "/var/lib/onion-chef/";
|
|
||||||
onion-chef-script = pkgs.writeScript "onion-chef.sh" ''
|
|
||||||
# wait until tor is up
|
|
||||||
until ls -l /var/lib/tor/state; do sleep 1; done
|
|
||||||
|
|
||||||
cd ${dataDir}
|
|
||||||
|
|
||||||
# Create directory for every user and set permissions
|
|
||||||
${ builtins.foldl'
|
|
||||||
(x: user: x +
|
|
||||||
''
|
|
||||||
mkdir -p -m 0700 ${user}
|
|
||||||
chown ${user} ${user}
|
|
||||||
# Copy onion hostnames into the user's directory
|
|
||||||
${ builtins.foldl'
|
|
||||||
(x: onion: x +
|
|
||||||
''
|
|
||||||
ONION_FILE=/var/lib/tor/onion/${onion}/hostname
|
|
||||||
if [ -e "$ONION_FILE" ]; then
|
|
||||||
cp $ONION_FILE ${user}/${onion}
|
|
||||||
chown ${user} ${user}/${onion}
|
|
||||||
fi
|
|
||||||
'')
|
|
||||||
""
|
|
||||||
(builtins.getAttr user cfg.access)
|
|
||||||
}
|
|
||||||
'')
|
|
||||||
""
|
|
||||||
(builtins.attrNames cfg.access)
|
|
||||||
}
|
|
||||||
'';
|
|
||||||
in {
|
|
||||||
options.services.onion-chef = {
|
|
||||||
enable = mkOption {
|
|
||||||
type = types.bool;
|
|
||||||
default = false;
|
|
||||||
description = ''
|
|
||||||
If enabled, the onion-chef service will be installed.
|
|
||||||
'';
|
|
||||||
};
|
|
||||||
access = mkOption {
|
|
||||||
type = types.attrs;
|
|
||||||
default = {};
|
|
||||||
description = ''
|
|
||||||
This option controls who is allowed to access onion hostnames. For
|
|
||||||
example the following allows the user operator to access the bitcoind
|
|
||||||
and clightning onion.
|
|
||||||
{
|
|
||||||
"operator" = [ "bitcoind" "clightning" ];
|
|
||||||
};
|
|
||||||
The onion hostnames can then be read from
|
|
||||||
/var/lib/onion-chef/<user>.
|
|
||||||
'';
|
|
||||||
};
|
|
||||||
};
|
|
||||||
|
|
||||||
config = mkIf cfg.enable {
|
|
||||||
systemd.tmpfiles.rules = [
|
|
||||||
"d '${dataDir}' 0755 root root - -"
|
|
||||||
];
|
|
||||||
|
|
||||||
systemd.services.onion-chef = {
|
|
||||||
description = "Run onion-chef";
|
|
||||||
wantedBy = [ "tor.service" ];
|
|
||||||
bindsTo = [ "tor.service" ];
|
|
||||||
after = [ "tor.service" ];
|
|
||||||
serviceConfig = nix-bitcoin-services.defaultHardening // {
|
|
||||||
ExecStart = "${pkgs.bash}/bin/bash ${onion-chef-script}";
|
|
||||||
Type = "oneshot";
|
|
||||||
RemainAfterExit = true;
|
|
||||||
PrivateNetwork = "true"; # This service needs no network access
|
|
||||||
PrivateUsers = "false";
|
|
||||||
ReadWritePaths = "${dataDir}";
|
|
||||||
CapabilityBoundingSet = "CAP_CHOWN CAP_FSETID CAP_SETFCAP CAP_DAC_OVERRIDE CAP_DAC_READ_SEARCH CAP_FOWNER CAP_IPC_OWNER";
|
|
||||||
};
|
|
||||||
};
|
|
||||||
};
|
|
||||||
}
|
|
121
modules/onion-services.nix
Normal file
121
modules/onion-services.nix
Normal file
@ -0,0 +1,121 @@
|
|||||||
|
# This module creates onion-services for NixOS services.
|
||||||
|
# An onion service can be enabled for every service that defines
|
||||||
|
# options 'address', 'port' and optionally 'getPublicAddressCmd'.
|
||||||
|
#
|
||||||
|
# See it in use at ./presets/enable-tor.nix
|
||||||
|
|
||||||
|
{ config, lib, pkgs, ... }:
|
||||||
|
|
||||||
|
with lib;
|
||||||
|
|
||||||
|
let
|
||||||
|
cfg = config.nix-bitcoin.onionServices;
|
||||||
|
|
||||||
|
services = builtins.attrNames cfg;
|
||||||
|
|
||||||
|
activeServices = builtins.filter (service:
|
||||||
|
config.services.${service}.enable && cfg.${service}.enable
|
||||||
|
) services;
|
||||||
|
|
||||||
|
publicServices = builtins.filter (service: cfg.${service}.public) activeServices;
|
||||||
|
in {
|
||||||
|
options.nix-bitcoin.onionServices = mkOption {
|
||||||
|
default = {};
|
||||||
|
type = with types; attrsOf (submodule (
|
||||||
|
{ config, ... }: {
|
||||||
|
options = {
|
||||||
|
enable = mkOption {
|
||||||
|
type = types.bool;
|
||||||
|
default = config.public;
|
||||||
|
description = ''
|
||||||
|
Create an onion service for the given service.
|
||||||
|
The service must define options 'address' and 'port'.
|
||||||
|
'';
|
||||||
|
};
|
||||||
|
public = mkOption {
|
||||||
|
type = types.bool;
|
||||||
|
default = false;
|
||||||
|
description = ''
|
||||||
|
Make the onion address accessible to the service.
|
||||||
|
If enabled, the onion service is automatically enabled.
|
||||||
|
Only available for services that define option `getPublicAddressCmd`.
|
||||||
|
'';
|
||||||
|
};
|
||||||
|
externalPort = mkOption {
|
||||||
|
type = types.nullOr types.port;
|
||||||
|
default = null;
|
||||||
|
description = "Override the external port of the onion service.";
|
||||||
|
};
|
||||||
|
};
|
||||||
|
}
|
||||||
|
));
|
||||||
|
};
|
||||||
|
|
||||||
|
config = mkMerge [
|
||||||
|
(mkIf (cfg != {}) {
|
||||||
|
# Define hidden services
|
||||||
|
services.tor = {
|
||||||
|
enable = true;
|
||||||
|
hiddenServices = genAttrs activeServices (name:
|
||||||
|
let
|
||||||
|
service = config.services.${name};
|
||||||
|
inherit (cfg.${name}) externalPort;
|
||||||
|
in {
|
||||||
|
map = [{
|
||||||
|
port = if externalPort != null then externalPort else service.port;
|
||||||
|
toPort = service.port;
|
||||||
|
toHost = if service.address == "0.0.0.0" then "127.0.0.1" else service.address;
|
||||||
|
}];
|
||||||
|
version = 3;
|
||||||
|
}
|
||||||
|
);
|
||||||
|
};
|
||||||
|
|
||||||
|
# Enable public services to access their own onion addresses
|
||||||
|
nix-bitcoin.onionAddresses.access = (
|
||||||
|
genAttrs publicServices singleton
|
||||||
|
) // {
|
||||||
|
# Allow the operator user to access onion addresses for all active services
|
||||||
|
${config.nix-bitcoin.operator.name} = mkIf config.nix-bitcoin.operator.enable activeServices;
|
||||||
|
};
|
||||||
|
systemd.services = let
|
||||||
|
onionAddresses = [ "onion-addresses.service" ];
|
||||||
|
in genAttrs publicServices (service: {
|
||||||
|
requires = onionAddresses;
|
||||||
|
after = onionAddresses;
|
||||||
|
});
|
||||||
|
})
|
||||||
|
|
||||||
|
# Set getPublicAddressCmd for public services
|
||||||
|
{
|
||||||
|
services = let
|
||||||
|
# publicServices' doesn't depend on config.services.*.enable,
|
||||||
|
# so we can use it to define config.services without causing infinite recursion
|
||||||
|
publicServices' = builtins.filter (service:
|
||||||
|
let srv = cfg.${service};
|
||||||
|
in srv.public && srv.enable
|
||||||
|
) services;
|
||||||
|
in genAttrs publicServices' (service: {
|
||||||
|
getPublicAddressCmd = "cat ${config.nix-bitcoin.onionAddresses.dataDir}/${service}/${service}";
|
||||||
|
});
|
||||||
|
}
|
||||||
|
|
||||||
|
# Set sensible defaults for some services
|
||||||
|
{
|
||||||
|
nix-bitcoin.onionServices = {
|
||||||
|
spark-wallet = {
|
||||||
|
externalPort = 80;
|
||||||
|
# Enable 'public' by default, but don't auto-enable the onion service.
|
||||||
|
# When the onion service is enabled, 'public' lets spark-wallet generate
|
||||||
|
# a QR code for accessing the web interface.
|
||||||
|
public = true;
|
||||||
|
# Low priority so we can override this with mkDefault in ./presets/enable-tor.nix
|
||||||
|
enable = mkOverride 1400 false;
|
||||||
|
};
|
||||||
|
btcpayserver = {
|
||||||
|
externalPort = 80;
|
||||||
|
};
|
||||||
|
};
|
||||||
|
}
|
||||||
|
];
|
||||||
|
}
|
32
modules/presets/enable-tor.nix
Normal file
32
modules/presets/enable-tor.nix
Normal file
@ -0,0 +1,32 @@
|
|||||||
|
{ lib, ... }:
|
||||||
|
let
|
||||||
|
defaultTrue = lib.mkDefault true;
|
||||||
|
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;
|
||||||
|
# disable Tor enforcement until btcpayserver can fetch rates over Tor
|
||||||
|
# btcpayserver.enforceTor = true;
|
||||||
|
nbxplorer.enforceTor = true;
|
||||||
|
spark-wallet.enforceTor = true;
|
||||||
|
recurring-donations.enforceTor = true;
|
||||||
|
};
|
||||||
|
|
||||||
|
# Add onion services for incoming connections
|
||||||
|
nix-bitcoin.onionServices = {
|
||||||
|
bitcoind.enable = defaultTrue;
|
||||||
|
liquidd.enable = defaultTrue;
|
||||||
|
electrs.enable = defaultTrue;
|
||||||
|
spark-wallet.enable = defaultTrue;
|
||||||
|
};
|
||||||
|
}
|
@ -14,23 +14,9 @@ let
|
|||||||
in {
|
in {
|
||||||
imports = [
|
imports = [
|
||||||
../modules.nix
|
../modules.nix
|
||||||
../nodeinfo.nix
|
./enable-tor.nix
|
||||||
../nix-bitcoin-webindex.nix
|
|
||||||
];
|
];
|
||||||
|
|
||||||
options = {
|
|
||||||
services.clightning.onionport = mkOption {
|
|
||||||
type = types.port;
|
|
||||||
default = 9735;
|
|
||||||
description = "Port on which to listen for tor client connections.";
|
|
||||||
};
|
|
||||||
services.lnd.onionport = mkOption {
|
|
||||||
type = types.ints.u16;
|
|
||||||
default = 9735;
|
|
||||||
description = "Port on which to listen for tor client connections.";
|
|
||||||
};
|
|
||||||
};
|
|
||||||
|
|
||||||
config = {
|
config = {
|
||||||
# For backwards compatibility only
|
# For backwards compatibility only
|
||||||
nix-bitcoin.secretsDir = mkDefault "/secrets";
|
nix-bitcoin.secretsDir = mkDefault "/secrets";
|
||||||
@ -39,99 +25,36 @@ in {
|
|||||||
|
|
||||||
nix-bitcoin.security.hideProcessInformation = true;
|
nix-bitcoin.security.hideProcessInformation = true;
|
||||||
|
|
||||||
# Tor
|
environment.systemPackages = with pkgs; [
|
||||||
services.tor = {
|
jq
|
||||||
enable = true;
|
];
|
||||||
client.enable = true;
|
|
||||||
|
|
||||||
hiddenServices.sshd = mkHiddenService { port = 22; };
|
# sshd
|
||||||
};
|
services.tor.hiddenServices.sshd = mkHiddenService { port = 22; };
|
||||||
|
nix-bitcoin.onionAddresses.access.${operatorName} = [ "sshd" ];
|
||||||
|
|
||||||
# bitcoind
|
|
||||||
services.bitcoind = {
|
services.bitcoind = {
|
||||||
enable = true;
|
enable = true;
|
||||||
listen = true;
|
listen = true;
|
||||||
dataDirReadableByGroup = mkIf cfg.electrs.high-memory true;
|
dataDirReadableByGroup = mkIf cfg.electrs.high-memory true;
|
||||||
enforceTor = true;
|
|
||||||
port = 8333;
|
|
||||||
assumevalid = "00000000000000000000e5abc3a74fe27dc0ead9c70ea1deb456f11c15fd7bc6";
|
assumevalid = "00000000000000000000e5abc3a74fe27dc0ead9c70ea1deb456f11c15fd7bc6";
|
||||||
addnodes = [ "ecoc5q34tmbq54wl.onion" ];
|
addnodes = [ "ecoc5q34tmbq54wl.onion" ];
|
||||||
discover = false;
|
discover = false;
|
||||||
addresstype = "bech32";
|
addresstype = "bech32";
|
||||||
dbCache = 1000;
|
dbCache = 1000;
|
||||||
# higher rpcthread count due to reports that lightning implementations fail
|
|
||||||
# under high bitcoind rpc load
|
|
||||||
rpcthreads = 16;
|
|
||||||
};
|
};
|
||||||
services.tor.hiddenServices.bitcoind = mkHiddenService { port = cfg.bitcoind.port; toHost = cfg.bitcoind.bind; };
|
|
||||||
|
|
||||||
# clightning
|
|
||||||
services.clightning.enforceTor = true;
|
|
||||||
services.tor.hiddenServices.clightning = mkIf cfg.clightning.enable (mkHiddenService {
|
|
||||||
port = cfg.clightning.onionport;
|
|
||||||
toHost = cfg.clightning.bind-addr;
|
|
||||||
toPort = cfg.clightning.bindport;
|
|
||||||
});
|
|
||||||
|
|
||||||
# lnd
|
|
||||||
services.lnd.enforceTor = true;
|
|
||||||
services.tor.hiddenServices.lnd = mkIf cfg.lnd.enable (mkHiddenService { port = cfg.lnd.onionport; toHost = cfg.lnd.listen; toPort = cfg.lnd.listenPort; });
|
|
||||||
|
|
||||||
# lightning-loop
|
|
||||||
services.lightning-loop.enforceTor = true;
|
|
||||||
|
|
||||||
# liquidd
|
|
||||||
services.liquidd = {
|
services.liquidd = {
|
||||||
rpcuser = "liquidrpc";
|
|
||||||
prune = 1000;
|
prune = 1000;
|
||||||
validatepegin = true;
|
validatepegin = true;
|
||||||
listen = true;
|
listen = true;
|
||||||
enforceTor = true;
|
|
||||||
port = 7042;
|
|
||||||
};
|
|
||||||
services.tor.hiddenServices.liquidd = mkIf cfg.liquidd.enable (mkHiddenService { port = cfg.liquidd.port; toHost = cfg.liquidd.bind; });
|
|
||||||
|
|
||||||
# electrs
|
|
||||||
services.electrs = {
|
|
||||||
port = 50001;
|
|
||||||
enforceTor = true;
|
|
||||||
};
|
|
||||||
services.tor.hiddenServices.electrs = mkIf cfg.electrs.enable (mkHiddenService {
|
|
||||||
port = cfg.electrs.port; toHost = cfg.electrs.address;
|
|
||||||
});
|
|
||||||
|
|
||||||
# btcpayserver
|
|
||||||
# disable tor enforcement until btcpayserver can fetch rates over Tor
|
|
||||||
services.btcpayserver.enforceTor = false;
|
|
||||||
services.nbxplorer.enforceTor = true;
|
|
||||||
services.tor.hiddenServices.btcpayserver = mkIf cfg.btcpayserver.enable (mkHiddenService { port = 80; toPort = 23000; toHost = cfg.btcpayserver.bind; });
|
|
||||||
|
|
||||||
services.spark-wallet = {
|
|
||||||
onion-service = true;
|
|
||||||
enforceTor = true;
|
|
||||||
};
|
};
|
||||||
|
|
||||||
services.recurring-donations.enforceTor = true;
|
nix-bitcoin.nodeinfo.enable = true;
|
||||||
|
|
||||||
services.nix-bitcoin-webindex.enforceTor = true;
|
services.backups.frequency = "daily";
|
||||||
|
|
||||||
# Backups
|
|
||||||
services.backups = {
|
|
||||||
program = "duplicity";
|
|
||||||
frequency = "daily";
|
|
||||||
};
|
|
||||||
|
|
||||||
environment.systemPackages = with pkgs; [
|
|
||||||
tor
|
|
||||||
jq
|
|
||||||
qrencode
|
|
||||||
];
|
|
||||||
|
|
||||||
services.onion-chef = {
|
|
||||||
enable = true;
|
|
||||||
access.${operatorName} = [ "bitcoind" "clightning" "nginx" "liquidd" "spark-wallet" "electrs" "btcpayserver" "sshd" ];
|
|
||||||
};
|
|
||||||
|
|
||||||
|
# operator
|
||||||
nix-bitcoin.operator.enable = true;
|
nix-bitcoin.operator.enable = true;
|
||||||
users.users.${operatorName} = {
|
users.users.${operatorName} = {
|
||||||
openssh.authorizedKeys.keys = config.users.users.root.openssh.authorizedKeys.keys;
|
openssh.authorizedKeys.keys = config.users.users.root.openssh.authorizedKeys.keys;
|
||||||
|
@ -5,18 +5,17 @@ with lib;
|
|||||||
let
|
let
|
||||||
cfg = config.services.spark-wallet;
|
cfg = config.services.spark-wallet;
|
||||||
inherit (config) nix-bitcoin-services;
|
inherit (config) nix-bitcoin-services;
|
||||||
onion-chef-service = (if cfg.onion-service then [ "onion-chef.service" ] else []);
|
|
||||||
|
|
||||||
# Use wasabi rate provider because the default (bitstamp) doesn't accept
|
# Use wasabi rate provider because the default (bitstamp) doesn't accept
|
||||||
# connections through Tor
|
# connections through Tor
|
||||||
torRateProvider = "--rate-provider wasabi --proxy socks5h://${config.services.tor.client.socksListenAddress}";
|
torRateProvider = "--rate-provider wasabi --proxy socks5h://${config.services.tor.client.socksListenAddress}";
|
||||||
startScript = ''
|
startScript = ''
|
||||||
${optionalString cfg.onion-service ''
|
${optionalString (cfg.getPublicAddressCmd != "") ''
|
||||||
publicURL="--public-url http://$(cat /var/lib/onion-chef/spark-wallet/spark-wallet)"
|
publicURL="--public-url http://$(${cfg.getPublicAddressCmd})"
|
||||||
''}
|
''}
|
||||||
exec ${config.nix-bitcoin.pkgs.spark-wallet}/bin/spark-wallet \
|
exec ${config.nix-bitcoin.pkgs.spark-wallet}/bin/spark-wallet \
|
||||||
--ln-path '${config.services.clightning.networkDir}' \
|
--ln-path '${config.services.clightning.networkDir}' \
|
||||||
--host ${cfg.host} \
|
--host ${cfg.address} --port ${toString cfg.port} \
|
||||||
--config '${config.nix-bitcoin.secretsDir}/spark-wallet-login' \
|
--config '${config.nix-bitcoin.secretsDir}/spark-wallet-login' \
|
||||||
${optionalString cfg.enforceTor torRateProvider} \
|
${optionalString cfg.enforceTor torRateProvider} \
|
||||||
$publicURL \
|
$publicURL \
|
||||||
@ -31,24 +30,31 @@ in {
|
|||||||
If enabled, the spark-wallet service will be installed.
|
If enabled, the spark-wallet service will be installed.
|
||||||
'';
|
'';
|
||||||
};
|
};
|
||||||
host = mkOption {
|
address = mkOption {
|
||||||
type = types.str;
|
type = types.str;
|
||||||
default = "localhost";
|
default = "localhost";
|
||||||
description = "http(s) server listen address.";
|
description = "http(s) server address.";
|
||||||
};
|
};
|
||||||
onion-service = mkOption {
|
port = mkOption {
|
||||||
type = types.bool;
|
type = types.port;
|
||||||
default = false;
|
default = 9737;
|
||||||
description = ''
|
description = "http(s) server port.";
|
||||||
"If enabled, configures spark-wallet to be reachable through an onion service.";
|
|
||||||
'';
|
|
||||||
};
|
};
|
||||||
extraArgs = mkOption {
|
extraArgs = mkOption {
|
||||||
type = types.separatedString " ";
|
type = types.separatedString " ";
|
||||||
default = "";
|
default = "";
|
||||||
description = "Extra command line arguments passed to spark-wallet.";
|
description = "Extra command line arguments passed to spark-wallet.";
|
||||||
};
|
};
|
||||||
enforceTor = nix-bitcoin-services.enforceTor;
|
getPublicAddressCmd = mkOption {
|
||||||
|
type = types.str;
|
||||||
|
default = "";
|
||||||
|
description = ''
|
||||||
|
Bash expression which outputs the public service address.
|
||||||
|
If set, spark-wallet prints a QR code to the systemd journal which
|
||||||
|
encodes an URL for accessing the web interface.
|
||||||
|
'';
|
||||||
|
};
|
||||||
|
inherit (nix-bitcoin-services) enforceTor;
|
||||||
};
|
};
|
||||||
|
|
||||||
config = mkIf cfg.enable {
|
config = mkIf cfg.enable {
|
||||||
@ -61,25 +67,16 @@ in {
|
|||||||
};
|
};
|
||||||
users.groups.spark-wallet = {};
|
users.groups.spark-wallet = {};
|
||||||
|
|
||||||
services.tor.hiddenServices.spark-wallet = mkIf cfg.onion-service {
|
|
||||||
map = [{
|
|
||||||
port = 80; toPort = 9737; toHost = cfg.host;
|
|
||||||
}];
|
|
||||||
version = 3;
|
|
||||||
};
|
|
||||||
services.onion-chef.enable = cfg.onion-service;
|
|
||||||
services.onion-chef.access.spark-wallet = if cfg.onion-service then [ "spark-wallet" ] else [];
|
|
||||||
systemd.services.spark-wallet = {
|
systemd.services.spark-wallet = {
|
||||||
description = "Run spark-wallet";
|
description = "Run spark-wallet";
|
||||||
wantedBy = [ "multi-user.target" ];
|
wantedBy = [ "multi-user.target" ];
|
||||||
requires = [ "clightning.service" ] ++ onion-chef-service;
|
requires = [ "clightning.service" ];
|
||||||
after = [ "clightning.service" ] ++ onion-chef-service;
|
after = [ "clightning.service" ];
|
||||||
script = startScript;
|
script = startScript;
|
||||||
serviceConfig = nix-bitcoin-services.defaultHardening // {
|
serviceConfig = nix-bitcoin-services.defaultHardening // {
|
||||||
User = "spark-wallet";
|
User = "spark-wallet";
|
||||||
Restart = "on-failure";
|
Restart = "on-failure";
|
||||||
RestartSec = "10s";
|
RestartSec = "10s";
|
||||||
ReadWritePaths = mkIf cfg.onion-service "/var/lib/onion-chef";
|
|
||||||
} // (if cfg.enforceTor
|
} // (if cfg.enforceTor
|
||||||
then nix-bitcoin-services.allowTor
|
then nix-bitcoin-services.allowTor
|
||||||
else nix-bitcoin-services.allowAnyIP)
|
else nix-bitcoin-services.allowAnyIP)
|
||||||
|
@ -5,7 +5,19 @@ let
|
|||||||
version = config.nix-bitcoin.configVersion;
|
version = config.nix-bitcoin.configVersion;
|
||||||
|
|
||||||
# Sorted by increasing version numbers
|
# Sorted by increasing version numbers
|
||||||
changes = [
|
changes = let
|
||||||
|
mkOnionServiceChange = service: {
|
||||||
|
version = "0.0.30";
|
||||||
|
condition = config.services.${service}.enable;
|
||||||
|
message = ''
|
||||||
|
The onion service for ${service} has been disabled in the default
|
||||||
|
configuration (`secure-node.nix`).
|
||||||
|
|
||||||
|
To enable the onion service, add the following to your configuration:
|
||||||
|
nix-bitcon.onionServices.${service}.enable = true;
|
||||||
|
'';
|
||||||
|
};
|
||||||
|
in [
|
||||||
{
|
{
|
||||||
version = "0.0.26";
|
version = "0.0.26";
|
||||||
condition = config.services.joinmarket.enable;
|
condition = config.services.joinmarket.enable;
|
||||||
@ -54,6 +66,9 @@ let
|
|||||||
https://github.com/JoinMarket-Org/joinmarket-clientserver/blob/v0.8.0/docs/NATIVE-SEGWIT-UPGRADE.md
|
https://github.com/JoinMarket-Org/joinmarket-clientserver/blob/v0.8.0/docs/NATIVE-SEGWIT-UPGRADE.md
|
||||||
'';
|
'';
|
||||||
}
|
}
|
||||||
|
(mkOnionServiceChange "clightning")
|
||||||
|
(mkOnionServiceChange "lnd")
|
||||||
|
(mkOnionServiceChange "btcpayserver")
|
||||||
];
|
];
|
||||||
|
|
||||||
incompatibleChanges = optionals
|
incompatibleChanges = optionals
|
||||||
@ -76,6 +91,10 @@ let
|
|||||||
lastChange = builtins.elemAt changes (builtins.length changes - 1);
|
lastChange = builtins.elemAt changes (builtins.length changes - 1);
|
||||||
in
|
in
|
||||||
{
|
{
|
||||||
|
imports = [
|
||||||
|
./obsolete-options.nix
|
||||||
|
];
|
||||||
|
|
||||||
options = {
|
options = {
|
||||||
nix-bitcoin.configVersion = mkOption {
|
nix-bitcoin.configVersion = mkOption {
|
||||||
type = with types; nullOr str;
|
type = with types; nullOr str;
|
||||||
@ -93,6 +112,6 @@ in
|
|||||||
|
|
||||||
config = {
|
config = {
|
||||||
# Force evaluation. An actual option value is never assigned
|
# Force evaluation. An actual option value is never assigned
|
||||||
system.extraDependencies = optional (builtins.length incompatibleChanges > 0) (builtins.throw errorMsg);
|
system = optionalAttrs (builtins.length incompatibleChanges > 0) (builtins.throw errorMsg);
|
||||||
};
|
};
|
||||||
}
|
}
|
||||||
|
@ -20,7 +20,5 @@ let self = {
|
|||||||
|
|
||||||
pinned = import ./pinned.nix;
|
pinned = import ./pinned.nix;
|
||||||
|
|
||||||
lib = import ./lib.nix { inherit (pkgs) lib; };
|
|
||||||
|
|
||||||
modulesPkgs = self // self.pinned;
|
modulesPkgs = self // self.pinned;
|
||||||
}; in self
|
}; in self
|
||||||
|
@ -1,5 +0,0 @@
|
|||||||
{ lib }:
|
|
||||||
{
|
|
||||||
# An address type that checks that there's no port
|
|
||||||
ipv4Address = lib.types.addCheck lib.types.str (s: builtins.length (builtins.split ":" s) == 1);
|
|
||||||
}
|
|
@ -44,7 +44,7 @@ let testEnv = rec {
|
|||||||
tests.spark-wallet = cfg.spark-wallet.enable;
|
tests.spark-wallet = cfg.spark-wallet.enable;
|
||||||
|
|
||||||
tests.lnd = cfg.lnd.enable;
|
tests.lnd = cfg.lnd.enable;
|
||||||
services.lnd.listenPort = 9736;
|
services.lnd.port = 9736;
|
||||||
|
|
||||||
tests.lightning-loop = cfg.lightning-loop.enable;
|
tests.lightning-loop = cfg.lightning-loop.enable;
|
||||||
|
|
||||||
@ -68,6 +68,8 @@ let testEnv = rec {
|
|||||||
'';
|
'';
|
||||||
};
|
};
|
||||||
|
|
||||||
|
tests.nodeinfo = config.nix-bitcoin.nodeinfo.enable;
|
||||||
|
|
||||||
tests.backups = cfg.backups.enable;
|
tests.backups = cfg.backups.enable;
|
||||||
|
|
||||||
# To test that unused secrets are made inaccessible by 'setup-secrets'
|
# To test that unused secrets are made inaccessible by 'setup-secrets'
|
||||||
@ -119,6 +121,8 @@ let testEnv = rec {
|
|||||||
services.joinmarket.enable = true;
|
services.joinmarket.enable = true;
|
||||||
services.backups.enable = true;
|
services.backups.enable = true;
|
||||||
|
|
||||||
|
nix-bitcoin.nodeinfo.enable = true;
|
||||||
|
|
||||||
services.hardware-wallets = {
|
services.hardware-wallets = {
|
||||||
trezor = true;
|
trezor = true;
|
||||||
ledger = true;
|
ledger = true;
|
||||||
@ -130,7 +134,6 @@ let testEnv = rec {
|
|||||||
scenarios.full
|
scenarios.full
|
||||||
../modules/presets/secure-node.nix
|
../modules/presets/secure-node.nix
|
||||||
];
|
];
|
||||||
services.nix-bitcoin-webindex.enable = true;
|
|
||||||
tests.secure-node = true;
|
tests.secure-node = true;
|
||||||
tests.banlist-and-restart = true;
|
tests.banlist-and-restart = true;
|
||||||
|
|
||||||
|
@ -216,17 +216,19 @@ def _():
|
|||||||
)
|
)
|
||||||
|
|
||||||
|
|
||||||
|
@test("nodeinfo")
|
||||||
|
def _():
|
||||||
|
status, _ = machine.execute("systemctl is-enabled --quiet onion-addresses 2> /dev/null")
|
||||||
|
if status == 0:
|
||||||
|
machine.wait_for_unit("onion-addresses")
|
||||||
|
json_info = succeed("sudo -u operator nodeinfo")
|
||||||
|
info = json.loads(json_info)
|
||||||
|
assert info["bitcoind"]["local_address"]
|
||||||
|
|
||||||
|
|
||||||
@test("secure-node")
|
@test("secure-node")
|
||||||
def _():
|
def _():
|
||||||
assert_running("onion-chef")
|
assert_running("onion-addresses")
|
||||||
|
|
||||||
# FIXME: use 'wait_for_unit' because 'create-web-index' always fails during startup due
|
|
||||||
# to incomplete unit dependencies.
|
|
||||||
# 'create-web-index' implicitly tests 'nodeinfo'.
|
|
||||||
machine.wait_for_unit("create-web-index")
|
|
||||||
assert_running("nginx")
|
|
||||||
wait_for_open_port(ip("nginx"), 80)
|
|
||||||
assert_matches(f"curl {ip('nginx')}", "nix-bitcoin")
|
|
||||||
|
|
||||||
|
|
||||||
# Run this test before the following tests that shut down services
|
# Run this test before the following tests that shut down services
|
||||||
|
Loading…
Reference in New Issue
Block a user