fix(vaultwarden): make backup script filesystem-agnostic for NTFS/exFAT

- Replace symbolic link handling with a latest.txt file pointer
- Trade hard-link deduplication for universal drive compatibility
- Guarantee complete standalone backups across all target filesystems
This commit is contained in:
mattspeer committed 2026-10-03 10:20:44 -05:00
1 parent d4d709347c
commit f62d60802f
1 file changed
+13 -11
+13 -11
View File
@@ -3,8 +3,9 @@
# ==============================================================================
# Script: vaultwarden_backup.sh
# Description: Backs up Vaultwarden to timestamped directories on a mounted
# drive using Docker exec and rsync. Utilizes hard links for
# deduplication and automatically prunes backups older than RETENTION_DAYS.
# drive using Docker exec and rsync. Compatible with non-POSIX
# filesystems (exFAT, NTFS, FAT32) and automatically prunes
# backups older than RETENTION_DAYS.
# Usage: sudo ./vaultwarden_backup.sh
# Notes: Must be run with root/sudo privileges.
# ==============================================================================
@@ -22,7 +23,7 @@ RETENTION_DAYS=30
# Timestamp and Folder Setup
TIMESTAMP=$(date +"%Y-%m-%d_%H%M%S")
CURRENT_BACKUP_DIR="$VAULTWARDEN_DESTINATION/backup_$TIMESTAMP"
LATEST_LINK="$VAULTWARDEN_DESTINATION/latest"
LATEST_TXT_FILE="$VAULTWARDEN_DESTINATION/latest.txt"
# ntfy Notification Configuration
NTFY_TOPIC="Server"
@@ -54,7 +55,7 @@ if ! docker ps --format '{{.Names}}' | grep -q "^${CONTAINER_NAME}$"; then
exit 1
fi
# Create target directories if they don't exist
# Create target directory for current run
mkdir -p "$CURRENT_BACKUP_DIR"
# ==============================================================================
@@ -97,13 +98,15 @@ if [ $RSYNC_DB_STATUS -ne 0 ]; then
exit 1
fi
# Step 3: Rsync remaining data (using --link-dest for storage efficiency if 'latest' exists)
echo "Rsyncing attachments, RSA keys, and configuration files..."
# Step 3: Find previous backup directory for --link-dest (if filesystem supports it)
PREVIOUS_BACKUP_DIR=$(ls -td "$VAULTWARDEN_DESTINATION"/backup_* 2>/dev/null | grep -v "$CURRENT_BACKUP_DIR" | head -n 1)
LINK_DEST_PARAM=""
if [ -d "$LATEST_LINK" ]; then
LINK_DEST_PARAM="--link-dest=$LATEST_LINK"
if [ -n "$PREVIOUS_BACKUP_DIR" ] && [ -d "$PREVIOUS_BACKUP_DIR" ]; then
LINK_DEST_PARAM="--link-dest=$PREVIOUS_BACKUP_DIR"
fi
echo "Rsyncing attachments, RSA keys, and configuration files..."
rsync -av --no-owner --no-group $LINK_DEST_PARAM --exclude='db.sqlite3*' "$VAULTWARDEN_DATA_DIR/" "$CURRENT_BACKUP_DIR/"
RSYNC_DATA_STATUS=$?
@@ -113,9 +116,8 @@ if [ $RSYNC_DATA_STATUS -ne 0 ]; then
exit 1
fi
# Step 4: Update 'latest' symlink to point to this new backup folder
rm -f "$LATEST_LINK"
ln -s "$CURRENT_BACKUP_DIR" "$LATEST_LINK"
# Step 4: Record current backup path to latest.txt
echo "$CURRENT_BACKUP_DIR" > "$LATEST_TXT_FILE"
# ==============================================================================
# Retention Cleanup (Prune Backups Older than RETENTION_DAYS)