Track vaultwarden backup and restore scripts
Daily SQLite backup to the NetBackup SMB share plus restore/import/export helpers. SMB credentials moved out of the scripts into ~/.smbcredentials (mode 600) and are passed to smbclient via -A instead of -U "user%pass". This keeps the password out of version control and out of the process list, where -U exposes it to any local user through ps.
This commit is contained in:
21
.gitignore
vendored
Normal file
21
.gitignore
vendored
Normal file
@@ -0,0 +1,21 @@
|
|||||||
|
# OS / editor cruft
|
||||||
|
.DS_Store
|
||||||
|
Thumbs.db
|
||||||
|
*.swp
|
||||||
|
*~
|
||||||
|
|
||||||
|
# SMB credentials - NEVER commit these.
|
||||||
|
# Real file lives at ~/.smbcredentials (mode 600). This guards against anyone
|
||||||
|
# dropping a copy inside the repo.
|
||||||
|
.smbcredentials
|
||||||
|
*.smbcredentials
|
||||||
|
smb.credentials
|
||||||
|
*.env
|
||||||
|
.env.*
|
||||||
|
|
||||||
|
# Backup output (the script uses /tmp, but guard local drops)
|
||||||
|
*.db
|
||||||
|
*.db-journal
|
||||||
|
|
||||||
|
# Logs
|
||||||
|
*.log
|
||||||
145
vaultwarden-backup-helpers/README.md
Normal file
145
vaultwarden-backup-helpers/README.md
Normal file
@@ -0,0 +1,145 @@
|
|||||||
|
# Vaultwarden Backup & Restore System
|
||||||
|
|
||||||
|
This directory contains scripts for backing up, restoring, and converting Vaultwarden data.
|
||||||
|
|
||||||
|
## Overview
|
||||||
|
|
||||||
|
### Primary Backup: SQLite Database (Automated Daily)
|
||||||
|
The main backup runs daily at 3:00 AM via cron (`/home/bdm/scripts/vaultwarden-backup.sh`). It:
|
||||||
|
1. Creates a consistent SQLite backup using `sqlite3 .backup`
|
||||||
|
2. Uploads to SMB share (`//192.168.123.2/NetBackup/Vault/`)
|
||||||
|
3. Cleans up backups older than 60 days
|
||||||
|
|
||||||
|
**This is the complete backup for disaster recovery.** It contains ALL users, their encrypted vaults, organizations, collections, sends, etc.
|
||||||
|
|
||||||
|
### Restore Options
|
||||||
|
|
||||||
|
#### Option 1: Full Instance Restore (Recommended for Disaster Recovery)
|
||||||
|
Use `restore-sqlite.sh` to restore the entire Vaultwarden instance:
|
||||||
|
```bash
|
||||||
|
./restore-sqlite.sh vaultwarden-2026-09-19_09-03-45.db
|
||||||
|
```
|
||||||
|
This replaces the database file and restarts Vaultwarden. All users log in with their existing master passwords.
|
||||||
|
|
||||||
|
#### Option 2: Individual User Vault Export/Import (JSON)
|
||||||
|
Use `export-to-json.sh` and `import-from-json.sh` for individual user vaults:
|
||||||
|
```bash
|
||||||
|
# Export (requires master password)
|
||||||
|
./export-to-json.sh user@example.com my-vault.json
|
||||||
|
|
||||||
|
# Import (requires master password)
|
||||||
|
./import-from-json.sh user@example.com my-vault.json
|
||||||
|
```
|
||||||
|
|
||||||
|
**Note:** JSON export requires the master password because the SQLite database stores all data ENCRYPTED. The master password is needed to decrypt the vault for JSON export.
|
||||||
|
|
||||||
|
## Scripts
|
||||||
|
|
||||||
|
| Script | Purpose | Requires Master Password |
|
||||||
|
|--------|---------|-------------------------|
|
||||||
|
| `vaultwarden-backup.sh` | Daily automated SQLite backup (run by cron) | No |
|
||||||
|
| `restore-sqlite.sh` | Restore entire instance from SQLite backup | No |
|
||||||
|
| `export-to-json.sh` | Export single user vault to JSON | **Yes** |
|
||||||
|
| `import-from-json.sh` | Import JSON vault to user account | **Yes** |
|
||||||
|
| `mount-smb.sh` | Mount SMB share for cleanup (internal) | No |
|
||||||
|
| `umount-smb.sh` | Unmount SMB share (internal) | No |
|
||||||
|
| `cleanup-old-backups.sh` | Delete backups older than 60 days (internal) | No |
|
||||||
|
|
||||||
|
## Backup Location
|
||||||
|
|
||||||
|
- **SMB Share:** `//192.168.123.2/NetBackup/Vault/`
|
||||||
|
- **Local Temp:** `/tmp/vaultwarden-backup/` (cleaned up after upload)
|
||||||
|
- **Log File:** `/var/log/vaultwarden-backup.log`
|
||||||
|
|
||||||
|
## Cron Schedule
|
||||||
|
|
||||||
|
Daily at 3:00 AM (see `crontab -l`):
|
||||||
|
```
|
||||||
|
0 3 * * * /home/bdm/scripts/vaultwarden-backup.sh >> /var/log/vaultwarden-backup.log 2>&1
|
||||||
|
```
|
||||||
|
|
||||||
|
## Manual Backup
|
||||||
|
|
||||||
|
To run a manual backup:
|
||||||
|
```bash
|
||||||
|
/home/bdm/scripts/vaultwarden-backup.sh
|
||||||
|
```
|
||||||
|
|
||||||
|
## Sudo Configuration
|
||||||
|
|
||||||
|
The backup script uses sudo for specific commands. Sudoers rules are in `/etc/sudoers.d/vaultwarden-backup`:
|
||||||
|
- `sqlite3` backup command
|
||||||
|
- `chown` for temp files
|
||||||
|
- SMB mount/umount/cleanup wrapper scripts
|
||||||
|
|
||||||
|
## Disaster Recovery Procedure
|
||||||
|
|
||||||
|
1. **New server setup:**
|
||||||
|
- Install Docker, Docker Compose
|
||||||
|
- Deploy Vaultwarden container with same volume name (`caddy_vaultwarden_data`)
|
||||||
|
- Start container once to create empty database
|
||||||
|
|
||||||
|
2. **Restore database:**
|
||||||
|
```bash
|
||||||
|
# Download backup from SMB (credentials read from the file below)
|
||||||
|
smbclient //192.168.123.2/NetBackup -A "$HOME/.smbcredentials" -c "cd Vault; get vaultwarden-YYYY-MM-DD_HH-MM-SS.db"
|
||||||
|
|
||||||
|
# Restore
|
||||||
|
./restore-sqlite.sh vaultwarden-YYYY-MM-DD_HH-MM-SS.db
|
||||||
|
```
|
||||||
|
|
||||||
|
3. **Verify:** Users can log in with their existing credentials
|
||||||
|
|
||||||
|
## JSON Import/Export Notes
|
||||||
|
|
||||||
|
- JSON files contain **DECRYPTED** vault data - store securely!
|
||||||
|
- Use `BW_MASTER_PASSWORD` env var for automation (less secure)
|
||||||
|
- Interactive prompt is more secure
|
||||||
|
- JSON format is Bitwarden-compatible (select "Bitwarden (json)" on import)
|
||||||
|
- Import does not overwrite existing items - it adds/updates
|
||||||
|
|
||||||
|
## Troubleshooting
|
||||||
|
|
||||||
|
### Backup fails with "sqlite3 backup failed"
|
||||||
|
- Check if container is running: `docker ps | grep vaultwarden`
|
||||||
|
- Check volume path: `ls -la /var/lib/docker/volumes/caddy_vaultwarden_data/_data/`
|
||||||
|
- Run manually to see errors: `/home/bdm/scripts/vaultwarden-backup.sh`
|
||||||
|
|
||||||
|
### SMB upload fails
|
||||||
|
- Check network connectivity: `ping 192.168.123.2`
|
||||||
|
- Check the SMB credentials file is present and readable: `ls -l ~/.smbcredentials`
|
||||||
|
- Test manually: `smbclient //192.168.123.2/NetBackup -A "$HOME/.smbcredentials" -c "ls"`
|
||||||
|
|
||||||
|
### Cron doesn't run
|
||||||
|
- Check cron logs: `journalctl -u cron -f`
|
||||||
|
- Verify crontab: `crontab -l`
|
||||||
|
- Check log file: `cat /var/log/vaultwarden-backup.log`
|
||||||
|
|
||||||
|
## SMB Credentials
|
||||||
|
|
||||||
|
The scripts do **not** contain the SMB password. It lives in an external file so
|
||||||
|
that it stays out of version control and out of the process list:
|
||||||
|
|
||||||
|
- **Location:** `~/.smbcredentials` (override with the `SMB_CRED_FILE` env var)
|
||||||
|
- **Permissions:** `600`, owned by the user running the backup (`bdm`)
|
||||||
|
|
||||||
|
Create it once, with mode 600:
|
||||||
|
|
||||||
|
```bash
|
||||||
|
umask 077
|
||||||
|
printf 'username = %s\npassword = %s\n' 'bdm' 'YOUR_PASSWORD' > ~/.smbcredentials
|
||||||
|
```
|
||||||
|
|
||||||
|
The scripts pass it to `smbclient` with `-A` (authentication file), which is
|
||||||
|
preferable to `-U "user%pass"` because a password passed via `-U` is visible to
|
||||||
|
any local user through `ps`.
|
||||||
|
|
||||||
|
Note that `/root/.smbcredentials` is a *separate* file used only by the `sudo
|
||||||
|
mount -t cifs` calls, which run as root. The two are independent.
|
||||||
|
|
||||||
|
## Security Notes
|
||||||
|
|
||||||
|
- SMB credentials are kept in `~/.smbcredentials` (mode 600), not in the scripts
|
||||||
|
- JSON exports contain plaintext passwords - encrypt them if storing long-term
|
||||||
|
- SQLite backups contain encrypted data - safe to store but treat as sensitive
|
||||||
|
- Master passwords are never stored - only used interactively or via env var
|
||||||
3
vaultwarden-backup-helpers/cleanup-old-backups.sh
Executable file
3
vaultwarden-backup-helpers/cleanup-old-backups.sh
Executable file
@@ -0,0 +1,3 @@
|
|||||||
|
#!/bin/bash
|
||||||
|
# Clean up old vaultwarden backups from SMB share
|
||||||
|
find "/mnt/netbackup/Vault" -name "vaultwarden-*.db" -mtime +60 -type f -print -delete 2>/dev/null | wc -l
|
||||||
74
vaultwarden-backup-helpers/export-to-json.sh
Executable file
74
vaultwarden-backup-helpers/export-to-json.sh
Executable file
@@ -0,0 +1,74 @@
|
|||||||
|
#!/bin/bash
|
||||||
|
# Vaultwarden JSON Export Script
|
||||||
|
# This script exports a user's vault to JSON format using the Bitwarden CLI.
|
||||||
|
#
|
||||||
|
# IMPORTANT: This requires the user's MASTER PASSWORD to decrypt the vault data.
|
||||||
|
# The SQLite database stores data ENCRYPTED - it cannot be converted to JSON without
|
||||||
|
# the master password.
|
||||||
|
#
|
||||||
|
# The JSON export is useful for:
|
||||||
|
# - Migrating to a different password manager
|
||||||
|
# - Importing into a different Vaultwarden instance as a different user
|
||||||
|
# - Human-readable backup (store securely!)
|
||||||
|
#
|
||||||
|
# For full instance disaster recovery, use restore-sqlite.sh instead.
|
||||||
|
#
|
||||||
|
# Usage: ./export-to-json.sh <email> [output-file.json]
|
||||||
|
# Example: ./export-to-json.sh user@example.com my-vault-export.json
|
||||||
|
#
|
||||||
|
# The master password can be provided via:
|
||||||
|
# - BW_MASTER_PASSWORD environment variable
|
||||||
|
# - Interactive prompt (recommended for security)
|
||||||
|
|
||||||
|
set -euo pipefail
|
||||||
|
|
||||||
|
EMAIL="${1:-}"
|
||||||
|
OUTPUT_FILE="${2:-vaultwarden-export-$(date +%Y-%m-%d).json}"
|
||||||
|
VAULTWARDEN_URL="https://vault.bdmurphy.me"
|
||||||
|
|
||||||
|
if [ -z "$EMAIL" ]; then
|
||||||
|
echo "Usage: $0 <email> [output-file.json]"
|
||||||
|
exit 1
|
||||||
|
fi
|
||||||
|
|
||||||
|
# Check if bw CLI is available
|
||||||
|
if ! command -v bw &> /dev/null; then
|
||||||
|
echo "ERROR: Bitwarden CLI (bw) not found. Install with: npm install -g @bitwarden/cli"
|
||||||
|
exit 1
|
||||||
|
fi
|
||||||
|
|
||||||
|
# Configure server URL
|
||||||
|
bw config server "$VAULTWARDEN_URL" >/dev/null
|
||||||
|
|
||||||
|
# Login
|
||||||
|
echo "Logging in to Vaultwarden as $EMAIL..."
|
||||||
|
|
||||||
|
if [ -n "${BW_MASTER_PASSWORD:-}" ]; then
|
||||||
|
# Use environment variable
|
||||||
|
export BW_SESSION=$(bw login "$EMAIL" "$BW_MASTER_PASSWORD" --raw)
|
||||||
|
else
|
||||||
|
# Interactive login
|
||||||
|
export BW_SESSION=$(bw login "$EMAIL" --raw)
|
||||||
|
fi
|
||||||
|
|
||||||
|
if [ -z "$BW_SESSION" ] || [ "$BW_SESSION" = "null" ]; then
|
||||||
|
echo "ERROR: Login failed. Check credentials."
|
||||||
|
exit 1
|
||||||
|
fi
|
||||||
|
|
||||||
|
echo "Login successful. Exporting vault..."
|
||||||
|
|
||||||
|
# Export vault to JSON
|
||||||
|
bw export --format json --output "$OUTPUT_FILE" --session "$BW_SESSION"
|
||||||
|
|
||||||
|
# Lock the vault
|
||||||
|
bw lock --session "$BW_SESSION" >/dev/null
|
||||||
|
|
||||||
|
echo "Export complete: $OUTPUT_FILE"
|
||||||
|
echo ""
|
||||||
|
echo "IMPORTANT: This file contains DECRYPTED vault data. Store it securely!"
|
||||||
|
echo "To import into another Vaultwarden instance:"
|
||||||
|
echo " 1. Log in to the target Vaultwarden web vault"
|
||||||
|
echo " 2. Go to Tools > Import Data"
|
||||||
|
echo " 3. Select 'Bitwarden (json)' as format"
|
||||||
|
echo " 4. Upload this file"
|
||||||
60
vaultwarden-backup-helpers/import-from-json.sh
Executable file
60
vaultwarden-backup-helpers/import-from-json.sh
Executable file
@@ -0,0 +1,60 @@
|
|||||||
|
#!/bin/bash
|
||||||
|
# Vaultwarden JSON Import Script
|
||||||
|
# This script imports a JSON export file into Vaultwarden using the Bitwarden CLI.
|
||||||
|
#
|
||||||
|
# Usage: ./import-from-json.sh <email> <input-file.json>
|
||||||
|
# Example: ./import-from-json.sh user@example.com vaultwarden-export-2026-09-19.json
|
||||||
|
#
|
||||||
|
# The master password can be provided via:
|
||||||
|
# - BW_MASTER_PASSWORD environment variable
|
||||||
|
# - Interactive prompt
|
||||||
|
|
||||||
|
set -euo pipefail
|
||||||
|
|
||||||
|
EMAIL="${1:-}"
|
||||||
|
INPUT_FILE="${2:-}"
|
||||||
|
VAULTWARDEN_URL="https://vault.bdmurphy.me"
|
||||||
|
|
||||||
|
if [ -z "$EMAIL" ] || [ -z "$INPUT_FILE" ]; then
|
||||||
|
echo "Usage: $0 <email> <input-file.json>"
|
||||||
|
exit 1
|
||||||
|
fi
|
||||||
|
|
||||||
|
if [ ! -f "$INPUT_FILE" ]; then
|
||||||
|
echo "ERROR: Input file not found: $INPUT_FILE"
|
||||||
|
exit 1
|
||||||
|
fi
|
||||||
|
|
||||||
|
# Check if bw CLI is available
|
||||||
|
if ! command -v bw &> /dev/null; then
|
||||||
|
echo "ERROR: Bitwarden CLI (bw) not found. Install with: npm install -g @bitwarden/cli"
|
||||||
|
exit 1
|
||||||
|
fi
|
||||||
|
|
||||||
|
# Configure server URL
|
||||||
|
bw config server "$VAULTWARDEN_URL" >/dev/null
|
||||||
|
|
||||||
|
# Login
|
||||||
|
echo "Logging in to Vaultwarden as $EMAIL..."
|
||||||
|
|
||||||
|
if [ -n "${BW_MASTER_PASSWORD:-}" ]; then
|
||||||
|
export BW_SESSION=$(bw login "$EMAIL" "$BW_MASTER_PASSWORD" --raw)
|
||||||
|
else
|
||||||
|
export BW_SESSION=$(bw login "$EMAIL" --raw)
|
||||||
|
fi
|
||||||
|
|
||||||
|
if [ -z "$BW_SESSION" ] || [ "$BW_SESSION" = "null" ]; then
|
||||||
|
echo "ERROR: Login failed. Check credentials."
|
||||||
|
exit 1
|
||||||
|
fi
|
||||||
|
|
||||||
|
echo "Login successful. Importing vault from $INPUT_FILE..."
|
||||||
|
|
||||||
|
# Import vault from JSON
|
||||||
|
bw import --format json --input "$INPUT_FILE" --session "$BW_SESSION"
|
||||||
|
|
||||||
|
# Lock the vault
|
||||||
|
bw lock --session "$BW_SESSION" >/dev/null
|
||||||
|
|
||||||
|
echo "Import complete!"
|
||||||
|
echo "Note: You may need to sync the vault in the web/browser extension."
|
||||||
7
vaultwarden-backup-helpers/mount-smb.sh
Executable file
7
vaultwarden-backup-helpers/mount-smb.sh
Executable file
@@ -0,0 +1,7 @@
|
|||||||
|
#!/bin/bash
|
||||||
|
# Mount SMB share for vaultwarden backup cleanup
|
||||||
|
mkdir -p /mnt/netbackup
|
||||||
|
if ! mountpoint -q /mnt/netbackup; then
|
||||||
|
mount -t cifs "//192.168.123.2/NetBackup" /mnt/netbackup \
|
||||||
|
-o credentials=/root/.smbcredentials,iocharset=utf8,vers=3.0,uid=1000,gid=1000,file_mode=0666,dir_mode=0777 2>/dev/null
|
||||||
|
fi
|
||||||
75
vaultwarden-backup-helpers/restore-sqlite.sh
Executable file
75
vaultwarden-backup-helpers/restore-sqlite.sh
Executable file
@@ -0,0 +1,75 @@
|
|||||||
|
#!/bin/bash
|
||||||
|
# Vaultwarden SQLite Database Restore Script
|
||||||
|
# This script restores a vaultwarden SQLite database backup to the running container.
|
||||||
|
#
|
||||||
|
# IMPORTANT: The SQLite backup is the PRIMARY backup for full instance recovery.
|
||||||
|
# It contains ALL users, their encrypted vault data, organizations, collections, etc.
|
||||||
|
# Simply replacing the database file and restarting Vaultwarden will restore everything.
|
||||||
|
#
|
||||||
|
# Usage: ./restore-sqlite.sh <backup-file.db>
|
||||||
|
# Example: ./restore-sqlite.sh vaultwarden-2026-09-19_09-03-45.db
|
||||||
|
|
||||||
|
set -euo pipefail
|
||||||
|
|
||||||
|
BACKUP_FILE="${1:-}"
|
||||||
|
VAULT_DATA="/var/lib/docker/volumes/caddy_vaultwarden_data/_data"
|
||||||
|
CONTAINER_NAME="vaultwarden"
|
||||||
|
SMB_SHARE="//192.168.123.2/NetBackup"
|
||||||
|
|
||||||
|
# SMB credentials live in an external file (mode 600), not in this script, so the
|
||||||
|
# password stays out of version control and out of the process list.
|
||||||
|
SMB_CRED_FILE="${SMB_CRED_FILE:-$HOME/.smbcredentials}"
|
||||||
|
|
||||||
|
if [ ! -r "$SMB_CRED_FILE" ]; then
|
||||||
|
echo "ERROR: SMB credentials file not readable: ${SMB_CRED_FILE}"
|
||||||
|
echo "Create it with: printf 'username = %s\\npassword = %s\\n' <user> <pass> | install -m 600 /dev/stdin ${SMB_CRED_FILE}"
|
||||||
|
exit 1
|
||||||
|
fi
|
||||||
|
|
||||||
|
if [ -z "$BACKUP_FILE" ]; then
|
||||||
|
echo "Usage: $0 <backup-file.db>"
|
||||||
|
echo "Available backups in SMB share:"
|
||||||
|
smbclient "$SMB_SHARE" -A "$SMB_CRED_FILE" -c "cd Vault; ls vaultwarden-*.db" 2>/dev/null | grep "vaultwarden-"
|
||||||
|
exit 1
|
||||||
|
fi
|
||||||
|
|
||||||
|
if [ ! -f "$BACKUP_FILE" ]; then
|
||||||
|
# Try to download from SMB
|
||||||
|
echo "Backup file not found locally. Downloading from SMB..."
|
||||||
|
smbclient "$SMB_SHARE" -A "$SMB_CRED_FILE" -c "cd Vault; get $BACKUP_FILE $BACKUP_FILE" 2>/dev/null
|
||||||
|
if [ ! -f "$BACKUP_FILE" ]; then
|
||||||
|
echo "ERROR: Could not find or download backup file: $BACKUP_FILE"
|
||||||
|
exit 1
|
||||||
|
fi
|
||||||
|
fi
|
||||||
|
|
||||||
|
echo "Restoring Vaultwarden database from: $BACKUP_FILE"
|
||||||
|
echo "This will replace the current database. All users will need to log in again."
|
||||||
|
read -p "Are you sure? (yes/no): " CONFIRM
|
||||||
|
if [ "$CONFIRM" != "yes" ]; then
|
||||||
|
echo "Aborted."
|
||||||
|
exit 1
|
||||||
|
fi
|
||||||
|
|
||||||
|
# Stop the container
|
||||||
|
echo "Stopping Vaultwarden container..."
|
||||||
|
docker stop "$CONTAINER_NAME"
|
||||||
|
|
||||||
|
# Backup current database (just in case)
|
||||||
|
CURRENT_DB="${VAULT_DATA}/db.sqlite3"
|
||||||
|
if [ -f "$CURRENT_DB" ]; then
|
||||||
|
sudo cp "$CURRENT_DB" "${CURRENT_DB}.pre-restore-$(date +%Y%m%d-%H%M%S)"
|
||||||
|
echo "Current database backed up."
|
||||||
|
fi
|
||||||
|
|
||||||
|
# Restore the backup
|
||||||
|
echo "Restoring database..."
|
||||||
|
sudo cp "$BACKUP_FILE" "$CURRENT_DB"
|
||||||
|
sudo chown 1000:1000 "$CURRENT_DB" # Adjust if different user runs container
|
||||||
|
|
||||||
|
# Start the container
|
||||||
|
echo "Starting Vaultwarden container..."
|
||||||
|
docker start "$CONTAINER_NAME"
|
||||||
|
|
||||||
|
echo "Restore complete! Vaultwarden should be available shortly."
|
||||||
|
echo "Users can log in with their existing master passwords."
|
||||||
3
vaultwarden-backup-helpers/umount-smb.sh
Executable file
3
vaultwarden-backup-helpers/umount-smb.sh
Executable file
@@ -0,0 +1,3 @@
|
|||||||
|
#!/bin/bash
|
||||||
|
# Unmount SMB share for vaultwarden backup cleanup
|
||||||
|
umount /mnt/netbackup 2>/dev/null
|
||||||
65
vaultwarden-backup.sh
Executable file
65
vaultwarden-backup.sh
Executable file
@@ -0,0 +1,65 @@
|
|||||||
|
#!/bin/bash
|
||||||
|
# Vaultwarden daily backup to SMB share via smbclient
|
||||||
|
|
||||||
|
VAULT_DATA="/var/lib/docker/volumes/caddy_vaultwarden_data/_data"
|
||||||
|
BACKUP_DIR="/tmp/vaultwarden-backup"
|
||||||
|
TIMESTAMP=$(date +%Y-%m-%d_%H-%M-%S)
|
||||||
|
BACKUP_FILE="${BACKUP_DIR}/vaultwarden-${TIMESTAMP}.db"
|
||||||
|
SMB_HOST="192.168.123.2"
|
||||||
|
SMB_SHARE="NetBackup"
|
||||||
|
SMB_DIR="Vault"
|
||||||
|
KEEP_DAYS=60
|
||||||
|
|
||||||
|
# SMB credentials are stored in an external file (mode 600) rather than inline
|
||||||
|
# here, so the password never lands in version control or in the process list.
|
||||||
|
# See vaultwarden-backup-helpers/README.md for setup.
|
||||||
|
SMB_CRED_FILE="${SMB_CRED_FILE:-$HOME/.smbcredentials}"
|
||||||
|
|
||||||
|
if [ ! -r "$SMB_CRED_FILE" ]; then
|
||||||
|
echo "$(date): ERROR - SMB credentials file not readable: ${SMB_CRED_FILE}"
|
||||||
|
echo "$(date): Create it with: printf 'username = %s\\npassword = %s\\n' <user> <pass> | install -m 600 /dev/stdin ${SMB_CRED_FILE}"
|
||||||
|
exit 1
|
||||||
|
fi
|
||||||
|
|
||||||
|
mkdir -p "$BACKUP_DIR"
|
||||||
|
|
||||||
|
echo "$(date): Starting vaultwarden backup..."
|
||||||
|
sudo sqlite3 "${VAULT_DATA}/db.sqlite3" ".backup '${BACKUP_FILE}'"
|
||||||
|
sudo chown "$(id -u):$(id -g)" "$BACKUP_FILE"
|
||||||
|
|
||||||
|
if [ -f "$BACKUP_FILE" ] && [ -s "$BACKUP_FILE" ]; then
|
||||||
|
SIZE=$(du -h "$BACKUP_FILE" | cut -f1)
|
||||||
|
echo "$(date): Backup created ($SIZE), uploading to SMB..."
|
||||||
|
|
||||||
|
smbclient "//${SMB_HOST}/${SMB_SHARE}" -A "$SMB_CRED_FILE" \
|
||||||
|
-c "cd ${SMB_DIR}; put ${BACKUP_FILE} vaultwarden-${TIMESTAMP}.db"
|
||||||
|
|
||||||
|
if [ $? -eq 0 ]; then
|
||||||
|
echo "$(date): Backup finished successfully."
|
||||||
|
else
|
||||||
|
echo "$(date): ERROR - SMB upload failed!"
|
||||||
|
exit 1
|
||||||
|
fi
|
||||||
|
|
||||||
|
rm -f "$BACKUP_FILE"
|
||||||
|
else
|
||||||
|
echo "$(date): ERROR - sqlite3 backup failed or file is empty!"
|
||||||
|
rm -f "$BACKUP_FILE"
|
||||||
|
exit 1
|
||||||
|
fi
|
||||||
|
|
||||||
|
# Clean up old backups (older than KEEP_DAYS)
|
||||||
|
echo "$(date): Cleaning up backups older than ${KEEP_DAYS} days..."
|
||||||
|
sudo mkdir -p /mnt/netbackup
|
||||||
|
if ! mountpoint -q /mnt/netbackup; then
|
||||||
|
sudo mount -t cifs "//${SMB_HOST}/${SMB_SHARE}" /mnt/netbackup \
|
||||||
|
-o credentials=/root/.smbcredentials,iocharset=utf8,vers=3.0,uid=$(id -u),gid=$(id -g),file_mode=0666,dir_mode=0777 2>/dev/null
|
||||||
|
fi
|
||||||
|
|
||||||
|
if mountpoint -q /mnt/netbackup; then
|
||||||
|
DELETED=$(find "/mnt/netbackup/${SMB_DIR}" -name "vaultwarden-*.db" -mtime +${KEEP_DAYS} -type f -print -delete 2>/dev/null | wc -l)
|
||||||
|
sudo umount /mnt/netbackup 2>/dev/null
|
||||||
|
echo "$(date): Deleted ${DELETED} old backup(s)."
|
||||||
|
else
|
||||||
|
echo "$(date): WARNING - Could not mount SMB for cleanup, skipping."
|
||||||
|
fi
|
||||||
Reference in New Issue
Block a user