From 384f4883b2a2cd4536898f0dd07150de9502e826 Mon Sep 17 00:00:00 2001 From: d11n Date: Mon, 6 Jun 2022 08:11:09 +0200 Subject: [PATCH] Backup script and docs finetuning (#655) * Remove restore directory after restore * Backup bitcoin folder, excluding blocks and chainstate * Deprecate and warn about the old backup process * Update log messages * Add backup documentation --- README.md | 15 +++- btcpay-backup.sh | 24 +++--- btcpay-restore.sh | 39 +++++---- docs/backup-restore.md | 177 +++++++++++++++++++++++++++++++++++++++++ 4 files changed, 221 insertions(+), 34 deletions(-) create mode 100644 docs/backup-restore.md diff --git a/README.md b/README.md index 537c252..b4afe10 100644 --- a/README.md +++ b/README.md @@ -499,6 +499,14 @@ Yes. Please [see the documentation](https://docs.btcpayserver.org/FAQ/FAQ-Deploy ## How can I back up my BTCPay Server? +See the [Backup & Restore](https://docs.btcpayserver.org/Deployment/BackupRestore/) guide in our documentation. + +
+For backwards compatibility: Click here for the description of the old backup.sh process + +:::warning +Please consider switching to the [new Backup & Restore process](https://docs.btcpayserver.org/Deployment/BackupRestore/), because the `backup.sh` will not be maintained anymore. +::: We provide a backup script that dumps the database and saves the important files: ```bash @@ -509,9 +517,9 @@ cd "$BTCPAY_BASE_DIRECTORY/btcpayserver-docker" This will save the backup locally as `/var/lib/docker/volumes/backup_datadir/_data/backup.tar.gz`. These are the options to customize the backup name and location: -- `BACKUP_TIMESTAMP=true` saves the backup with datetime as part of the file name, so that backups do not get overwritten. -- `BACKUP_PROVIDER=SCP` saves the backup remotely, requires additional `SCP_TARGET` environment variable (see below). -- `BACKUP_PROVIDER=Dropbox` saves the backup to Dropbox, requires additional `DROPBOX_TOKEN` environment variable (see below). +* `BACKUP_TIMESTAMP=true` saves the backup with datetime as part of the file name, so that backups do not get overwritten. +* `BACKUP_PROVIDER=SCP` saves the backup remotely, requires additional `SCP_TARGET` environment variable (see below). +* `BACKUP_PROVIDER=Dropbox` saves the backup to Dropbox, requires additional `DROPBOX_TOKEN` environment variable (see below). ```bash cd "$BTCPAY_BASE_DIRECTORY/btcpayserver-docker" @@ -533,6 +541,7 @@ This option does not need to stop and restart the docker-containers: cd "$BTCPAY_BASE_DIRECTORY/btcpayserver-docker" ./backup.sh --only-db ``` +
## How can I connect to the database? diff --git a/btcpay-backup.sh b/btcpay-backup.sh index 2fc7213..8029c1b 100755 --- a/btcpay-backup.sh +++ b/btcpay-backup.sh @@ -35,7 +35,7 @@ cd $btcpay_dir dbcontainer=$(docker ps -a -q -f "name=postgres_1") if [ -z "$dbcontainer" ]; then printf "\n" - echo "ℹ️ Database container is not up and running. Starting BTCPay Server …" + echo "ℹ️ Database container is not up and running. Starting BTCPay Server …" docker volume create generated_postgres_datadir docker-compose -f $BTCPAY_DOCKER_COMPOSE up -d postgres @@ -48,7 +48,7 @@ if [ -z "$dbcontainer" ]; then fi printf "\n" -echo "ℹ️ Dumping database …" +echo "ℹ️ Dumping database …" { docker exec $dbcontainer pg_dumpall -c -U postgres | gzip > $dbdump_path echo "✅ Database dump done." @@ -57,18 +57,22 @@ echo "ℹ️ Dumping database …" exit 1 } -printf "\nℹ️ Stopping BTCPay Server …\n\n" +printf "\nℹ️ Stopping BTCPay Server …\n\n" btcpay_down printf "\n" cd $docker_dir -echo "ℹ️ Archiving files in $(pwd)…" +echo "ℹ️ Archiving files in $(pwd)…" { tar \ --exclude="volumes/backup_datadir" \ - --exclude="volumes/generated_bitcoin_datadir" \ - --exclude="volumes/generated_litecoin_datadir" \ + --exclude="volumes/generated_bitcoin_datadir/blocks" \ + --exclude="volumes/generated_bitcoin_datadir/chainstate" \ + --exclude="volumes/generated_bitcoin_datadir/debug.log" \ + --exclude="volumes/generated_litecoin_datadir/blocks" \ + --exclude="volumes/generated_litecoin_datadir/chainstate" \ + --exclude="volumes/generated_litecoin_datadir/debug.log" \ --exclude="volumes/generated_postgres_datadir" \ --exclude="volumes/generated_clightning_bitcoin_datadir/_data/lightning-rpc" \ --exclude="**/logs/*" \ @@ -92,18 +96,18 @@ echo "ℹ️ Archiving files in $(pwd)…" } fi } || { - echo "🚨 Archiving failed. Please check the error message above." - printf "\nℹ️ Restarting BTCPay Server …\n\n" + echo "🚨 Archiving failed. Please check the error message above." + printf "\nℹ️ Restarting BTCPay Server …\n\n" cd $btcpay_dir btcpay_up exit 1 } -printf "\nℹ️ Restarting BTCPay Server …\n\n" +printf "\nℹ️ Restarting BTCPay Server …\n\n" cd $btcpay_dir btcpay_up -printf "\nℹ️ Cleaning up …\n\n" +printf "\nℹ️ Cleaning up …\n\n" rm $dbdump_path printf "✅ Backup done => $backup_path\n\n" diff --git a/btcpay-restore.sh b/btcpay-restore.sh index 67ebdfc..214b5c6 100755 --- a/btcpay-restore.sh +++ b/btcpay-restore.sh @@ -4,13 +4,13 @@ set -o pipefail -o errexit if [ "$(id -u)" != "0" ]; then printf "\n🚨 This script must be run as root.\n" - printf "➡️ Use the command 'sudo su -' (include the trailing hypen) and try again.\n\n" + printf "➡️ Use the command 'sudo su -' (include the trailing hypen) and try again.\n\n" exit 1 fi backup_path=$1 if [ -z "$backup_path" ]; then - printf "\nℹ️ Usage: btcpay-restore.sh /path/to/backup.tar.gz\n\n" + printf "\nℹ️ Usage: btcpay-restore.sh /path/to/backup.tar.gz\n\n" exit 1 fi @@ -21,7 +21,7 @@ fi if [[ "$backup_path" == *.gpg && -z "$BTCPAY_BACKUP_PASSPHRASE" ]]; then printf "\n🔐 $backup_path is encrypted. Please provide the passphrase to decrypt it." - printf "\nℹ️ Usage: BTCPAY_BACKUP_PASSPHRASE=t0pSeCrEt btcpay-restore.sh /path/to/backup.tar.gz.gpg\n\n" + printf "\nℹ️ Usage: BTCPAY_BACKUP_PASSPHRASE=t0pSeCrEt btcpay-restore.sh /path/to/backup.tar.gz.gpg\n\n" exit 1 fi @@ -32,7 +32,7 @@ dbdump_name=postgres.sql.gz btcpay_dir="$BTCPAY_BASE_DIRECTORY/btcpayserver-docker" # ensure clean restore dir -printf "\nℹ️ Cleaning restore directory $restore_dir …\n\n" +printf "\nℹ️ Cleaning restore directory $restore_dir …\n\n" rm -rf $restore_dir mkdir -p $restore_dir @@ -43,14 +43,14 @@ if [[ "$backup_path" == *.gpg ]]; then backup_path="${backup_path%.*}" printf "✅ Decryption done.\n\n" } || { - echo "🚨 Decryption failed. Please check the error message above." + echo "🚨 Decryption failed. Please check the error message above." exit 1 } fi cd $restore_dir -echo "ℹ️ Extracting files in $(pwd) …" +echo "ℹ️ Extracting files in $(pwd) …" tar -xvf $backup_path -C $restore_dir # basic control checks @@ -67,13 +67,13 @@ fi cd $btcpay_dir . helpers.sh -printf "\nℹ️ Stopping BTCPay Server …\n\n" +printf "\nℹ️ Stopping BTCPay Server …\n\n" btcpay_down cd $restore_dir { - printf "\nℹ️ Restoring volumes …\n" + printf "\nℹ️ Restoring volumes …\n" # ensure volumes dir exists if [ ! -d "$docker_dir/volumes" ]; then mkdir -p $docker_dir/volumes @@ -81,33 +81,31 @@ cd $restore_dir # copy volume directories over cp -r volumes/* $docker_dir/volumes/ # ensure datadirs excluded in backup exist - mkdir -p $docker_dir/volumes/generated_bitcoin_datadir/_data - mkdir -p $docker_dir/volumes/generated_litecoin_datadir/_data mkdir -p $docker_dir/volumes/generated_postgres_datadir/_data echo "✅ Volume restore done." } || { echo "🚨 Restoring volumes failed. Please check the error message above." - printf "\nℹ️ Restarting BTCPay Server …\n\n" + printf "\nℹ️ Restarting BTCPay Server …\n\n" cd $btcpay_dir btcpay_up exit 1 } { - printf "\nℹ️ Starting database container …\n" + printf "\nℹ️ Starting database container …\n" docker-compose -f $BTCPAY_DOCKER_COMPOSE up -d postgres sleep 10 dbcontainer=$(docker ps -a -q -f "name=postgres") if [ -z "$dbcontainer" ]; then echo "🚨 Database container could not be started or found." - printf "\nℹ️ Restarting BTCPay Server …\n\n" + printf "\nℹ️ Restarting BTCPay Server …\n\n" cd $btcpay_dir btcpay_up exit 1 fi } || { - echo "🚨 Starting database container failed. Please check the error message above." - printf "\nℹ️ Restarting BTCPay Server …\n\n" + echo "🚨 Starting database container failed. Please check the error message above." + printf "\nℹ️ Restarting BTCPay Server …\n\n" cd $btcpay_dir btcpay_up exit 1 @@ -116,23 +114,22 @@ cd $restore_dir cd $restore_dir { - printf "\nℹ️ Restoring database …" + printf "\nℹ️ Restoring database …" gunzip -c $dbdump_name | docker exec -i $dbcontainer psql -U postgres postgres -a echo "✅ Database restore done." } || { - echo "🚨 Restoring database failed. Please check the error message above." + echo "🚨 Restoring database failed. Please check the error message above." printf "\nℹ️ Restarting BTCPay Server …\n\n" cd $btcpay_dir btcpay_up exit 1 } -printf "\nℹ️ Restarting BTCPay Server …\n\n" +printf "\nℹ️ Restarting BTCPay Server …\n\n" cd $btcpay_dir btcpay_up -printf "\nℹ️ Cleaning up …\n\n" -# rm -rf $restore_dir -# rm -rf $backup_path $backup_path.gpg +printf "\nℹ️ Cleaning up …\n\n" +rm -rf $restore_dir printf "✅ Restore done\n\n" diff --git a/docs/backup-restore.md b/docs/backup-restore.md new file mode 100644 index 0000000..2443d1d --- /dev/null +++ b/docs/backup-restore.md @@ -0,0 +1,177 @@ +# Backup & Restore + +This guide gets you up to speed with the [Docker deployment](../Docker/)'s Backup & Restore process. +You will learn about what to keep in mind when doing a backup and how to restore a backup. + +[[toc]] + +## Remarks and Considerations + +The original backups strategy in BTCPay Server still exists and can be found [here](https://docs.btcpayserver.org/Docker/#how-can-i-back-up-my-btcpay-server). +While this documentation covers the [new process](https://github.com/btcpayserver/btcpayserver-docker/pull/641), the old `backup.sh` script still works. + +:::warning +BTCPay Server is and will never be responsible for your backup. +Please make sure the backup includes the files and data you want to store. +Also, test the restore process before starting to rely on it. +::: + +### Lightning channel backup + +Please be aware of this important issue: +Old Lightning channel state is toxic! +You can lose all your funds if you close a channel based on an outdated state — and the state changes often! +If you publish an old state (say from yesterday's backup), you will most likely lose all your funds in the channel because the counterparty might publish a [revocation transaction](https://www.d11n.net/lightning-network-payment-channel-lifecycle.html#what-happens-in-case-of-a-false-close%3F)! + +There is a high chance of failure in a disaster recovery scenario, where you may do a backup once per night and need to restore that one backup. + +The Lightning channel backup from the `btcpay-backup.sh` script will be sufficient in a migration case, where the shutdown of the old server happens cleanly. +The old server should not be started after the restoration and start of the new server. + +:::tip +The Lightning static channel backup should be watched by a script and copied over to a remote server to ensure you always have the latest state available. +We will provide such a script with a future update. +For now, keep the above in mind when restoring from the backup! +::: + +## How does the backup work? + +The backup process is run with the `btcpay-backup.sh` script. + +Log in to your server, switch to the `root` user and type the following: + +```bash +# The backup script needs to be run as the root user +sudo su - + +# As the other scripts, it is inside the BTCPay base directory +cd $BTCPAY_BASE_DIRECTORY +./btcpay-backup.sh +``` + +The backup process needs to be run as `root`. +It will check for and let you know if you have to switch users. + +The script will do the following steps: + +* Ensure the database container is running +* Make a dump of the database +* Stop BTCPay Server +* Archive the Docker volumes and database dump + * Excluding the blockchains `blocks` and `chainstate` directories + * Optional: [Encrypt the archive](#set-a-backup-passphrase) +* Restart BTCPay Server +* Cleanup: Remove temporary files like the database dump + +If the backup directory doesn't exist yet, the script will create it. +With these preparations taken, the backup process is now starting. + +The script has checks to ensure it either works or fails with a comprehensive error message at every step of the way. +If there are errors, you will be notified like this: + +``` +🚨 Database container could not be started or found. +``` + +If everything works smoothly, you will see multiple completed marks in your console. +Whenever the backup has completed successfully, it will state: + +``` +✅ Backup done => /var/lib/docker/volumes/backup_datadir/_data/backup.tar.gz +``` + +Your BTCPay Server has now finished the backup process. +You must store these backups safely, for instance, by copying them to a remote server. + +After making a backup the first time, it is always wise to at least test your backup in a restore scenario. +We will go over the extra options you can set with your backup in the next topic. + +### Set a backup passphrase + +You can set the `BTCPAY_BACKUP_PASSPHRASE` environment variable for encrypting the backup. +This passphrase will be used by the backup and restore scripts to encrypt and decrypt the backup file. +For the backup script, this would look like the following: + +```bash +# Set the passphrase without adding it to the shell history +read -s -p "Enter passphrase: " BTCPAY_BACKUP_PASSPHRASE +export BTCPAY_BACKUP_PASSPHRASE + +./btcpay-backup.sh +``` + +This `BTCPAY_BACKUP_PASSPHRASE` if set, is necessary to be in the [restore process](#how-to-restore) as well. + +### Automation by crontab + +Here is an example of a crontab script that does a nightly backup at 4:15 AM: + +``` +SHELL=/bin/bash +PATH=/bin:/usr/sbin:/usr/bin:/usr/local/bin +15 4 * * * /root/btcpayserver-docker/btcpay-backup.sh >/dev/null 2>&1 +``` + +You need to set the right `SHELL` and `PATH`, so that the script can run with the correct context. +You might also want to set the `BTCPAY_BACKUP_PASSPHRASE` environment variable. + +## How to restore? + +It's very similar to the `btcpay-backup.sh` process but in reverse. +The `btcpay-restore.sh` script needs to be run with the path to your `backup.tar.gz` file. + +First off, open a terminal and type the following as root. +Remember that if you set `BTCPAY_BACKUP_PASSPHRASE` on the backup, you also need to provide it for decryption : + +```bash +# The restore script needs to be run as the root user +sudo su - + +# As the other scripts, it is inside the BTCPay base directory +cd $BTCPAY_BASE_DIRECTORY + +# Optional: Set the passphrase if you have used one for the backup +read -s -p "Enter passphrase: " BTCPAY_BACKUP_PASSPHRASE +export BTCPAY_BACKUP_PASSPHRASE + +# Run the restore script with the full path to the backup file +./btcpay-restore.sh /var/backups/backup.tar.gz.gpg +``` + +The script will do the following steps: + +* Extract (and decrypt) the backup archive +* Stop BTCPay Server +* Restore the Docker volumes +* Start the database container +* Import the database dump +* Restart BTCPay Server +* Cleanup: Remove the temporary restore directory + +If the backup file cannot be found in the provided path, the script will exit with an error. + +``` +🚨 /var/backups/backup.tar.gz.gpg does not exist. +``` + +Just as the `btcpay-backup.sh` script, the restore will stop at ANY error it may encounter. +If the backup file was created while the `BTCPAY_BACKUP_PASSPHRASE` was set but not used on restoring, the following error would occur: + +``` +🚨 Decryption failed. Please check the error message above. +``` + +When the restore has completed, you get the message: + +``` +✅ Restore done +``` + +Everything should be up and running again when the restore is complete. +You've successfully restored your BTCPay Server. Congratulations! + +:::tip +Always make sure your backup strategy is tested and fits your needs. +No one solution fits all, and we tried to cover the basic cases. +For the latest updates, always feel free to ask on the BTCPay Server community channels. +:::