Run nodeinfo
to see onion addresses and local addresses for enabled services.
NixOS uses the systemd service manager.
Usage:
# Show service status
systemctl status bitcoind
# Show the last 100 log messages
journalctl -u bitcoind -n 100
# Show all log messages since the last system boot
journalctl -b -u bitcoind
# These commands require root permissions
systemctl stop bitcoind
systemctl start bitcoind
systemctl restart bitcoind
# Show the service definition
systemctl cat bitcoind
# Show all service parameters
systemctl show bitcoind
The clightning database can be replicated to a local path
or to a remote SSH target.
When remote replication is enabled, nix-bitcoin mounts a SSHFS to a local path.
Optionally, backups can be encrypted via gocryptfs
.
Note: You should also backup the static file hsm_secret
(located at
/var/lib/clightning/bitcoin/hsm_secret
by default), either manually
or via the services.backups
module.
-
Add this to your
configuration.nix
:services.clightning.replication = { enable = true; sshfs.destination = "user@hostname:directory"; # This is optional encrypt = true; }; programs.ssh.knownHosts."hostname".publicKey = "<ssh public key from running `ssh-keyscan` on the host>";
Leave out the
encrypt
line if you want to store data on your destination in plaintext.
Adjustuser
,hostname
anddirectory
as necessary. -
Deploy
-
To allow SSH access from the nix-bitcoin node to the target node, either use the remote node config below, or copy the contents of
$secretsDir/clightning-replication-ssh.pub
to theauthorized_keys
file ofuser
(or usessh-copy-id
). -
You can restrict the nix-bitcoin node's capabilities on the SSHFS target using OpenSSH's builtin features, as detailed here.
To implement this on NixOS, add the following to the NixOS configuration of the SSHFS target node:
systemd.tmpfiles.rules = [ # Because this directory is chrooted by sshd, it must only be writable by user/group root "d /var/backup/nb-replication 0755 root root - -" "d /var/backup/nb-replication/writable 0700 nb-replication - - -" ]; services.openssh = { extraConfig = '' Match user nb-replication ChrootDirectory /var/backup/nb-replication AllowTcpForwarding no AllowAgentForwarding no ForceCommand internal-sftp PasswordAuthentication no X11Forwarding no ''; }; users.users.nb-replication = { isSystemUser = true; group = "nb-replication"; shell = "${pkgs.coreutils}/bin/false"; openssh.authorizedKeys.keys = [ "<contents of $secretsDir/clightning-replication-ssh.pub>" ]; }; users.groups.nb-replication = {};
With this setup, the corresponding
sshfs.destination
on the nix-bitcoin node is"nb-replication@hostname:writable"
.
-
Add this to your
configuration.nix
services.clightning.replication = { enable = true; local.directory = "/var/backup/clightning"; encrypt = true; };
Leave out the
encrypt
line if you want to store data inlocal.directory
in plaintext. -
Deploy
clightning will now replicate database files to local.directory
. This
can be used to replicate to an external HDD by mounting it at path
local.directory
.
Follow the steps in section "Local directory target" above and mount a custom remote
destination (e.g., a NFS or SMB share) to local.directory
.
You might want to disable local.setupDirectory
in order to create the mount directory
yourself with custom permissions.
Normally you would connect to RTL via SSH tunneling with a command like this
ssh -L 3000:127.0.0.1:3000 root@bitcoin-node
Or like this, if you are using netns-isolation
ssh -L 3000:169.254.1.29:3000 root@bitcoin-node
Otherwise, you can access it via Tor Browser at http://<onion-address>
.
You can find the <onion-address>
with command nodeinfo
.
The default password location is $secretsDir/rtl-password
.
See: Secrets dir
-
Install Zeus (version ≥ 0.9.0)
-
Edit your
configuration.nix
Add the following config:
services.lnd.lndconnect = { enable = true; onion = true; };
Add the following config:
services.clightning.plugins.clnrest = { enable = true; lnconnect = { enable = true; onion = true; }; };
-
Deploy your configuration
-
Run the following command on your node (as user
operator
) to create a QR code with address and authentication information:lndconnect
lnconnect-clnrest
-
Configure Zeus
- Add a new node and scan the QR code
- Click
Save node config
- Start sending and stacking sats privately
- Create a plain text URL:
lndconnect --url
- Set a custom host. By default,
lndconnect
detects the system's external IP and uses it as the host.lndconnect --host myhost
Connecting Zeus directly to your node is much faster than using Tor, but a bit more complex to setup.
There are two ways to establish a secure, direct connection:
-
Connecting via TLS. This requires installing your lightning app's TLS Certificate on your mobile device.
-
Connecting via WireGuard. This approach is simpler and more versatile, and is described in this guide.
-
Install Zeus (version ≥ 0.9.0) and WireGuard on your mobile device.
-
Add the following to your
configuration.nix
:imports = [ # Use this line when using the default deployment method <nix-bitcoin/modules/presets/wireguard.nix> # Use this line when using Flakes (nix-bitcoin + /modules/presets/wireguard.nix) ] # For lnd services.lnd.lndconnect.enable = true; # For clightning services.clightning = { plugins.clnrest = { enable = true; lnconnect.enable = true; }; };
-
Deploy your configuration.
-
If your node is behind an external firewall or NAT (e.g. a router), add the following port forwarding rule to the external device:
- Port: 51820 (the default value of option
networking.wireguard.interfaces.wg-nb.listenPort
) - Protocol: UDP
- Destination: IP of your node
- Port: 51820 (the default value of option
-
Setup WireGuard on your mobile device.
Run the following command on your node (as user
operator
) to create a QR code for WireGuard:nix-bitcoin-wg-connect # For debugging: Show the WireGuard config as text nix-bitcoin-wg-connect --text
The above commands automatically detect your node's external IP.
To set a custom IP or hostname, run the following:nix-bitcoin-wg-connect 93.184.216.34 nix-bitcoin-wg-connect mynode.org
Configure WireGuard:
- Press the
+
button in the bottom right corner - Scan the QR code
- Add the tunnel
- Press the
-
Setup Zeus
Run the following command on your node (as user
operator
) to create a QR code for Zeus:lndconnect-wg
lnconnect-clnrest-wg
Configure Zeus:
- Add a new node and scan the QR code
- Click
Save node config
- On the certificate warning screen, click
I understand, save node config
.
Certificates are not needed when connecting via WireGuard. - Start sending and stacking sats privately
Create a plain text URL:
lndconnect-wg --url
- Android phone
- Orbot installed from F-Droid (recommended) or Google Play
- Electrum mobile app 4.0.1 and newer installed from direct download or Google Play
- Tor installed from source or repository
- Electrum installed
-
Enable electrs in
configuration.nix
Change
# services.electrs.enable = true;
to
services.electrs.enable = true;
-
Deploy new
configuration.nix
-
Get electrs onion address with format
<onion-address>:<port>
nodeinfo | jq -r .electrs.onion_address
-
Connect to electrs
Make sure Tor is running on Desktop or as Orbot on Android.
On Desktop
electrum --oneserver -1 -s "<electrs onion address>:t" -p socks5:127.0.0.1:9050
On Android
Three dots in the upper-right-hand corner Network > Proxy mode: socks5, Host: 127.0.0.1, Port: 9050 Network > Auto-connect: OFF Network > One-server mode: ON Network > Server: <electrs onion address>:t
-
Get the SSH onion address (excluding the port suffix)
ssh operator@bitcoin-node nodeinfo | jq -r .sshd.onion_address | sed 's/:.*//'
-
Create a SSH key
ssh-keygen -t ed25519 -f ~/.ssh/id_ed25519
-
Place the ed25519 key's fingerprint in the
configuration.nix
openssh.authorizedKeys.keys
field like so# FIXME: Add your SSH pubkey services.openssh.enable = true; users.users.root = { openssh.authorizedKeys.keys = [ "<contents of ~/.ssh/id_ed25519.pub>" ]; };
-
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>:127.0.0.1:22 root@<SSH onion address>
-
Edit your deployment tool's configuration and change the node's address to
127.0.0.1
and the ssh port to<random port of your choosing>
. If you use krops as described in the installation tutorial, settarget = "127.0.0.1:<random port of your choosing>";
inkrops/deploy.nix
. -
After deploying the new configuration, it will connect through the SSH tunnel you established in step iv. This also allows you to do more complex SSH setups that some deployment tools don't support. An example would be authenticating with Trezor's SSH agent, which provides extra security.
-
Enable Trezor in
configuration.nix
Change
# services.hardware-wallets.trezor = true;
to
services.hardware-wallets.trezor = true;
-
Deploy new
configuration.nix
-
Check that your nix-bitcoin node recognizes your Trezor
ssh operator@bitcoin-node lsusb
Should show something relating to your Trezor
-
If your Trezor has outdated firmware or is not yet initialized: Start your Trezor in bootloader mode
Trezor v1
Plug in your Trezor with both buttons depressed
Trezor v2
Start swiping your finger across your Trezor's touchscreen and plug in the USB cable when your finger is halfway through
-
If your Trezor's firmware is outdated: Update your Trezor's firmware
trezorctl firmware-update
Follow the on-screen instructions
Caution: This command will wipe your Trezor. If you already store Bitcoin on it, only do this with the recovery seed nearby.
-
If your Trezor is not yet initialized: Set up your Trezor
trezorctl reset-device -p
Follow the on-screen instructions
-
Find your Trezor
hwi enumerate hwi -t trezor -d <path from previous command> promptpin hwi -t trezor -d <path> sendpin <number positions for the PIN as displayed on your device's screen> hwi enumerate
-
Follow Bitcoin Core's instructions on Using Bitcoin Core with Hardware Wallets to use your Trezor with
bitcoin-cli
on your nix-bitcoin node
For clarity reasons, nix-bitcoin renames all scripts to jm-*
without .py
, for
example wallet-tool.py
becomes jm-wallet-tool
. The rest of this section
details nix-bitcoin specific workflows for JoinMarket.
By default, a wallet is automatically generated at service startup.
It's stored at /var/lib/joinmarket/wallets/wallet.jmdat
, and its mnmenoic recovery
seed phrase is stored at /var/lib/joinmarket/jm-wallet-seed
.
A missing wallet file is automatically recreated if the seed file is still present.
If you want to manually initialize your wallet instead, follow these steps:
-
Enable JoinMarket in your node configuration
services.joinmarket.enable = true;
-
Move the automatically generated
wallet.jmdat
mv /var/lib/joinmarket/wallet.jmdat /var/lib/joinmarket/bak.jmdat
-
Generate wallet on your node
jm-wallet-tool generate
Follow the on-screen instructions and write down your seed.
In order to use nix-bitcoin's
joinmarket.yieldgenerator
, use the password from$secretsDir/jm-wallet-password
and use the suggested default wallet namewallet.jmdat
. If you want to use your ownjm-wallet-password
, simply replace the password string in your local secrets directory. See: Secrets dir
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.
-
Add screen to your
environment.systemPackages
, for exampleenvironment.systemPackages = with pkgs; [ vim screen ];
-
Start the screen session
screen -S "tumbler"
-
Start the tumbler
Example: Tumbling into your wallet after buying from an exchange to improve privacy:
jm-tumbler wallet.jmdat <addr1> <addr2> <addr3>
After tumbling your bitcoin end up in these three addresses. You can now spend them without the exchange collecting data on your purchases.
Get more information here
-
Detach the screen session to leave the tumbler running in the background
Ctrl-a d or Ctrl-a Ctrl-d
-
Re-attach to the screen session
screen -r tumbler
-
End screen session
Type exit when tumbler is done
exit
The maker/yield generator in nix-bitcoin is implemented using a systemd service.
See here for more yield generator information.
-
Enable yield generator bot in your node configuration
services.joinmarket.yieldgenerator = { enable = true; # Optional: Add custom parameters cjfee_a = 300; cjfee_r = 0.00003; }; '';
-
Check service status
systemctl status joinmarket-yieldgenerator
-
Profit
There is a number of plugins available for clightning.
See Readme: Features → clightning
or search.nixos.org for a complete list.
You can activate and configure these plugins like so:
services.clightning = {
enable = true;
plugins = {
clboss.enable = true;
clboss.min-onchain = 40000;
};
};
Please have a look at the module for a plugin (e.g. clboss.nix) to learn its configuration options.
When services.clightning.tor.proxy
is enabled, trustedcoin
also uses Tor for all external connections by default.
In this case, connections to block explorers can sometimes get blocked.
An example of clightning log error output when connections are getting blocked:
lightningd[5138]: plugin-trustedcoin estimatefees error: https://blockstream.info/api error: 403 Forbidden
lightningd[4933]: plugin-trustedcoin getblock error: got something that isn't a block hash: <html><head>...
To work around this and connect via clearnet instead, set this option:
services.clightning.plugins.trustedcoin.tor.proxy = false;