Merge fort-nix/nix-bitcoin#402: Misc. improvements
6d694a6269
backups: allow extraFiles to override default settings (Erik Arvstedt)0c45415c86
backups: exclude bitcoind, liquidd txindex data (Erik Arvstedt)0853dedc43
tests/regtest: don't fail when restarting bitcoind (Erik Arvstedt)b73c093d3d
joinmarket-ob-watcher: require nix-bitcoin.service (Erik Arvstedt)27905e2c3a
tests: disable restarting joinmarket-ob-watcher (Erik Arvstedt)c8251cdad7
onion-services: don't always enable Tor (Erik Arvstedt)3c6a664b7b
examples/configuration: show how to enable sudo/doas for `operator` (Erik Arvstedt)4d5bc810eb
secrets: fix setup-secrets in case of no secrets (Erik Arvstedt)e61c743644
test: add option `extraTestScript` (Erik Arvstedt)2cf12d8765
README: minor fixes (Erik Arvstedt)e57ab83a51
docs/hardware: update (Erik Arvstedt)1b597f92a6
docs/hardware: add line breaks (Erik Arvstedt)a92d6a8e80
netns: expose bridgeIp as an option (Erik Arvstedt)f36df8f563
secure-node: remove redundant bitcoind settings (Erik Arvstedt)09169365d8
liquid: remove unused features (Erik Arvstedt)82d910e937
nbxplorer: fix bitcoind, liquidd settings (Erik Arvstedt)f61e928139
services: support 0.0.0.0/:: in `address` options (Erik Arvstedt)1848c3dd98
btcpayserver: minor improvements (Erik Arvstedt)e561637600
minor fixes (Erik Arvstedt) Pull request description: ACKs for top commit: nixbitcoin: ACK6d694a6269
jonasnick: ACK6d694a6269
Tree-SHA512: 9a409e05e75284a27b94ef489ab0bce8bf49b50fa01e31c7c3430e388e273e7186f74794b979b625db9cd7ec2861e9933cc93e4c54139314f7f9d54d9b5f39f2
This commit is contained in:
commit
693c646c49
12
README.md
12
README.md
@ -52,7 +52,7 @@ 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 support accepting inbound connections via onion services.
|
* All applications use Tor for outbound connections and support accepting inbound connections via onion services.
|
||||||
|
|
||||||
NixOS modules
|
NixOS modules ([src](modules/modules.nix))
|
||||||
* Application services
|
* Application services
|
||||||
* [bitcoind](https://github.com/bitcoin/bitcoin), with a default banlist against spy nodes
|
* [bitcoind](https://github.com/bitcoin/bitcoin), with a default banlist against spy nodes
|
||||||
* [clightning](https://github.com/ElementsProject/lightning) with support for announcing an onion service\
|
* [clightning](https://github.com/ElementsProject/lightning) with support for announcing an onion service\
|
||||||
@ -85,19 +85,19 @@ NixOS modules
|
|||||||
|
|
||||||
Security
|
Security
|
||||||
---
|
---
|
||||||
* **Simplicity:** Only services you select in `configuration.nix` and their dependencies are installed, packages and dependencies are [pinned](pkgs/nixpkgs-pinned.nix), support for [doas](https://github.com/Duncaen/OpenDoas) ([sudo alternative](https://lobste.rs/s/efsvqu/heap_based_buffer_overflow_sudo_cve_2021#c_c6fcfa)), most packages are built from the [NixOS stable channel](https://github.com/NixOS/nixpkgs/tree/nixos-20.09), with a few exceptions that are built from the nixpkgs unstable channel, builds happen in a [sandboxed environment](https://nixos.org/manual/nix/stable/#conf-sandbox), code is continuously reviewed and refined.
|
* **Simplicity:** Only services enabled in `configuration.nix` and their dependencies are installed, support for [doas](https://github.com/Duncaen/OpenDoas) ([sudo alternative](https://lobste.rs/s/efsvqu/heap_based_buffer_overflow_sudo_cve_2021#c_c6fcfa)), code is continuously reviewed and refined.
|
||||||
* **Integrity:** Nix package manager, NixOS and packages can be built from source to reduce reliance on binary caches, nix-bitcoin merge commits are signed, all commits are approved by multiple nix-bitcoin developers, upstream packages are cryptographically verified where possible, we use this software ourselves.
|
* **Integrity:** The Nix package manager guarantees that all dependencies are exactly specified, packages can be built from source to reduce reliance on binary caches, nix-bitcoin merge commits are signed, all commits are approved by multiple nix-bitcoin developers, upstream packages are cryptographically verified where possible, we use this software ourselves.
|
||||||
* **Principle of Least Privilege:** Services operate with least privileges; they each have their own user and are restricted further with [systemd options](pkgs/lib.nix), [RPC whitelisting](modules/bitcoind-rpc-public-whitelist.nix), and [netns-isolation](modules/netns-isolation.nix). There's a non-root user *operator* to interact with the various services.
|
* **Principle of Least Privilege:** Services operate with least privileges; they each have their own user and are restricted further with [systemd features](pkgs/lib.nix), [RPC whitelisting](modules/bitcoind-rpc-public-whitelist.nix) and [netns-isolation](modules/netns-isolation.nix). There's a non-root user *operator* to interact with the various services.
|
||||||
* **Defense-in-depth:** nix-bitcoin is built with a [hardened kernel](https://github.com/NixOS/nixpkgs/blob/master/nixos/modules/profiles/hardened.nix) by default, services are confined through discretionary access control, Linux namespaces, [dbus firewall](modules/security.nix) and seccomp-bpf with continuous improvements.
|
* **Defense-in-depth:** nix-bitcoin supports a [hardened kernel](https://github.com/NixOS/nixpkgs/blob/master/nixos/modules/profiles/hardened.nix), services are confined through discretionary access control, Linux namespaces, [dbus firewall](modules/security.nix) and seccomp-bpf with continuous improvements.
|
||||||
|
|
||||||
Note that if the machine you're deploying *from* is insecure, there is nothing nix-bitcoin can do to protect itself.
|
Note that if the machine you're deploying *from* is insecure, there is nothing nix-bitcoin can do to protect itself.
|
||||||
|
|
||||||
Docs
|
Docs
|
||||||
---
|
---
|
||||||
* [FAQ](docs/faq.md)
|
|
||||||
* [Hardware Requirements](docs/hardware.md)
|
* [Hardware Requirements](docs/hardware.md)
|
||||||
* [Install instructions](docs/install.md)
|
* [Install instructions](docs/install.md)
|
||||||
* [Usage instructions](docs/usage.md)
|
* [Usage instructions](docs/usage.md)
|
||||||
|
* [FAQ](docs/faq.md)
|
||||||
|
|
||||||
Troubleshooting
|
Troubleshooting
|
||||||
---
|
---
|
||||||
|
@ -1,8 +1,18 @@
|
|||||||
Hardware requirements
|
Hardware requirements
|
||||||
---
|
---
|
||||||
* Disk space: 500 GB (400GB for Bitcoin blockchain + some room)
|
* RAM: 2GB. ECC memory is better. Additionally, it's recommended to use DDR4 memory with
|
||||||
* Bitcoin Core pruning is not supported at the moment because it's not supported by c-lightning. It's possible to use pruning but you need to know what you're doing.
|
targeted row refresh (TRR) enabled (https://rambleed.com/).
|
||||||
* RAM: 2GB of memory. ECC memory is better. Additionally, it's recommended to use DDR4 memory with targeted row refresh (TRR) enabled (https://rambleed.com/).
|
* Disk space: 500 GB (400GB for Bitcoin blockchain + some room) for an unpruned
|
||||||
|
instance of Bitcoin Core.
|
||||||
|
* This can be significantly lowered by enabling pruning.
|
||||||
|
Note: Pruning is not supported by `electrs`.
|
||||||
|
|
||||||
Tested hardware includes [pcengine's apu2c4](https://pcengines.ch/apu2c4.htm), [GB-BACE-3150](https://www.gigabyte.com/Mini-PcBarebone/GB-BACE-3150-rev-10), [GB-BACE-3160](https://www.gigabyte.com/de/Mini-PcBarebone/GB-BACE-3160-rev-10#ov).
|
Tested low-end hardware includes:
|
||||||
Some hardware (including Intel NUCs) may not be compatible with the hardened kernel turned on by default (see https://github.com/fort-nix/nix-bitcoin/issues/39#issuecomment-517366093 for a workaround).
|
- [Raspberry Pi 4](https://www.raspberrypi.org/products/raspberry-pi-4-model-b/)
|
||||||
|
- [PC Engines apu2c4](https://pcengines.ch/apu2c4.htm)
|
||||||
|
- [Gigabyte GB-BACE-3150](https://www.gigabyte.com/Mini-PcBarebone/GB-BACE-3150-rev-10)
|
||||||
|
- [Gigabyte GB-BACE-3160](https://www.gigabyte.com/de/Mini-PcBarebone/GB-BACE-3160-rev-10#ov)
|
||||||
|
|
||||||
|
Some hardware (including Intel NUCs) may not be compatible with the [hardened kernel preset](../modules/presets/hardened.nix)
|
||||||
|
(See https://github.com/fort-nix/nix-bitcoin/issues/39#issuecomment-517366093
|
||||||
|
for a workaround).
|
||||||
|
@ -243,6 +243,10 @@
|
|||||||
openssh.authorizedKeys.keys = [ "" ];
|
openssh.authorizedKeys.keys = [ "" ];
|
||||||
};
|
};
|
||||||
|
|
||||||
|
# FIXME: Uncomment this to allow the operator user to run
|
||||||
|
# commands as root with `sudo` or `doas`
|
||||||
|
# users.users.operator.extraGroups = [ "wheel" ];
|
||||||
|
|
||||||
# FIXME: add packages you need in your system
|
# FIXME: add packages you need in your system
|
||||||
environment.systemPackages = with pkgs; [
|
environment.systemPackages = with pkgs; [
|
||||||
vim
|
vim
|
||||||
@ -261,5 +265,4 @@
|
|||||||
# 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.51";
|
nix-bitcoin.configVersion = "0.0.51";
|
||||||
|
|
||||||
}
|
}
|
||||||
|
@ -40,14 +40,25 @@ let
|
|||||||
|
|
||||||
cfg = config.services.backups;
|
cfg = config.services.backups;
|
||||||
|
|
||||||
filelist = pkgs.writeText "filelist.txt" ''
|
# Potential backup file paths are are matched against filelist
|
||||||
${optionalString (!cfg.with-bulk-data) "- ${config.services.bitcoind.dataDir}/blocks"}
|
# entries from top to bottom.
|
||||||
${optionalString (!cfg.with-bulk-data) "- ${config.services.bitcoind.dataDir}/chainstate"}
|
# The first match determines inclusion or exclusion.
|
||||||
|
filelist = builtins.toFile "filelist.txt" ''
|
||||||
|
${builtins.concatStringsSep "\n" cfg.extraFiles}
|
||||||
|
|
||||||
|
${optionalString (!cfg.with-bulk-data) ''
|
||||||
|
- ${config.services.bitcoind.dataDir}/blocks
|
||||||
|
- ${config.services.bitcoind.dataDir}/chainstate
|
||||||
|
- ${config.services.bitcoind.dataDir}/indexes
|
||||||
|
''}
|
||||||
${config.services.bitcoind.dataDir}
|
${config.services.bitcoind.dataDir}
|
||||||
${config.services.clightning.dataDir}
|
${config.services.clightning.dataDir}
|
||||||
${config.services.lnd.dataDir}
|
${config.services.lnd.dataDir}
|
||||||
${optionalString (!cfg.with-bulk-data) "- ${config.services.liquidd.dataDir}/*/blocks"}
|
${optionalString (!cfg.with-bulk-data) ''
|
||||||
${optionalString (!cfg.with-bulk-data) "- ${config.services.liquidd.dataDir}/*/chainstate"}
|
- ${config.services.liquidd.dataDir}/*/blocks
|
||||||
|
- ${config.services.liquidd.dataDir}/*/chainstate
|
||||||
|
- ${config.services.liquidd.dataDir}/*/indexes
|
||||||
|
''}
|
||||||
${config.services.liquidd.dataDir}
|
${config.services.liquidd.dataDir}
|
||||||
${optionalString cfg.with-bulk-data "${config.services.electrs.dataDir}"}
|
${optionalString cfg.with-bulk-data "${config.services.electrs.dataDir}"}
|
||||||
${config.services.nbxplorer.dataDir}
|
${config.services.nbxplorer.dataDir}
|
||||||
@ -59,9 +70,6 @@ let
|
|||||||
|
|
||||||
${builtins.concatStringsSep "\n" postgresqlBackupPaths}
|
${builtins.concatStringsSep "\n" postgresqlBackupPaths}
|
||||||
|
|
||||||
# Extra files
|
|
||||||
${builtins.concatStringsSep "\n" cfg.extraFiles}
|
|
||||||
|
|
||||||
# Exclude all unspecified files and directories
|
# Exclude all unspecified files and directories
|
||||||
- /
|
- /
|
||||||
'';
|
'';
|
||||||
|
@ -26,7 +26,6 @@ let
|
|||||||
package = mkOption {
|
package = mkOption {
|
||||||
type = types.package;
|
type = types.package;
|
||||||
default = config.nix-bitcoin.pkgs.bitcoind;
|
default = config.nix-bitcoin.pkgs.bitcoind;
|
||||||
defaultText = "pkgs.blockchains.bitcoind";
|
|
||||||
description = "The package providing bitcoin binaries.";
|
description = "The package providing bitcoin binaries.";
|
||||||
};
|
};
|
||||||
extraConfig = mkOption {
|
extraConfig = mkOption {
|
||||||
|
@ -101,23 +101,36 @@ let
|
|||||||
nbLib = config.nix-bitcoin.lib;
|
nbLib = config.nix-bitcoin.lib;
|
||||||
nbPkgs = config.nix-bitcoin.pkgs;
|
nbPkgs = config.nix-bitcoin.pkgs;
|
||||||
|
|
||||||
bitcoind = config.services.bitcoind;
|
inherit (config.services) bitcoind liquidd;
|
||||||
in {
|
in {
|
||||||
inherit options;
|
inherit options;
|
||||||
|
|
||||||
config = mkIf cfg.btcpayserver.enable {
|
config = mkIf cfg.btcpayserver.enable {
|
||||||
services.bitcoind.enable = true;
|
services.bitcoind = {
|
||||||
|
enable = true;
|
||||||
|
rpc.users.btcpayserver = {
|
||||||
|
passwordHMACFromFile = true;
|
||||||
|
rpcwhitelist = cfg.bitcoind.rpc.users.public.rpcwhitelist ++ [
|
||||||
|
"setban"
|
||||||
|
"generatetoaddress"
|
||||||
|
"getpeerinfo"
|
||||||
|
];
|
||||||
|
};
|
||||||
|
# Enable p2p connections
|
||||||
|
listen = true;
|
||||||
|
extraConfig = ''
|
||||||
|
whitelist=${nbLib.address cfg.nbxplorer.address}
|
||||||
|
'';
|
||||||
|
};
|
||||||
services.clightning.enable = mkIf (cfg.btcpayserver.lightningBackend == "clightning") true;
|
services.clightning.enable = mkIf (cfg.btcpayserver.lightningBackend == "clightning") true;
|
||||||
services.lnd.enable = mkIf (cfg.btcpayserver.lightningBackend == "lnd") true;
|
services.lnd.enable = mkIf (cfg.btcpayserver.lightningBackend == "lnd") true;
|
||||||
services.liquidd.enable = mkIf cfg.btcpayserver.lbtc true;
|
services.liquidd = mkIf cfg.btcpayserver.lbtc {
|
||||||
|
enable = true;
|
||||||
services.bitcoind.rpc.users.btcpayserver = {
|
# Enable p2p connections
|
||||||
passwordHMACFromFile = true;
|
listen = true;
|
||||||
rpcwhitelist = cfg.bitcoind.rpc.users.public.rpcwhitelist ++ [
|
extraConfig = ''
|
||||||
"setban"
|
whitelist=${nbLib.address cfg.nbxplorer.address}
|
||||||
"generatetoaddress"
|
'';
|
||||||
"getpeerinfo"
|
|
||||||
];
|
|
||||||
};
|
};
|
||||||
|
|
||||||
services.lnd.macaroons.btcpayserver = mkIf (cfg.btcpayserver.lightningBackend == "lnd") {
|
services.lnd.macaroons.btcpayserver = mkIf (cfg.btcpayserver.lightningBackend == "lnd") {
|
||||||
@ -143,15 +156,15 @@ in {
|
|||||||
configFile = builtins.toFile "config" ''
|
configFile = builtins.toFile "config" ''
|
||||||
network=${bitcoind.network}
|
network=${bitcoind.network}
|
||||||
btcrpcuser=${cfg.bitcoind.rpc.users.btcpayserver.name}
|
btcrpcuser=${cfg.bitcoind.rpc.users.btcpayserver.name}
|
||||||
btcrpcurl=http://${bitcoind.rpc.address}:${toString cfg.bitcoind.rpc.port}
|
btcrpcurl=http://${nbLib.addressWithPort bitcoind.rpc.address cfg.bitcoind.rpc.port}
|
||||||
btcnodeendpoint=${bitcoind.address}:${toString bitcoind.port}
|
btcnodeendpoint=${nbLib.addressWithPort bitcoind.address bitcoind.port}
|
||||||
bind=${cfg.nbxplorer.address}
|
bind=${cfg.nbxplorer.address}
|
||||||
port=${toString cfg.nbxplorer.port}
|
port=${toString cfg.nbxplorer.port}
|
||||||
${optionalString cfg.btcpayserver.lbtc ''
|
${optionalString cfg.btcpayserver.lbtc ''
|
||||||
chains=btc,lbtc
|
chains=btc,lbtc
|
||||||
lbtcrpcuser=${cfg.liquidd.rpcuser}
|
lbtcrpcuser=${liquidd.rpcuser}
|
||||||
lbtcrpcurl=http://${cfg.liquidd.rpc.address}:${toString cfg.liquidd.rpc.port}
|
lbtcrpcurl=http://${nbLib.addressWithPort liquidd.rpc.address liquidd.rpc.port}
|
||||||
lbtcnodeendpoint=${cfg.liquidd.address}:${toString cfg.liquidd.port}
|
lbtcnodeendpoint=${nbLib.addressWithPort liquidd.address liquidd.port}
|
||||||
''}
|
''}
|
||||||
'';
|
'';
|
||||||
in {
|
in {
|
||||||
@ -221,8 +234,8 @@ in {
|
|||||||
'';
|
'';
|
||||||
serviceConfig = nbLib.defaultHardening // {
|
serviceConfig = nbLib.defaultHardening // {
|
||||||
ExecStart = ''
|
ExecStart = ''
|
||||||
${cfg.btcpayserver.package}/bin/btcpayserver --conf=${cfg.btcpayserver.dataDir}/settings.config \
|
${cfg.btcpayserver.package}/bin/btcpayserver --conf='${cfg.btcpayserver.dataDir}/settings.config' \
|
||||||
--datadir=${cfg.btcpayserver.dataDir}
|
--datadir='${cfg.btcpayserver.dataDir}'
|
||||||
'';
|
'';
|
||||||
User = cfg.btcpayserver.user;
|
User = cfg.btcpayserver.user;
|
||||||
Restart = "on-failure";
|
Restart = "on-failure";
|
||||||
@ -236,7 +249,7 @@ in {
|
|||||||
isSystemUser = true;
|
isSystemUser = true;
|
||||||
group = cfg.nbxplorer.group;
|
group = cfg.nbxplorer.group;
|
||||||
extraGroups = [ "bitcoinrpc-public" ]
|
extraGroups = [ "bitcoinrpc-public" ]
|
||||||
++ optional cfg.btcpayserver.lbtc cfg.liquidd.group;
|
++ optional cfg.btcpayserver.lbtc liquidd.group;
|
||||||
home = cfg.nbxplorer.dataDir;
|
home = cfg.nbxplorer.dataDir;
|
||||||
};
|
};
|
||||||
users.groups.${cfg.nbxplorer.group} = {};
|
users.groups.${cfg.nbxplorer.group} = {};
|
||||||
|
@ -112,9 +112,10 @@ in
|
|||||||
ExecStart = ''
|
ExecStart = ''
|
||||||
${config.nix-bitcoin.pkgs.charge-lnd}/bin/charge-lnd \
|
${config.nix-bitcoin.pkgs.charge-lnd}/bin/charge-lnd \
|
||||||
--lnddir ${dataDir}/lnddir-proxy \
|
--lnddir ${dataDir}/lnddir-proxy \
|
||||||
--grpc ${lnd.rpcAddress}:${toString lnd.rpcPort} \
|
--grpc ${nbLib.addressWithPort lnd.rpcAddress lnd.rpcPort} \
|
||||||
--config ${checkedConfig} \
|
--config ${checkedConfig} \
|
||||||
${optionalString (electrs != null) "--electrum-server ${electrs.address}:${toString electrs.port}"} \
|
${optionalString (electrs != null)
|
||||||
|
"--electrum-server ${nbLib.addressWithPort electrs.address electrs.port}"} \
|
||||||
${escapeShellArgs cfg.extraFlags}
|
${escapeShellArgs cfg.extraFlags}
|
||||||
'';
|
'';
|
||||||
Type = "oneshot";
|
Type = "oneshot";
|
||||||
|
@ -7,7 +7,7 @@ let
|
|||||||
address = mkOption {
|
address = mkOption {
|
||||||
type = types.str;
|
type = types.str;
|
||||||
default = "127.0.0.1";
|
default = "127.0.0.1";
|
||||||
description = "IP address or UNIX domain socket to listen for peer connections.";
|
description = "Address to listen for peer connections.";
|
||||||
};
|
};
|
||||||
port = mkOption {
|
port = mkOption {
|
||||||
type = types.port;
|
type = types.port;
|
||||||
@ -84,7 +84,7 @@ let
|
|||||||
${optionalString (cfg.proxy != null) "proxy=${cfg.proxy}"}
|
${optionalString (cfg.proxy != null) "proxy=${cfg.proxy}"}
|
||||||
always-use-proxy=${boolToString cfg.always-use-proxy}
|
always-use-proxy=${boolToString cfg.always-use-proxy}
|
||||||
bind-addr=${cfg.address}:${toString cfg.port}
|
bind-addr=${cfg.address}:${toString cfg.port}
|
||||||
bitcoin-rpcconnect=${config.services.bitcoind.rpc.address}
|
bitcoin-rpcconnect=${nbLib.address 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
|
||||||
|
@ -96,7 +96,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.rpc.address}:${toString bitcoind.rpc.port} \
|
--daemon-rpc-addr=${nbLib.addressWithPort bitcoind.rpc.address bitcoind.rpc.port} \
|
||||||
${cfg.extraArgs}
|
${cfg.extraArgs}
|
||||||
'';
|
'';
|
||||||
User = cfg.user;
|
User = cfg.user;
|
||||||
|
@ -93,10 +93,10 @@ in {
|
|||||||
"d '${cfg.dataDir}' 0770 ${cfg.user} ${cfg.group} - -"
|
"d '${cfg.dataDir}' 0770 ${cfg.user} ${cfg.group} - -"
|
||||||
];
|
];
|
||||||
|
|
||||||
systemd.services.joinmarket-ob-watcher = {
|
systemd.services.joinmarket-ob-watcher = rec {
|
||||||
wantedBy = [ "multi-user.target" ];
|
wantedBy = [ "multi-user.target" ];
|
||||||
requires = [ "tor.service" ];
|
requires = [ "tor.service" "bitcoind.service" ];
|
||||||
after = [ "tor.service" ];
|
after = requires;
|
||||||
# The service writes to HOME/.config/matplotlib
|
# The service writes to HOME/.config/matplotlib
|
||||||
environment.HOME = cfg.dataDir;
|
environment.HOME = cfg.dataDir;
|
||||||
preStart = ''
|
preStart = ''
|
||||||
|
@ -124,7 +124,7 @@ let
|
|||||||
[BLOCKCHAIN]
|
[BLOCKCHAIN]
|
||||||
blockchain_source = bitcoin-rpc
|
blockchain_source = bitcoin-rpc
|
||||||
network = ${bitcoind.network}
|
network = ${bitcoind.network}
|
||||||
rpc_host = ${bitcoind.rpc.address}
|
rpc_host = ${nbLib.address 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}
|
||||||
${optionalString (cfg.rpcWalletFile != null) "rpc_wallet_file = ${cfg.rpcWalletFile}"}
|
${optionalString (cfg.rpcWalletFile != null) "rpc_wallet_file = ${cfg.rpcWalletFile}"}
|
||||||
|
@ -50,7 +50,7 @@ let
|
|||||||
cli = mkOption {
|
cli = mkOption {
|
||||||
default = pkgs.writeScriptBin "loop" ''
|
default = pkgs.writeScriptBin "loop" ''
|
||||||
${cfg.package}/bin/loop \
|
${cfg.package}/bin/loop \
|
||||||
--rpcserver ${rpclisten} \
|
--rpcserver ${nbLib.addressWithPort cfg.rpcAddress cfg.rpcPort} \
|
||||||
--macaroonpath '${cfg.dataDir}/${network}/loop.macaroon' \
|
--macaroonpath '${cfg.dataDir}/${network}/loop.macaroon' \
|
||||||
--tlscertpath '${secretsDir}/loop-cert' "$@"
|
--tlscertpath '${secretsDir}/loop-cert' "$@"
|
||||||
'';
|
'';
|
||||||
@ -66,17 +66,16 @@ let
|
|||||||
lnd = config.services.lnd;
|
lnd = config.services.lnd;
|
||||||
|
|
||||||
network = config.services.bitcoind.network;
|
network = config.services.bitcoind.network;
|
||||||
rpclisten = "${cfg.rpcAddress}:${toString cfg.rpcPort}";
|
|
||||||
configFile = builtins.toFile "loop.conf" ''
|
configFile = builtins.toFile "loop.conf" ''
|
||||||
datadir=${cfg.dataDir}
|
datadir=${cfg.dataDir}
|
||||||
network=${network}
|
network=${network}
|
||||||
rpclisten=${rpclisten}
|
rpclisten=${cfg.rpcAddress}:${toString cfg.rpcPort}
|
||||||
restlisten=${cfg.restAddress}:${toString cfg.restPort}
|
restlisten=${cfg.restAddress}:${toString cfg.restPort}
|
||||||
logdir=${cfg.dataDir}/logs
|
logdir=${cfg.dataDir}/logs
|
||||||
tlscertpath=${secretsDir}/loop-cert
|
tlscertpath=${secretsDir}/loop-cert
|
||||||
tlskeypath=${secretsDir}/loop-key
|
tlskeypath=${secretsDir}/loop-key
|
||||||
|
|
||||||
lnd.host=${lnd.rpcAddress}:${toString lnd.rpcPort}
|
lnd.host=${nbLib.addressWithPort lnd.rpcAddress lnd.rpcPort}
|
||||||
lnd.macaroonpath=${lnd.networkDir}/admin.macaroon
|
lnd.macaroonpath=${lnd.networkDir}/admin.macaroon
|
||||||
lnd.tlspath=${lnd.certPath}
|
lnd.tlspath=${lnd.certPath}
|
||||||
|
|
||||||
|
@ -50,7 +50,7 @@ let
|
|||||||
cli = mkOption {
|
cli = mkOption {
|
||||||
default = pkgs.writeScriptBin "pool" ''
|
default = pkgs.writeScriptBin "pool" ''
|
||||||
exec ${cfg.package}/bin/pool \
|
exec ${cfg.package}/bin/pool \
|
||||||
--rpcserver ${rpclisten} \
|
--rpcserver ${nbLib.addressWithPort cfg.rpcAddress cfg.rpcPort} \
|
||||||
--network ${network} \
|
--network ${network} \
|
||||||
--basedir '${cfg.dataDir}' "$@"
|
--basedir '${cfg.dataDir}' "$@"
|
||||||
'';
|
'';
|
||||||
@ -65,9 +65,8 @@ let
|
|||||||
lnd = config.services.lnd;
|
lnd = config.services.lnd;
|
||||||
|
|
||||||
network = config.services.bitcoind.network;
|
network = config.services.bitcoind.network;
|
||||||
rpclisten = "${cfg.rpcAddress}:${toString cfg.rpcPort}";
|
|
||||||
configFile = builtins.toFile "pool.conf" ''
|
configFile = builtins.toFile "pool.conf" ''
|
||||||
rpclisten=${rpclisten}
|
rpclisten=${cfg.rpcAddress}:${toString cfg.rpcPort}
|
||||||
restlisten=${cfg.restAddress}:${toString cfg.restPort}
|
restlisten=${cfg.restAddress}:${toString cfg.restPort}
|
||||||
${optionalString (cfg.proxy != null) "proxy=${cfg.proxy}"}
|
${optionalString (cfg.proxy != null) "proxy=${cfg.proxy}"}
|
||||||
|
|
||||||
|
@ -143,7 +143,6 @@ let
|
|||||||
|
|
||||||
bitcoind = config.services.bitcoind;
|
bitcoind = config.services.bitcoind;
|
||||||
|
|
||||||
pidFile = "${cfg.dataDir}/liquidd.pid";
|
|
||||||
configFile = pkgs.writeText "elements.conf" ''
|
configFile = pkgs.writeText "elements.conf" ''
|
||||||
chain=${bitcoind.makeNetworkName "liquidv1" ''
|
chain=${bitcoind.makeNetworkName "liquidv1" ''
|
||||||
regtest
|
regtest
|
||||||
@ -169,18 +168,13 @@ let
|
|||||||
rpcconnect=${cfg.rpc.address}
|
rpcconnect=${cfg.rpc.address}
|
||||||
${lib.concatMapStrings (rpcallowip: "rpcallowip=${rpcallowip}\n") cfg.rpcallowip}
|
${lib.concatMapStrings (rpcallowip: "rpcallowip=${rpcallowip}\n") cfg.rpcallowip}
|
||||||
rpcuser=${cfg.rpcuser}
|
rpcuser=${cfg.rpcuser}
|
||||||
mainchainrpchost=${bitcoind.rpc.address}
|
mainchainrpchost=${nbLib.address bitcoind.rpc.address}
|
||||||
mainchainrpcport=${toString bitcoind.rpc.port}
|
mainchainrpcport=${toString bitcoind.rpc.port}
|
||||||
mainchainrpcuser=${bitcoind.rpc.users.public.name}
|
mainchainrpcuser=${bitcoind.rpc.users.public.name}
|
||||||
|
|
||||||
# Extra config options (from liquidd nixos service)
|
# Extra config options (from liquidd nixos service)
|
||||||
${cfg.extraConfig}
|
${cfg.extraConfig}
|
||||||
'';
|
'';
|
||||||
cmdlineOptions = concatMapStringsSep " " (arg: "'${arg}'") [
|
|
||||||
"-datadir=${cfg.dataDir}"
|
|
||||||
"-pid=${pidFile}"
|
|
||||||
];
|
|
||||||
hexStr = types.strMatching "[0-9a-f]+";
|
|
||||||
rpcUserOpts = { name, ... }: {
|
rpcUserOpts = { name, ... }: {
|
||||||
options = {
|
options = {
|
||||||
name = mkOption {
|
name = mkOption {
|
||||||
@ -234,8 +228,7 @@ in {
|
|||||||
Type = "simple";
|
Type = "simple";
|
||||||
User = cfg.user;
|
User = cfg.user;
|
||||||
Group = cfg.group;
|
Group = cfg.group;
|
||||||
ExecStart = "${nbPkgs.elementsd}/bin/elementsd ${cmdlineOptions}";
|
ExecStart = "${nbPkgs.elementsd}/bin/elementsd -datadir='${cfg.dataDir}'";
|
||||||
PIDFile = pidFile;
|
|
||||||
Restart = "on-failure";
|
Restart = "on-failure";
|
||||||
ReadWritePaths = cfg.dataDir;
|
ReadWritePaths = cfg.dataDir;
|
||||||
} // nbLib.allowedIPAddresses cfg.enforceTor;
|
} // nbLib.allowedIPAddresses cfg.enforceTor;
|
||||||
|
@ -41,7 +41,7 @@ in {
|
|||||||
services.tor = {
|
services.tor = {
|
||||||
enable = true;
|
enable = true;
|
||||||
relay.onionServices.lnd-rest = nbLib.mkOnionService {
|
relay.onionServices.lnd-rest = nbLib.mkOnionService {
|
||||||
target.addr = lnd.restAddress;
|
target.addr = nbLib.address lnd.restAddress;
|
||||||
target.port = lnd.restPort;
|
target.port = lnd.restPort;
|
||||||
port = lnd.restPort;
|
port = lnd.restPort;
|
||||||
};
|
};
|
||||||
|
@ -127,7 +127,7 @@ let
|
|||||||
|
|
||||||
bitcoind = config.services.bitcoind;
|
bitcoind = config.services.bitcoind;
|
||||||
|
|
||||||
bitcoindRpcAddress = bitcoind.rpc.address;
|
bitcoindRpcAddress = nbLib.address bitcoind.rpc.address;
|
||||||
networkDir = cfg.networkDir;
|
networkDir = cfg.networkDir;
|
||||||
configFile = pkgs.writeText "lnd.conf" ''
|
configFile = pkgs.writeText "lnd.conf" ''
|
||||||
datadir=${cfg.dataDir}
|
datadir=${cfg.dataDir}
|
||||||
@ -217,11 +217,13 @@ in {
|
|||||||
# existing, but the RPC service isn't yet, which results in error
|
# existing, but the RPC service isn't yet, which results in error
|
||||||
# "waiting to start, RPC services not available".
|
# "waiting to start, RPC services not available".
|
||||||
curl = "${pkgs.curl}/bin/curl -s --show-error --retry 10 --cacert ${cfg.certPath}";
|
curl = "${pkgs.curl}/bin/curl -s --show-error --retry 10 --cacert ${cfg.certPath}";
|
||||||
restUrl = "https://${cfg.restAddress}:${toString cfg.restPort}/v1";
|
restUrl = "https://${nbLib.addressWithPort cfg.restAddress cfg.restPort}/v1";
|
||||||
in [
|
in [
|
||||||
(nbLib.script "lnd-create-wallet" ''
|
(nbLib.script "lnd-create-wallet" ''
|
||||||
attempts=250
|
attempts=250
|
||||||
while ! { exec 3>/dev/tcp/${cfg.restAddress}/${toString cfg.restPort} && exec 3>&-; } &>/dev/null; do
|
while ! {
|
||||||
|
exec 3>/dev/tcp/${nbLib.address 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
|
||||||
|
@ -18,9 +18,9 @@
|
|||||||
./lightning-loop.nix
|
./lightning-loop.nix
|
||||||
./lightning-pool.nix
|
./lightning-pool.nix
|
||||||
./charge-lnd.nix
|
./charge-lnd.nix
|
||||||
./btcpayserver.nix
|
|
||||||
./electrs.nix
|
./electrs.nix
|
||||||
./liquid.nix
|
./liquid.nix
|
||||||
|
./btcpayserver.nix
|
||||||
./joinmarket.nix
|
./joinmarket.nix
|
||||||
./joinmarket-ob-watcher.nix
|
./joinmarket-ob-watcher.nix
|
||||||
./hardware-wallets.nix
|
./hardware-wallets.nix
|
||||||
|
@ -47,6 +47,12 @@ let
|
|||||||
readOnly = true;
|
readOnly = true;
|
||||||
description = "Exposes netns parameters.";
|
description = "Exposes netns parameters.";
|
||||||
};
|
};
|
||||||
|
|
||||||
|
bridgeIp = mkOption {
|
||||||
|
default = bridgeIp;
|
||||||
|
readOnly = true;
|
||||||
|
description = "IP of the netns bridge interface.";
|
||||||
|
};
|
||||||
};
|
};
|
||||||
|
|
||||||
cfg = config.nix-bitcoin.netns-isolation;
|
cfg = config.nix-bitcoin.netns-isolation;
|
||||||
|
@ -16,7 +16,7 @@ with lib;
|
|||||||
|
|
||||||
torClientAddressWithPort = mkOption {
|
torClientAddressWithPort = mkOption {
|
||||||
readOnly = true;
|
readOnly = true;
|
||||||
default = with config.services.tor.client.socksListenAddress;
|
default = with config.services.tor.client.socksListenAddress;
|
||||||
"${addr}:${toString port}";
|
"${addr}:${toString port}";
|
||||||
};
|
};
|
||||||
|
|
||||||
|
@ -13,6 +13,7 @@ let
|
|||||||
};
|
};
|
||||||
|
|
||||||
cfg = config.nix-bitcoin.nodeinfo;
|
cfg = config.nix-bitcoin.nodeinfo;
|
||||||
|
nbLib = config.nix-bitcoin.lib;
|
||||||
|
|
||||||
# Services included in the output
|
# Services included in the output
|
||||||
services = {
|
services = {
|
||||||
@ -96,7 +97,7 @@ let
|
|||||||
mkInfo = extraCode: name: cfg:
|
mkInfo = extraCode: name: cfg:
|
||||||
''
|
''
|
||||||
add_service("${name}", """
|
add_service("${name}", """
|
||||||
info["local_address"] = "${cfg.address}:${toString cfg.port}"
|
info["local_address"] = "${nbLib.addressWithPort cfg.address cfg.port}"
|
||||||
'' + mkIfOnionPort name (onionPort: ''
|
'' + mkIfOnionPort name (onionPort: ''
|
||||||
set_onion_address(info, "${name}", ${onionPort})
|
set_onion_address(info, "${name}", ${onionPort})
|
||||||
'') + extraCode + ''
|
'') + extraCode + ''
|
||||||
|
@ -43,18 +43,18 @@ let
|
|||||||
cfg = config.nix-bitcoin.onionServices;
|
cfg = config.nix-bitcoin.onionServices;
|
||||||
nbLib = config.nix-bitcoin.lib;
|
nbLib = config.nix-bitcoin.lib;
|
||||||
|
|
||||||
services = builtins.attrNames cfg;
|
onionServices = builtins.attrNames cfg;
|
||||||
|
|
||||||
activeServices = builtins.filter (service:
|
activeServices = builtins.filter (service:
|
||||||
config.services.${service}.enable && cfg.${service}.enable
|
config.services.${service}.enable && cfg.${service}.enable
|
||||||
) services;
|
) onionServices;
|
||||||
|
|
||||||
publicServices = builtins.filter (service: cfg.${service}.public) activeServices;
|
publicServices = builtins.filter (service: cfg.${service}.public) activeServices;
|
||||||
in {
|
in {
|
||||||
inherit options;
|
inherit options;
|
||||||
|
|
||||||
config = mkMerge [
|
config = mkMerge [
|
||||||
(mkIf (cfg != {}) {
|
(mkIf (activeServices != []) {
|
||||||
# Define hidden services
|
# Define hidden services
|
||||||
services.tor = {
|
services.tor = {
|
||||||
enable = true;
|
enable = true;
|
||||||
@ -65,7 +65,7 @@ in {
|
|||||||
in nbLib.mkOnionService {
|
in nbLib.mkOnionService {
|
||||||
port = if externalPort != null then externalPort else service.port;
|
port = if externalPort != null then externalPort else service.port;
|
||||||
target.port = service.port;
|
target.port = service.port;
|
||||||
target.addr = if service.address == "0.0.0.0" then "127.0.0.1" else service.address;
|
target.addr = nbLib.address service.address;
|
||||||
}
|
}
|
||||||
);
|
);
|
||||||
};
|
};
|
||||||
@ -93,7 +93,7 @@ in {
|
|||||||
publicServices' = builtins.filter (service:
|
publicServices' = builtins.filter (service:
|
||||||
let srv = cfg.${service};
|
let srv = cfg.${service};
|
||||||
in srv.public && srv.enable
|
in srv.public && srv.enable
|
||||||
) services;
|
) onionServices;
|
||||||
in genAttrs publicServices' (service: {
|
in genAttrs publicServices' (service: {
|
||||||
getPublicAddressCmd = "cat ${config.nix-bitcoin.onionAddresses.dataDir}/services/${service}";
|
getPublicAddressCmd = "cat ${config.nix-bitcoin.onionAddresses.dataDir}/services/${service}";
|
||||||
});
|
});
|
||||||
|
@ -36,8 +36,6 @@ in {
|
|||||||
enable = true;
|
enable = true;
|
||||||
listen = true;
|
listen = true;
|
||||||
dataDirReadableByGroup = mkIf cfg.electrs.high-memory true;
|
dataDirReadableByGroup = mkIf cfg.electrs.high-memory true;
|
||||||
discover = false;
|
|
||||||
addresstype = "bech32";
|
|
||||||
dbCache = 1000;
|
dbCache = 1000;
|
||||||
};
|
};
|
||||||
|
|
||||||
|
@ -13,7 +13,8 @@ let
|
|||||||
type = types.bool;
|
type = types.bool;
|
||||||
default = false;
|
default = false;
|
||||||
description = ''
|
description = ''
|
||||||
Set permissions for existing secrets in `nix-bitcoin.secretsDir`.
|
Set permissions for existing secrets in `nix-bitcoin.secretsDir`
|
||||||
|
before services are started.
|
||||||
'';
|
'';
|
||||||
};
|
};
|
||||||
|
|
||||||
@ -21,7 +22,7 @@ let
|
|||||||
type = types.bool;
|
type = types.bool;
|
||||||
default = false;
|
default = false;
|
||||||
description = ''
|
description = ''
|
||||||
Automatically generate all required secrets at system startup.
|
Automatically generate all required secrets before services are started.
|
||||||
Note: Make sure to create a backup of the generated secrets.
|
Note: Make sure to create a backup of the generated secrets.
|
||||||
'';
|
'';
|
||||||
};
|
};
|
||||||
@ -57,7 +58,7 @@ let
|
|||||||
};
|
};
|
||||||
permissions = mkOption {
|
permissions = mkOption {
|
||||||
type = str;
|
type = str;
|
||||||
default = "0440";
|
default = "440";
|
||||||
};
|
};
|
||||||
};
|
};
|
||||||
}
|
}
|
||||||
@ -204,7 +205,9 @@ in {
|
|||||||
}
|
}
|
||||||
|
|
||||||
# Make all other files accessible to root only
|
# Make all other files accessible to root only
|
||||||
unprocessedFiles=$(comm -23 <(printf '%s\n' *) <(printf '%s\n' "''${processedFiles[@]}" | sort))
|
unprocessedFiles=$(
|
||||||
|
comm -23 <(shopt -s nullglob; printf '%s\n' *) <(printf '%s\n' "''${processedFiles[@]}")
|
||||||
|
)
|
||||||
if [[ $unprocessedFiles ]]; then
|
if [[ $unprocessedFiles ]]; then
|
||||||
IFS=$'\n'
|
IFS=$'\n'
|
||||||
chown root: $unprocessedFiles
|
chown root: $unprocessedFiles
|
||||||
|
13
pkgs/lib.nix
13
pkgs/lib.nix
@ -83,4 +83,17 @@ let self = {
|
|||||||
map = [ map ];
|
map = [ map ];
|
||||||
version = 3;
|
version = 3;
|
||||||
};
|
};
|
||||||
|
|
||||||
|
# Convert a bind address, which may be a special INADDR_ANY address,
|
||||||
|
# to an actual IP address
|
||||||
|
address = addr:
|
||||||
|
if addr == "0.0.0.0" then
|
||||||
|
"127.0.0.1"
|
||||||
|
else if addr == "::" then
|
||||||
|
"::1"
|
||||||
|
else
|
||||||
|
addr;
|
||||||
|
|
||||||
|
addressWithPort = addr: port: "${self.address addr}:${toString port}";
|
||||||
|
|
||||||
}; in self
|
}; in self
|
||||||
|
@ -42,6 +42,7 @@ name: testConfig:
|
|||||||
builtins.concatStringsSep "\n\n" [
|
builtins.concatStringsSep "\n\n" [
|
||||||
initData
|
initData
|
||||||
(builtins.readFile ./../tests.py)
|
(builtins.readFile ./../tests.py)
|
||||||
|
cfg.test.extraTestScript
|
||||||
# Don't run tests in interactive mode.
|
# Don't run tests in interactive mode.
|
||||||
# is_interactive is set in ../run-tests.sh
|
# is_interactive is set in ../run-tests.sh
|
||||||
''
|
''
|
||||||
|
@ -19,7 +19,11 @@ with lib;
|
|||||||
dictionary variable 'test_data'. The data is exported via JSON.
|
dictionary variable 'test_data'. The data is exported via JSON.
|
||||||
'';
|
'';
|
||||||
};
|
};
|
||||||
|
extraTestScript = mkOption {
|
||||||
|
type = types.lines;
|
||||||
|
default = "";
|
||||||
|
description = "Extra lines added to the Python test script.";
|
||||||
|
};
|
||||||
container = {
|
container = {
|
||||||
# Forwarded to extra-container. For descriptions, see
|
# Forwarded to extra-container. For descriptions, see
|
||||||
# https://github.com/erikarvstedt/extra-container/blob/master/eval-config.nix
|
# https://github.com/erikarvstedt/extra-container/blob/master/eval-config.nix
|
||||||
|
@ -98,6 +98,10 @@ let
|
|||||||
txfee = 200;
|
txfee = 200;
|
||||||
};
|
};
|
||||||
|
|
||||||
|
# Disable restarting joinmarket-ob-watcher because it always fails
|
||||||
|
# on non-synced mainnet nodes
|
||||||
|
systemd.services.joinmarket-ob-watcher.serviceConfig.Restart = mkForce "no";
|
||||||
|
|
||||||
tests.nodeinfo = config.nix-bitcoin.nodeinfo.enable;
|
tests.nodeinfo = config.nix-bitcoin.nodeinfo.enable;
|
||||||
|
|
||||||
tests.backups = cfg.backups.enable;
|
tests.backups = cfg.backups.enable;
|
||||||
@ -225,7 +229,8 @@ let
|
|||||||
services.bitcoind.regtest = true;
|
services.bitcoind.regtest = true;
|
||||||
systemd.services.bitcoind.postStart = mkAfter ''
|
systemd.services.bitcoind.postStart = mkAfter ''
|
||||||
cli=${config.services.bitcoind.cli}/bin/bitcoin-cli
|
cli=${config.services.bitcoind.cli}/bin/bitcoin-cli
|
||||||
$cli createwallet "test"
|
# Don't fail when wallet already exists
|
||||||
|
$cli createwallet "test" || true
|
||||||
address=$($cli getnewaddress)
|
address=$($cli getnewaddress)
|
||||||
$cli generatetoaddress 10 $address
|
$cli generatetoaddress 10 $address
|
||||||
'';
|
'';
|
||||||
|
Loading…
Reference in New Issue
Block a user