Files
Docker-Backup-Script/README.MD
T
2026-05-09 14:21:13 +00:00

8.9 KiB

Docker Services Recovery

This document describes how to restore the Docker services (netbird, pocket-id, caddy, vaultwarden) from an Internxt backup using docker-recover.sh.

Overview

The recovery script does the following:

  1. Lists available backups on Internxt and prompts you to choose one (or accepts one as an argument)
  2. Downloads the selected archive from Internxt via rclone
  3. Extracts it to a staging directory
  4. Stops any existing containers for the four services
  5. Moves existing /opt/<service> directories aside as <service>.pre-recovery.<timestamp>
  6. Restores each service's directory from the archive into /opt/
  7. For Netbird specifically: creates the containers/volumes without starting, copies the management database into the named volume, then starts everything
  8. Brings all services back up with docker compose up -d

Prerequisites

Before running recovery, the target machine needs:

  • Docker with the compose plugin (v2)
  • rclone installed and configured with a remote named internxt pointing to the same bucket/path that holds the backups
  • Root access (the script must be run as root or via sudo)
  • The docker-recover.sh script installed and executable, e.g. at /usr/local/bin/docker-recover.sh

Setting up rclone on a new machine

If you're recovering to a fresh VPS, the easiest way to get rclone configured is to copy the config file from the old machine:

# On the old machine, find the config file:
rclone config file

# Copy that file to the new machine at:
# /root/.config/rclone/rclone.conf

Alternatively, run rclone config on the new machine and reconfigure the Internxt remote from scratch.

Verify it works:

rclone listremotes
# should show: internxt:

rclone lsf internxt:vps-backups/
# should list the available backup archives

Usage

sudo docker-recover.sh                                        # interactive: lists backups, prompts for choice
sudo docker-recover.sh latest                                 # restores the most recent backup automatically
sudo docker-recover.sh strato-docker_2026-05-07_03-00-00.tar.gz   # restore a specific archive
sudo docker-recover.sh --dry-run                              # show what would happen, change nothing
sudo docker-recover.sh --dry-run latest                       # dry-run on the latest backup
sudo docker-recover.sh -n latest                              # short form of --dry-run
sudo docker-recover.sh --help                                 # show usage

1. Verify the backup with a dry-run

Before doing anything destructive, always run a dry-run first to see exactly what the script intends to do:

sudo docker-recover.sh --dry-run latest

Every operation is logged as WOULD RUN: <command> and prefixed with [DRY-RUN]. No files are changed, no containers are touched, nothing is downloaded.

For an even more thorough dry-run, do this two-step:

  1. Start a real recovery and abort at the confirmation prompt — this downloads the archive to /tmp/docker-recovery/ but doesn't change anything else
  2. Run --dry-run afterwards — since the archive is now cached locally, the script will list the actual top-level entries from the archive

2. (If migrating to a new VPS) Update DNS first

If you're recovering to a different machine with a different IP address, update your DNS A/AAAA records before running recovery, and ideally wait for propagation. Otherwise:

  • Caddy may try to renew TLS certificates on startup against the old IP
  • Netbird clients won't be able to reach the new server until DNS resolves correctly

3. Run the recovery

sudo docker-recover.sh latest

The script will:

  • List available backups
  • Ask for confirmation before doing anything destructive
  • Stream progress to the terminal and log everything to /var/log/docker-recover.log

4. Verify the services came up

docker ps

All four services should be running. Check individual logs if anything looks off:

cd /opt/netbird && docker compose logs --tail=50
cd /opt/pocket-id && docker compose logs --tail=50
cd /opt/caddy && docker compose logs --tail=50
cd /opt/vaultwarden && docker compose logs --tail=50

5. Verify each service's functionality

  • Caddy: curl -I https://yourdomain.example.com should return a valid response with the existing TLS certificate
  • Pocket-ID: log in via the web UI; check that previously registered passkeys still work
  • Netbird: check that existing peers reconnect and the dashboard shows your network
  • Vaultwarden: log in with an existing account; verify your vault items are present

6. Clean up the pre-recovery directories

The script preserves the previous state of /opt/<service> as /opt/<service>.pre-recovery.<timestamp>. Once you've verified everything works correctly:

sudo rm -rf /opt/*.pre-recovery.*

If something looks wrong, you can roll back by stopping the new containers, removing /opt/<service>, and renaming the .pre-recovery.<timestamp> directory back.

What gets restored

For each of netbird, pocket-id, caddy, vaultwarden:

  • The full contents of /opt/<service>/docker-compose.yml, .env files, configuration files, bind-mounted data directories

For Netbird specifically, the management database is restored separately:

  • The archive contains a netbird/_netbird-db/ subdirectory holding the database extracted from /var/lib/netbird/ inside the management container
  • The script creates the Netbird containers (and the named Docker volume that backs /var/lib/netbird/) without starting them, copies the database in, then starts everything

This is necessary because Netbird stores its database in a Docker named volume rather than in the bind-mounted /opt/netbird/ directory, so a plain tarball of /opt/netbird/ is not enough on its own.

Caddy TLS certificates

Caddy's TLS certificates and ACME account info live in /opt/caddy/data/ (assuming a bind mount). Restoring this directory means:

  • HTTPS works immediately on the new machine without re-issuing certificates
  • No risk of hitting Let's Encrypt rate limits during migration

If you ever change domain names during a migration, you may need to remove old certificates from /opt/caddy/data/caddy/certificates/ and let Caddy re-issue them for the new names.

Troubleshooting

rclone remote 'internxt' not configured

Run rclone listremotes as the same user that's running the script (root if using sudo). If internxt: doesn't appear, the rclone config file isn't where root expects it. Copy it to /root/.config/rclone/rclone.conf or set RCLONE_CONFIG=/path/to/rclone.conf in the environment.

No backups found matching strato-docker_*.tar.gz

Verify the remote contents directly:

sudo rclone lsf internxt:vps-backups/

If the archives use a different prefix or are in a different folder, adjust ARCHIVE_PREFIX and RCLONE_PATH at the top of the script.

Netbird database not restored

If the script logs could not detect Netbird management container; skipping DB restore, this means it couldn't find a service named netbird-server (newer setup) or management (older setup) in /opt/netbird/docker-compose.yml. Check the compose file and adjust the detection logic in the script if your service has a different name.

Containers fail to start after recovery

Check the logs (docker compose logs) for the affected service. Common issues:

  • Port conflicts: another service on the host is using the same port
  • Missing environment variables: the .env file wasn't included in the backup or was misplaced
  • Volume permission issues: file ownership in the restored directories doesn't match what the container expects (especially for non-root containers)

Pre-recovery rollback

If recovery succeeds but a service is broken, you can revert to the pre-recovery state:

cd /opt/<service> && docker compose down
sudo rm -rf /opt/<service>
sudo mv /opt/<service>.pre-recovery.<timestamp> /opt/<service>
cd /opt/<service> && docker compose up -d

For Netbird specifically, you may also need to remove and recreate the Docker named volume to clear out the restored database:

cd /opt/netbird
docker compose down -v   # the -v removes the named volumes too
# then bring up the rolled-back state
docker compose up -d

Logs

All recovery operations are logged to /var/log/docker-recover.log (in addition to being printed to the terminal). The log persists across runs, so you can review past recoveries.

  • /usr/local/bin/docker-backup.sh — the backup script that produces these archives, run nightly via cron
  • /usr/local/bin/docker-recover.sh — this recovery script
  • /var/log/docker-backup.log — backup logs
  • /var/log/docker-recover.log — recovery logs
  • /tmp/docker-recovery/ — staging directory used during recovery (downloaded archives are cached here)