diff --git a/examples/configuration.nix b/examples/configuration.nix index c1a28e9..514a4ea 100644 --- a/examples/configuration.nix +++ b/examples/configuration.nix @@ -137,6 +137,27 @@ # interact with off/on chain bridge using `loop in` and `loop out`. # services.lightning-loop.enable = true; + ### Backups + # Enable this module to use nix-bitcoin's own backups module. By default, it + # uses duplicity to incrementally back up all important files in /var/lib to + # /var/lib/localBackups once a day. + # services.backups.enable = true; + # You can pull the localBackups folder with + # `nixops scp --from bitcoin-node /var/lib/localBackups /my-backup-path/` + # Alternatively, you can also set a remote target url, for example + # services.backups.destination = "sftp://user@host[:port]/[relative|/absolute]_path"; + # Supply the sftp password by appending the FTP_PASSWORD environment variable + # to secrets/backup-encryption-env like so + # `echo "FTP_PASSWORD=" >> secrets/backup-encryption-env` + # You many also need to set a ssh host and publickey with + # programs.ssh.knownHosts."host" = { + # hostNames = [ "host" ]; + # publicKey = ""; + # }; + # If you also want to backup bulk data like the Bitcoin & Liquid blockchains + # and electrs data directory, enable + # services.backups.with-bulk-data = true; + # FIXME: Define your hostname. networking.hostName = "nix-bitcoin"; time.timeZone = "UTC"; diff --git a/modules/backups.nix b/modules/backups.nix new file mode 100644 index 0000000..47b74a1 --- /dev/null +++ b/modules/backups.nix @@ -0,0 +1,87 @@ +{ config, lib, pkgs, ... }: + +with lib; + +let + cfg = config.services.backups; + filelist = pkgs.writeText "filelist.txt" '' + ${optionalString (!cfg.with-bulk-data) "- ${config.services.bitcoind.dataDir}/blocks"} + ${optionalString (!cfg.with-bulk-data) "- ${config.services.bitcoind.dataDir}/chainstate"} + ${config.services.bitcoind.dataDir} + ${config.services.clightning.dataDir} + ${config.services.lnd.dataDir} + /secrets/lnd-seed-mnemonic + ${optionalString (!cfg.with-bulk-data) "- ${config.services.liquidd.dataDir}/*/blocks"} + ${optionalString (!cfg.with-bulk-data) "- ${config.services.liquidd.dataDir}/*/chainstate"} + ${config.services.liquidd.dataDir} + ${optionalString cfg.with-bulk-data "${config.services.electrs.dataDir}"} + ${config.services.lightning-charge.dataDir} + /var/lib/tor + # Extra files + ${cfg.extraFiles} + + # Exclude all unspecified files and directories + - / + ''; + +in { + options.services.backups = { + enable = mkEnableOption "Backups service"; + program = mkOption { + type = types.enum [ "duplicity" ]; + default = "duplicity"; + description = '' + Program with which to do backups. + ''; + }; + with-bulk-data = mkOption { + type = types.bool; + default = false; + description = '' + Whether to also backup Bitcoin blockchain and other bulk data. + ''; + }; + destination = mkOption { + type = types.str; + default = "file:///var/lib/localBackups"; + description = '' + Where to back up to. + ''; + }; + frequency = mkOption { + type = types.nullOr types.str; + default = null; + description = '' + Run backup with the given frequency. If null, do not run automatically. + ''; + }; + extraFiles = mkOption { + type = types.lines; + default = ""; + example = '' + /var/lib/nginx + ''; + description = "Additional files to be appended to filelist."; + }; + }; + + config = mkMerge [ + (mkIf (cfg.enable && cfg.program == "duplicity") { + environment.systemPackages = [ pkgs.duplicity ]; + + services.duplicity = { + enable = true; + extraFlags = [ + "--include-filelist" "${filelist}" + "--full-if-older-than" "1M" + ]; + targetUrl = "${cfg.destination}"; + frequency = cfg.frequency; + secretFile = "${config.nix-bitcoin.secretsDir}/backup-encryption-env"; + }; + + nix-bitcoin.secrets.backup-encryption-env.user = "root"; + + }) + ]; +} diff --git a/modules/modules.nix b/modules/modules.nix index f509cc8..3625c1e 100644 --- a/modules/modules.nix +++ b/modules/modules.nix @@ -17,6 +17,7 @@ ./secrets/secrets.nix ./netns-isolation.nix ./dbus.nix + ./backups.nix ]; disabledModules = [ "services/networking/bitcoind.nix" ]; diff --git a/modules/presets/secure-node.nix b/modules/presets/secure-node.nix index 065bbb6..374dd52 100644 --- a/modules/presets/secure-node.nix +++ b/modules/presets/secure-node.nix @@ -210,6 +210,11 @@ in { services.nix-bitcoin-webindex.enforceTor = true; + # Backups + services.backups = { + program = "duplicity"; + frequency = "daily"; + }; environment.systemPackages = with pkgs; [ tor diff --git a/pkgs/generate-secrets/generate-secrets.sh b/pkgs/generate-secrets/generate-secrets.sh index 2d70741..ef3611b 100755 --- a/pkgs/generate-secrets/generate-secrets.sh +++ b/pkgs/generate-secrets/generate-secrets.sh @@ -12,12 +12,14 @@ makePasswordSecret lnd-wallet-password makePasswordSecret liquid-rpcpassword makePasswordSecret lightning-charge-token makePasswordSecret spark-wallet-password +makePasswordSecret backup-encryption-password [[ -e bitcoin-HMAC-privileged ]] || rpcauth privileged $(cat bitcoin-rpcpassword-privileged) | grep rpcauth | cut -d ':' -f 2 > bitcoin-HMAC-privileged [[ -e bitcoin-HMAC-public ]] || rpcauth public $(cat bitcoin-rpcpassword-public) | grep rpcauth | cut -d ':' -f 2 > bitcoin-HMAC-public [[ -e lightning-charge-env ]] || echo "API_TOKEN=$(cat lightning-charge-token)" > lightning-charge-env [[ -e nanopos-env ]] || echo "CHARGE_TOKEN=$(cat lightning-charge-token)" > nanopos-env [[ -e spark-wallet-login ]] || echo "login=spark-wallet:$(cat spark-wallet-password)" > spark-wallet-login +[[ -e backup-encryption-env ]] || echo "PASSPHRASE=$(cat backup-encryption-password)" > backup-encryption-env if [[ ! -e lnd-key || ! -e lnd-cert ]]; then openssl ecparam -genkey -name prime256v1 -out lnd-key