#!/usr/bin/env bash set -euo pipefail ROOT_DIR="$(cd "$(dirname "${BASH_SOURCE[0]}")/.." && pwd)" source "${ROOT_DIR}/scripts/docker-prod-common.sh" BACKUP_ROOT="${1:-${ROOT_DIR}/backups}" shift || true EXTRA_VOLUMES=("$@") TIMESTAMP="$(date -u +"%Y%m%dT%H%M%SZ")" mkdir -p "${BACKUP_ROOT}" BACKUP_ROOT="$(cd "${BACKUP_ROOT}" && pwd)" BACKUP_DIR="${BACKUP_ROOT}/rentaldrivego-prod-${TIMESTAMP}" VOLUME_BACKUP_DIR="${BACKUP_DIR}/volumes" DEFAULT_VOLUMES=( "${PROJECT_NAME}_api_uploads" "${PROJECT_NAME}_pgmanage_prod_data" "${PROJECT_NAME}_postgres_prod_data" "${PROJECT_NAME}_redis_prod_data" ) mkdir -p "${BACKUP_DIR}" mkdir -p "${VOLUME_BACKUP_DIR}" ensure_env_file ensure_traefik_network echo "Creating production backup in ${BACKUP_DIR}" prod_compose up -d postgres >/dev/null echo "Backing up PostgreSQL database..." prod_compose exec -T postgres sh -lc 'pg_dump -U "$POSTGRES_USER" -d "$POSTGRES_DB" -Fc' > "${BACKUP_DIR}/postgres.dump" echo "Backing up uploaded files..." prod_compose run --rm --no-deps api bash -lc ' mkdir -p /var/lib/rentaldrivego/storage tar -czf - -C /var/lib/rentaldrivego/storage . ' > "${BACKUP_DIR}/api-uploads.tar.gz" echo "Backing up Traefik certificates..." if traefik_compose run --rm traefik sh -lc 'test -d /letsencrypt' > /dev/null 2>&1; then traefik_compose run --rm traefik sh -lc ' mkdir -p /letsencrypt tar -czf - -C /letsencrypt . ' > "${BACKUP_DIR}/traefik-letsencrypt.tar.gz" else echo "Skipping Traefik certificate backup; Traefik runtime is not available." fi declare -a ALL_VOLUMES=("${DEFAULT_VOLUMES[@]}") if [[ -n "${DOCKER_EXTRA_BACKUP_VOLUMES:-}" ]]; then # shellcheck disable=SC2206 ALL_VOLUMES+=(${DOCKER_EXTRA_BACKUP_VOLUMES}) fi if [[ "${#EXTRA_VOLUMES[@]}" -gt 0 ]]; then ALL_VOLUMES+=("${EXTRA_VOLUMES[@]}") fi echo "Backing up named Docker volumes..." declare -A seen_volumes=() for volume_name in "${ALL_VOLUMES[@]}"; do [[ -n "${volume_name}" ]] || continue if [[ -n "${seen_volumes[${volume_name}]:-}" ]]; then continue fi seen_volumes["${volume_name}"]=1 if ! docker_volume_exists "${volume_name}"; then echo "Skipping missing volume: ${volume_name}" continue fi echo " - ${volume_name}" backup_named_volume "${volume_name}" "${VOLUME_BACKUP_DIR}/${volume_name}.tar.gz" done cat > "${BACKUP_DIR}/manifest.txt" < /dev/null; then echo " - ${VOLUME_BACKUP_DIR}/*.tar.gz" fi echo " - ${BACKUP_DIR}/manifest.txt"