Keyboard shortcuts

Press ← or → to navigate between chapters

Press S or / to search in the book

Press ? to show this help

Press Esc to hide this help

Upgrading

Some releases contain changes that need manual action, such as a removed service, a changed default or a required reindex. bitcoinix reports them when it evaluates your configuration: if a change is newer than nix-bitcoin.configVersion and affects your configuration, evaluation fails with a short description of the change. Options of removed services fail evaluation regardless of the config version.

Keep nix-bitcoin.configVersion set in your configuration. If it is unset, these changes are not reported.

When evaluation fails after an update, follow the sections below for each version newer than your config version, starting with the oldest. Then set nix-bitcoin.configVersion to the version named in the error message.

Updating bitcoinix

With a flake-based deployment, verify the new release tag as in step 3 of the installation, set it in flake.nix, run nix flake lock and check the locked commit as in step 4.2. Then deploy.

With krops, run update-nix-bitcoin from the deployment shell.
This fetches the latest release, verifies the signature on its release tag and updates nix-bitcoin-release.nix.
It refuses to switch to a release older than the one currently pinned. To downgrade on purpose, run fetch-release.sh with releaseVersion=<version> and write its output to nix-bitcoin-release.nix.

Upgrading to config version 0.1.5

Currencyrate, rebalance, clnrest and mempool’s settings.CORE_RPC.PASSWORD each have a migration notice. Review the changes for each one you use before updating your config version.

The clnrest package has moved from nix-bitcoin.pkgs.clnrest to nix-bitcoin.pkgs.clightning-plugins.clnrest. Update explicit package references in custom configurations. For flake builds, use '.#packages.aarch64-linux.clightning-plugins/clnrest' (or x86_64-linux) instead of '.#packages.aarch64-linux.clnrest'. The default package is selected automatically. The migration notice also applies when RTL enables clnrest automatically. If you have no custom package references, this rename requires no manual changes.

The Python currencyrate plugin has been replaced by Rust cln-currencyrate. Keep services.clightning.plugins.currencyrate.enable = true, but update any custom scripts before deploying:

  • Replace currencyrates <currency> with listcurrencyrates <currency>. The response is now {"currencyrates": [{"source": "…", "amount": 95000.0}, …]}, with amounts in fiat per BTC, replacing the map of source names to msat per fiat unit. Adapt both parsing and units. currencyrate <currency> returns a single median rate in fiat per BTC.
  • currencyconvert still takes amount and currency, for example lightning-cli currencyconvert 10 USD, but its msat result is now a JSON number rather than a string with an msat suffix. The median is now calculated from fiat prices before conversion.
  • Rename add-source and disable-source in services.clightning.extraConfig to currencyrate-add-source and currencyrate-disable-source. Review them against the new plugin’s README. The plugin follows CLN’s configured proxy.

After deploying, check that lightning-cli help currencyconvert and lightning-cli help listcurrencyrates list the new RPCs. A live conversion such as lightning-cli currencyconvert 100 USD also needs reachable price sources.

The rebalance plugin now uses Core Lightning’s askrene routing. If you enable services.clightning.plugins.rebalance.enable, update custom scripts and configuration before deploying:

  • Remove the getroute_method argument from rebalance RPC calls; it is no longer accepted.
  • Remove rebalance-getroute, rebalance-maxhops and rebalance-msatfactor from services.clightning.extraConfig and any included configuration files. These settings are still accepted with a deprecation warning but are ignored, so they no longer control route selection or hop limits.
  • Update scripts that read rebalancereport: its getroute_method, maxhops_threshold and msatfactor fields have been removed.

mempool no longer accepts services.mempool.settings.CORE_RPC.PASSWORD. Its settings are copied to the world-readable Nix store, so evaluation now fails when this option is set. Remove it and save the password to bitcoin-rpcpassword-public in the secrets dir. mempool reads it from there at startup, also when it uses bitcoind from another node. The old value stays readable in the Nix store until it is garbage-collected, so change the password if untrusted users or services run on the node.

After addressing these changes, set nix-bitcoin.configVersion = "0.1.5";.

Upgrading to config version 0.1.3

Bitcoin Knots support and the services.bitcoind.package option have been removed. Remove services.bitcoind.package from your configuration, including explicit selections of Bitcoin Core. The daemon, bitcoin-cli and Core Lightning now use nix-bitcoin.pkgs.bitcoind (Bitcoin Core) directly. bitcoind-knots is no longer included in bitcoinix’s pinned packages. If you used Knots, review any Knots-specific settings in services.bitcoind.extraConfig before deploying with Bitcoin Core.

electrs 0.12.0 switched to bindex, which uses a new index format. electrs must rebuild its index from scratch, and it does not convert or delete the old one, so bitcoinix refuses to start electrs while the old index is in place. Reindexing takes from a few hours to about a day, depending on your hardware. The final index is about 7% of the size of bitcoind’s blocks/*.dat files and can temporarily grow to about 14% during the initial sync. electrs accepts connections while it indexes but answers with incomplete history and balances until indexing has finished. The same applies to mempool if it uses electrs as its Electrum server.

To upgrade, delete the old index before deploying (default data dir shown; for regtest, the index is in regtest instead of bitcoin):

systemctl stop electrs
rm -r /var/lib/electrs/bitcoin

Then deploy the new system config to your node and follow the progress with journalctl -u electrs -f.

If you roll back to the previous config after electrs 0.12 has started once, also remove the marker file /var/lib/electrs/bitcoin.bindex. Otherwise the index check is skipped on the next upgrade.

electrs 0.12.0 also requires Bitcoin Core 31 or later. It reads blocks through bitcoind’s REST interface, which bitcoinix enables automatically (services.bitcoind.rest.enable). REST is served without authentication on the RPC address and port: every source allowed by services.bitcoind.rpc.allowip can read blocks, transactions, the UTXO set and the mempool, bypassing RPC users and rpcwhitelist. If services.bitcoind.rpc.allowip contains sources other than localhost and bitcoinix’s network namespaces, evaluation fails. Remove them, or set services.bitcoind.rest.allowNonLocal = true to accept unauthenticated REST access for these sources. Evaluation also fails if services.bitcoind.extraConfig contains rpcallowip or includeconf directives: move RPC sources to services.bitcoind.rpc.allowip, or review the raw and included settings and set services.bitcoind.rest.allowUncheckedConfig = true. electrs no longer connects to bitcoind’s whitelisted P2P port.

Services using nix-bitcoin.lib.defaultHardening, including Bitcoin Core, Core Lightning and LND, now see /run and /dev (including /dev/shm) as read-only. Before deploying, review custom service hooks (preStart, postStart, ExecStartPre, ExecStartPost) and plugins that write there: they can now fail with Read-only file system.

The service’s RuntimeDirectory, StateDirectory, configured data directory and existing ReadWritePaths remain writable. Move custom writes into those directories, or add a narrow ReadWritePaths exception for an existing path that must remain writable. See Write to /run or /dev/shm from a service hook for an example. If you have no custom code writing outside the allowed directories, no script changes are needed.

mempool 3.3 migrates its MariaDB database from schema version 97 to 106 on the first start of the backend. The migration can’t be undone: rolling back the NixOS generation keeps the migrated database, and mempool 3.2 has no downgrade path. The database is not covered by services.backups. To keep a way back, dump it before deploying:

mysqldump --single-transaction mempool > mempool-3.2.sql

Run this as root, and replace mempool if you set services.mempool.database.name.

setup-secrets now runs in a sandbox whenever nix-bitcoin.setupSecrets is enabled, including when nix-bitcoin.generateSecrets enables it automatically. Before deploying:

  • Replace declared secret symlinks to files outside nix-bitcoin.secretsDir with files inside that directory, preserving their contents. If another tool supplies or rotates these secrets, configure it to install the files there before setup-secrets starts. External targets are read-only or hidden inside the sandbox.
  • Review custom nix-bitcoin.generateSecretsCmds. They have no IP network access and can write only to the secrets directory and private temporary directories. Put final secret files in the secrets directory. Commands requiring writable executable memory (such as JIT compilation) or setuid/setgid file modes are blocked. If generation needs these facilities, arrange to supply all required secrets before setup-secrets, set nix-bitcoin.generateSecrets = false, and keep nix-bitcoin.setupSecrets = true to set the supplied files’ permissions.
  • Remove setuid/setgid bits from any nix-bitcoin.secrets.<name>.permissions values; the sandbox rejects those modes when setting permissions too.

The secrets directory is now root:root 0700 while setup runs even when generateSecrets is false. If any step fails, every service loses access to secrets in that directory until setup succeeds. After fixing the cause reported by journalctl -u setup-secrets, run as root:

systemctl reset-failed setup-secrets
systemctl restart setup-secrets
systemctl start nix-bitcoin-secrets.target

Then restart any dependent services that failed. Successful setup restores the directory to 0751 and applies each declared secret’s configured owner and mode.

After migrating your configuration, set nix-bitcoin.configVersion = "0.1.3";.

Upgrading to config version 0.1.2

bitcoind’s RPC authentication cookie now lives at /run/bitcoind/.cookie for both mainnet and regtest. The runtime directory allows the bitcoind service group to read the cookie while preventing group members from replacing it.

Update external RPC clients and scripts that read /var/lib/bitcoind/.cookie or /var/lib/bitcoind/regtest/.cookie to use /run/bitcoind/.cookie. If you set services.bitcoind.dataDir, the old cookie was under that directory instead. For clients running in containers or filesystem sandboxes, update any bind mounts or allowed paths for cookie access as well.

The bitcoin-cli installed by bitcoinix reads the new path from bitcoin.conf automatically. Services configured by bitcoinix use RPC credentials and need no cookie path changes.

An old cookie can remain in the data directory after an unclean shutdown before the upgrade. Once the upgraded bitcoind is running, that old cookie is stale and can be removed. bitcoind creates a new cookie in /run/bitcoind each time it starts.

The mempool backend now listens on services.mempool.address (default 127.0.0.1) instead of all interfaces. With network namespace isolation enabled, it listens on its namespace address. Access through the nginx frontend is unchanged. If you access the backend API directly from another host, set services.mempool.address to the node’s LAN or VPN address.

The MariaDB server enabled by mempool now listens on 127.0.0.1 by default. mempool itself uses MariaDB’s Unix socket and needs no connection changes. If other clients access this database server over the network, explicitly set services.mysql.settings.mysqld.bind-address to the desired listen address. Existing explicit values of this option take precedence over the new default.

LND now restarts automatically after a clean exit, so it can recover after its chain backend health check shuts it down. By default, lncli stop also causes LND to restart after 10 seconds. To keep LND stopped for maintenance, use sudo systemctl stop lnd and update any scripts that relied on lncli stop leaving it down. Start it again with sudo systemctl start lnd when maintenance is complete.

BTCPay Server 2.4.5 blocks outbound requests to private network addresses by default to prevent server-side request forgery. This affects webhooks, invoice notification URLs and LNURL requests that point to localhost, LAN or VPN addresses. The Lightning node that bitcoinix configures for BTCPay Server is unaffected. To allow specific private destinations, list them in BTCPay’s ssrfexceptions setting:

systemd.services.btcpayserver.environment.BTCPAY_SSRFEXCEPTIONS = "192.168.1.50:8443;10.8.0.0/24";

Entries are exact hostnames, IP addresses or CIDR ranges, optionally with a port, separated by ; or ,.

Keep each exception as narrow as possible: one address with its port, or the smallest range that covers the destination. Never list the ports of node services such as the LND REST API or the bitcoind RPC. Anyone who can set a webhook, a notification URL or a Lightning address in BTCPay can make it send requests to every listed destination. A hostname entry trusts every address the hostname resolves to, so list only hostnames whose DNS you control.

After updating any affected clients and settings, set nix-bitcoin.configVersion = "0.1.2";.

Upgrading to config version 0.1.1

Liquid support has been removed, including the Elements daemon, liquid-swap, and BTCPay Server’s LBTC integration. Liquid peg-outs were suspended after the September 2026 Elements consensus bug (incident assessment).

If you used Liquid, remove services.liquidd, services.btcpayserver.lbtc, and any Liquid-specific onion service or network namespace settings from your configuration.

Upgrading does not delete Liquid data. These files stay on the node:

  • the data directory (default: /var/lib/liquidd), which holds your Liquid wallets
  • the secret liquid-rpcpassword in the secrets directory (default: /etc/nix-bitcoin-secrets)
  • the onion service keys in /var/lib/tor/onion/liquidd, if Liquid had an onion service (the default with the secure-node.nix preset)

The backups service no longer includes the data directory. To keep backing up the wallets without the chain data (as before, unless with-bulk-data was set), add:

services.backups.extraFiles = [
  "- /var/lib/liquidd/*/blocks"
  "- /var/lib/liquidd/*/chainstate"
  "- /var/lib/liquidd/*/indexes"
  "/var/lib/liquidd"
];

To access the wallets later, run upstream Elements Core 23.3.4 or later on a copy of the data directory. Earlier versions, including the elementsd package in nixpkgs 26.05, lack the fix for that bug. Delete the files above once you no longer need them.

The netns-exec wrapper has been removed. Its namespace allowlist had been empty since JoinMarket was removed, so it rejected every namespace. To run a command in a service network namespace, use sudo ip netns exec nb-<service> <command>. If you set nix-bitcoin.netns-isolation.allowedUser, remove it from your configuration.

Lightning Pool and Lightning Loop support, including RTL’s Loop integration, has also been removed. Remove services.lightning-pool, services.lightning-loop, services.rtl.nodes.lnd.loop, and any Pool- or Loop-specific onion service or network namespace settings from your configuration.

If you still need either service, arrange a separately managed deployment before upgrading. The services stop running after the upgrade, and their packages and CLI wrappers are no longer installed by bitcoinix. Existing data directories (default: /var/lib/lightning-pool and /var/lib/lightning-loop) and Loop secrets (loop-key and loop-cert in the secrets directory) are retained. Keep these files for the separately managed deployment.

Before upgrading, make sure no Loop swap is in progress (loop listswaps). Once a Loop Out has revealed its preimage, its sweep must confirm before the HTLC expires, otherwise the swap amount is lost. Pool account funds stay locked until the account expires; to recover them, run poold with the retained data directory.

BTCPay Server’s wallet UTXO scan is now disabled by default. The btcpayserver RPC user no longer has permission to call scantxoutset, because a scan can keep bitcoind busy for minutes. If you use this feature, explicitly restore permission:

services.bitcoind.rpc.users.btcpayserver.rpcwhitelist = [ "scantxoutset" ];

If you do not use wallet UTXO scanning, leave it disabled and acknowledge the change by updating the config version below.

The charge-lnd macaroon now grants read access and write access only to UpdateChannelPolicy and UpdateChanStatus. The previous broad offchain:write grant also allowed sending payments and abandoning channels. LND regenerates /run/lnd/charge-lnd.macaroon with the restricted permissions when it restarts during deployment. Regeneration does not revoke old copies: they remain valid with their original permissions. Do not reuse them. If another application used this macaroon, give it a separate macaroon with the permissions it needs via services.lnd.macaroons.

lnconnect-clnrest now includes clnrest’s server certificate (server.pem) in direct connection URLs. Previously it included the mutual-TLS client certificate (client.pem), which did not match the certificate presented by clnrest. Regenerate direct connection URLs and reconnect clients. Tor and WireGuard URLs use --nocert and are unaffected.

c-lightning-REST support has been removed because it is no longer maintained. Remove services.clightning-rest (or the legacy services.rtl.cl-rest) and any associated onion service or network namespace settings from your configuration. Use the clnrest plugin for Core Lightning’s REST API:

services.clightning = {
  enable = true;
  plugins.clnrest = {
    enable = true;
    # Optional: connection helper and access via Tor
    lnconnect = {
      enable = true;
      onion = true;
    };
  };
};

clnrest uses runes for authentication instead of c-lightning-REST macaroons and listens on port 3010 by default. Reconnect clients using lnconnect-clnrest instead of lndconnect-clightning, or lnconnect-clnrest-wg instead of lndconnect-clightning-wg with the WireGuard preset. See connecting via Tor and connecting via WireGuard. RTL already uses clnrest and enables it automatically for its Core Lightning node.

Custom API clients must switch to POST /v1/<rpc-method> with JSON parameters and handle native Core Lightning RPC responses. The convenience endpoints getBalance, getFees, and channel/localRemoteBal are gone; calculate their summaries from listfunds, getinfo, and listpeerchannels. The old /v1/ws protocol is also replaced by clnrest’s notification streaming. See the upstream migration guide.

clnrest runs within clightning.service and shares Core Lightning’s network namespace and sandbox. There is no separate REST service or API-specific Tor enforcement setting. services.clightning.tor.enforce applies to both; the WireGuard preset disables enforcement for that service to allow connections over the tunnel.

Swagger documentation is served on the REST API port at /, instead of a separate docPort. If you used extraConfig.DOMAIN for a custom certificate hostname, supply suitable certificates with the clnrest-certs option through services.clightning.extraConfig. When using a custom certificate directory, pass --tlscertpath=/path/to/certs/server.pem to lnconnect-clnrest for direct TLS connection URLs. See the clnrest configuration reference.

The former c-lightning-REST data directory (default: /var/lib/clightning-rest) and onion service keys (/var/lib/tor/onion/clightning-rest, if configured) are retained. The backups service no longer includes the former data directory. To keep backing it up, add its path to services.backups.extraFiles:

services.backups.extraFiles = [ "/var/lib/clightning-rest" ];

By default, clnrest’s certificates and rune are stored in Core Lightning’s network directory and remain covered by the Core Lightning backup.

After migrating your configuration, set nix-bitcoin.configVersion = "0.1.1";.