diff --git a/hosts/by-name/servo/services/cryptocurrencies/bitcoin.nix b/hosts/by-name/servo/services/cryptocurrencies/bitcoin.nix index 21e3dbe9..ee107b27 100644 --- a/hosts/by-name/servo/services/cryptocurrencies/bitcoin.nix +++ b/hosts/by-name/servo/services/cryptocurrencies/bitcoin.nix @@ -30,6 +30,13 @@ # see docs at top of file for how to generate this passwordHMAC = "30002c05d82daa210550e17a182db3f3$6071444151281e1aa8a2729f75e3e2d224e9d7cac3974810dab60e7c28ffaae4"; }; + extraConfig = '' + # don't load the wallet, and disable wallet RPC calls + disablewallet=1 + # TODO: configure tor integration + # proxy=127.0.0.1:9050 + # externalip=$(cat /var/lib/tor/onion/bitcoind/hostname) + ''; }; sane.users.colin.fs.".bitcoin/bitcoin.conf" = sane-lib.fs.wantedSymlinkTo config.sops.secrets."bitcoin.conf".path; diff --git a/hosts/by-name/servo/services/cryptocurrencies/clightning.nix b/hosts/by-name/servo/services/cryptocurrencies/clightning.nix index 0ddecbd6..6b0dd4b0 100644 --- a/hosts/by-name/servo/services/cryptocurrencies/clightning.nix +++ b/hosts/by-name/servo/services/cryptocurrencies/clightning.nix @@ -1,9 +1,16 @@ # clightning is an implementation of Bitcoin's Lightning Network. # as such, this assumes that `services.bitcoin` is enabled. +# docs: +# - tor clightning config: # # management/setup/use: # - guide: # - `sudo -u clightning -g clightning lightning-cli help` +# +# first, acquire peers: +# - `lightning-cli listpeers` +# +# sanity: # - `lightning-cli listfunds` # # to receive a payment (do as `clightning` user): @@ -23,13 +30,34 @@ "befcb82d9821049164db5217beb85439$2c31ac7db3124612e43893ae13b9527dbe464ab2d992e814602e7cb07dc28985"; sane.services.clightning.enable = true; + sane.services.clightning.proxy = "127.0.0.1:9050"; # proxy outgoing traffic through tor + # sane.services.clightning.publicAddress = "statictor:127.0.0.1:9051"; + sane.services.clightning.getPublicAddressCmd = "cat /var/lib/tor/onion/clightning/hostname"; + + services.tor.relay.onionServices.clightning = { + version = 3; + map = [{ + # by default tor will route public tor port P to 127.0.0.1:P. + # so if this port is the same as clightning would natively use, then no further config is needed here. + # see: + port = 9735; + # target.port; target.addr; #< set if tor port != clightning port + }]; + # allow "tor" group (i.e. clightning) to read /var/lib/tor/onion/clightning/hostname + settings.HiddenServiceDirGroupReadable = true; + }; + + # must be in "tor" group to read /var/lib/tor/onion/*/hostname + users.users.clightning.extraGroups = [ "tor" ]; + + systemd.services.clightning.after = [ "tor.service" ]; + sane.services.clightning.extraConfigFiles = [ config.sops.secrets."lightning-config".path ]; sops.secrets."lightning-config" = { mode = "0600"; owner = "clightning"; group = "clightning"; }; - sane.services.clightning.proxy = "127.0.0.1:9050"; # tor sane.programs.clightning.enableFor.user.colin = true; # put `lightning-cli` onto PATH } diff --git a/hosts/by-name/servo/services/cryptocurrencies/tor.nix b/hosts/by-name/servo/services/cryptocurrencies/tor.nix index e50352e4..927f7b74 100644 --- a/hosts/by-name/servo/services/cryptocurrencies/tor.nix +++ b/hosts/by-name/servo/services/cryptocurrencies/tor.nix @@ -1,8 +1,22 @@ -{ ... }: +# tor settings: +{ lib, ... }: { + # tor hidden service hostnames aren't deterministic, so persist. + # might be able to get away with just persisting /var/lib/tor/onion, not sure. + sane.persist.sys.byStore.plaintext = [ + { user = "tor"; group = "tor"; mode = "0710"; path = "/var/lib/tor"; } + ]; + # tor: `tor.enable` doesn't start a relay, exit node, proxy, etc. it's minimal. # tor.client.enable configures a torsocks proxy, accessible *only* to localhost. # at 127.0.0.1:9050 services.tor.enable = true; services.tor.client.enable = true; + + # in order for services to read /var/lib/tor/onion/*/hostname, they must be able to traverse /var/lib/tor, + # and /var/lib/tor must have g+x. + # DataDirectoryGroupReadable causes tor to use g+rx, technically more than we need, but all the files are 600 so it's fine. + services.tor.settings.DataDirectoryGroupReadable = true; + # StateDirectoryMode defaults to 0700, and thereby prevents the onion hostnames from being group readable + systemd.services.tor.serviceConfig.StateDirectoryMode = lib.mkForce "0710"; } diff --git a/modules/services/clightning.nix b/modules/services/clightning.nix index 14768c8d..4f50439d 100644 --- a/modules/services/clightning.nix +++ b/modules/services/clightning.nix @@ -18,6 +18,7 @@ let network=bitcoin bitcoin-datadir=${bitcoind.dataDir} ${lib.optionalString (cfg.proxy != null) "proxy=${cfg.proxy}"} + ${lib.optionalString (cfg.publicAddress != null) "addr=${cfg.publicAddress}"} always-use-proxy=${lib.boolToString cfg.always-use-proxy} bind-addr=${cfg.address}:${toString cfg.port} bitcoin-rpcconnect=127.0.0.1 @@ -68,6 +69,28 @@ in default = "127.0.0.1"; description = mdDoc "Address to listen for peer connections."; }; + publicAddress = mkOption { + type = types.nullOr types.str; + default = null; + description = '' + address to publish to peers. + leaving this empty will prevent incoming connections and channels, but it should still be possible to create outgoing channels. + + formats: + - statictor:: + creates a tor hidden service based on this node's pubkey, which remains constant across reboots. + ''; + example = "statictor:127.0.0.1:9051"; + }; + getPublicAddressCmd = mkOption { + type = types.nullOr types.str; + default = null; + description = mdDoc '' + Bash expression which outputs the public service address to announce to peers. + this is an alternative to the `publicAddress` option, for if the address is not known statically (e.g. tor). + ''; + }; + port = mkOption { type = types.port; default = 9735; @@ -140,7 +163,12 @@ in rm -f ${cfg.networkDir}/lightning-rpc umask u=rw,g=r,o= - cat ${configFile} ${lib.concatStringsSep " " cfg.extraConfigFiles} > ${cfg.dataDir}/config + { + cat ${configFile} ${lib.concatStringsSep " " cfg.extraConfigFiles} + ${lib.optionalString (cfg.getPublicAddressCmd != null) '' + echo "announce-addr=$(${cfg.getPublicAddressCmd}):${builtins.toString cfg.port}" + ''} + } > ${cfg.dataDir}/config ''; # Wait until the rpc socket appears postStart = ''