From 1151b16e52b6ab557c829083f64fa9074434d270 Mon Sep 17 00:00:00 2001 From: Maksym Buz Date: Sun, 4 Jan 2026 13:58:39 +0100 Subject: [PATCH] feat: Add scripts for Docker cleanup and Vaultwarden database backup. --- docker-cleanup.sh | 89 +++++++++++++++++++++++++++++++++++++++++++ vaultwarden-backup.sh | 70 ++++++++++++++++++++++++++++++++++ 2 files changed, 159 insertions(+) create mode 100644 docker-cleanup.sh create mode 100644 vaultwarden-backup.sh diff --git a/docker-cleanup.sh b/docker-cleanup.sh new file mode 100644 index 0000000..bee7623 --- /dev/null +++ b/docker-cleanup.sh @@ -0,0 +1,89 @@ +#!/bin/bash + +# Script: docker-cleanup.sh +# Description: Cleans up unused Docker images, volumes, networks, and builder cache. +# Preserves stopped containers. +# Calculates reclaimed space and logs it to syslog. +# Dependencies: docker, bc, grep (with PCRE support) + +USAGE_TAG="docker-cleanup" + +# Logging functions +log_info() { + logger -t "$USAGE_TAG" -p user.info "$1" +} + +log_error() { + logger -t "$USAGE_TAG" -p user.error "$1" +} + +# Check for 'bc' dependency +if ! command -v bc &> /dev/null; then + log_error "Error: 'bc' is not installed. Please install it (apt install bc) to calculate reclaimed space." + # Fail safe: don't run blindly if we can't calculate/log properly, or just run without logging space? + # User requested logging to syslog, assuming they want the space report. + exit 1 +fi + +log_info "Starting Docker cleanup (Images, Volumes, Networks, Builder)..." + +# Initialize output variable +OUTPUT="" + +# 1. Prune Images (all unused images, not just dangling) with input 'y' just in case, though -f usually covers it +# Note: 'image prune -a' removes images not used by ANY container (including stopped ones). +CMD_OUTPUT=$(docker image prune -a -f 2>&1) +OUTPUT="${OUTPUT}${CMD_OUTPUT}"$'\n' + +# 2. Prune Volumes +CMD_OUTPUT=$(docker volume prune -f 2>&1) +OUTPUT="${OUTPUT}${CMD_OUTPUT}"$'\n' + +# 3. Prune Networks +CMD_OUTPUT=$(docker network prune -f 2>&1) +OUTPUT="${OUTPUT}${CMD_OUTPUT}"$'\n' + +# 4. Prune Builder Cache +CMD_OUTPUT=$(docker builder prune -f 2>&1) +OUTPUT="${OUTPUT}${CMD_OUTPUT}"$'\n' + +# Check for critical failures (though docker commands might succeed partially) +# We proceed to calculate space regardless. + +# Extract reclaimed space amounts using grep with Perl-compatible regex. +RECLAIMED_SPACES=$(echo "$OUTPUT" | grep -Po '(?<=Total reclaimed space: )[0-9.]+[A-Z]+' | grep -v '^0B$') + +# Initialize total reclaimed space counter +TOTAL_RECLAIMED=0 + +# Loop through each reclaimed space value +for SPACE in $RECLAIMED_SPACES; do + # Extract the unit (KB, MB, GB) + UNIT=${SPACE: -2} + # Extract the numeric value + VALUE=${SPACE%${UNIT}} + + # Normalize to GB + case $UNIT in + kB|KB) VAL_IN_GB=$(echo "$VALUE / 1024 / 1024" | bc -l) ;; + mB|MB) VAL_IN_GB=$(echo "$VALUE / 1024" | bc -l) ;; + gB|GB) VAL_IN_GB=$VALUE ;; + *) VAL_IN_GB=0 ;; + esac + + # Add to total + TOTAL_RECLAIMED=$(echo "$TOTAL_RECLAIMED + $VAL_IN_GB" | bc -l) +done + +# Check if we reclaimed anything significant (greater than 0) +IS_POSITIVE=$(echo "$TOTAL_RECLAIMED > 0" | bc -l) + +if [ "$IS_POSITIVE" -eq 1 ]; then + # Format to 3 decimal places + FORMATTED_TOTAL=$(printf "%.3f" "$TOTAL_RECLAIMED") + log_info "Cleanup finished. Total reclaimed space: ${FORMATTED_TOTAL} GB" +else + log_info "Cleanup finished. No significant space was reclaimed." +fi + +exit 0 \ No newline at end of file diff --git a/vaultwarden-backup.sh b/vaultwarden-backup.sh new file mode 100644 index 0000000..70e83ac --- /dev/null +++ b/vaultwarden-backup.sh @@ -0,0 +1,70 @@ +#!/bin/bash +set -euo pipefail + +# --- Settings --- +# Container Name +CONTAINER_NAME="vaultwarden" + +# Host path mapped to /data inside the container +BACKUP_SOURCE_DIR="/home/mbuz/docker/vaultwarden" + +# Destination for backups +BACKUP_DEST_DIR="/mnt/media/vault_backups" + +# Retention Policy: Delete backups older than N days +RETENTION_DAYS=30 + +# Syslog Tag +LOG_TAG="vaultwarden-backup" +# --- End of Settings --- + +# Logging helpers +log_info() { logger -t "$LOG_TAG" -p user.info "$1"; } +log_error() { logger -t "$LOG_TAG" -p user.error "$1"; } + +log_info "Starting Vaultwarden backup..." + +# 1. Mount Check +if [ ! -d "$BACKUP_DEST_DIR" ]; then + log_info "Destination directory not found. Attempting to mount..." + sudo mount -a || true + sleep 2 + if [ ! -d "$BACKUP_DEST_DIR" ]; then + log_error "ERROR: Destination '$BACKUP_DEST_DIR' unavailable after mount attempt." + exit 1 + fi +fi + +# 2. Backup Execution +# We assume the container has 'sqlite3' installed. If not, this will fail safely. +# Format: db_backup_YYYYMMDD_HHMMSS.sqlite3 +TIMESTAMP=$(date +%Y%m%d_%H%M%S) +FILENAME="db_backup_${TIMESTAMP}.sqlite3" + +log_info "Creating backup: $FILENAME" + +# We execute sqlite3 inside the container to safely backup the DB to the /data volume (mapped to host) +if ! docker exec "$CONTAINER_NAME" command -v sqlite3 &>/dev/null; then + log_error "ERROR: 'sqlite3' command not found inside '$CONTAINER_NAME'. Please install it or check image." + exit 1 +fi + +docker exec "$CONTAINER_NAME" sqlite3 /data/db.sqlite3 ".backup '/data/$FILENAME'" + +# 3. Verify and Move +HOST_FILE_PATH="$BACKUP_SOURCE_DIR/$FILENAME" + +if [ -f "$HOST_FILE_PATH" ]; then + mv "$HOST_FILE_PATH" "$BACKUP_DEST_DIR/" + log_info "SUCCESS: Backup moved to $BACKUP_DEST_DIR/$FILENAME" +else + log_error "ERROR: Backup file '$HOST_FILE_PATH' not found on host." + exit 1 +fi + +# 4. Cleanup / Rotation +log_info "Cleaning up backups older than $RETENTION_DAYS days..." +find "$BACKUP_DEST_DIR" -name "db_backup_*.sqlite3" -type f -mtime +$RETENTION_DAYS -delete + +log_info "Backup process completed." +exit 0 \ No newline at end of file