#!/usr/bin/env sh set -eu COMPOSE_FILE="${COMPOSE_FILE:-docker-compose.production.yml}" ENV_FILE="${ENV_FILE:-.env.production}" BACKUP_DIR="${BACKUP_DIR:-./data/backups}" RETENTION_DAYS="${BACKUP_RETENTION_DAYS:-14}" SYNOLOGY_BACKUP_DIR="${SYNOLOGY_BACKUP_DIR:-}" timestamp="$(date -u +%Y%m%d-%H%M%S)" postgres_file="postgres-${timestamp}.dump" config_file="config-${timestamp}.tar.gz" logs_file="logs-${timestamp}.tar.gz" manifest_file="backup-${timestamp}.manifest" mkdir -p "${BACKUP_DIR}" # If SYNOLOGY_BACKUP_DIR wasn't exported in the shell, read it from ENV_FILE. if [ -z "${SYNOLOGY_BACKUP_DIR}" ] && [ -f "${ENV_FILE}" ]; then SYNOLOGY_BACKUP_DIR="$( sed -n 's/^SYNOLOGY_BACKUP_DIR=//p' "${ENV_FILE}" | tail -n 1 )" fi docker compose --env-file "${ENV_FILE}" -f "${COMPOSE_FILE}" exec -T postgres sh -lc \ "PGPASSWORD=\"\$POSTGRES_PASSWORD\" pg_dump -U \"\$POSTGRES_USER\" -d \"\$POSTGRES_DB\" -Fc" \ > "${BACKUP_DIR}/${postgres_file}" cat > "${BACKUP_DIR}/${manifest_file}" < /backup/${logs_file}; fi" # 3) Sync uploads incrementally to Synology (copy only new files). docker compose --env-file "${ENV_FILE}" -f "${COMPOSE_FILE}" run --rm --no-deps \ -v "${SYNOLOGY_BACKUP_DIR}:/backup" \ --entrypoint sh app -lc ' mkdir -p /backup/uploads/documents /backup/uploads/photos; if [ -f /app/uploads/homepage.md ] && [ ! -f /backup/uploads/homepage.md ]; then cp /app/uploads/homepage.md /backup/uploads/homepage.md; fi; if [ -d /app/uploads/documents ]; then cp -an /app/uploads/documents/. /backup/uploads/documents/; fi; if [ -d /app/uploads/photos ]; then cp -an /app/uploads/photos/. /backup/uploads/photos/; fi ' cp "${BACKUP_DIR}/${manifest_file}" "${SYNOLOGY_BACKUP_DIR}/${manifest_file}" # Keep rolling dump/config/log/manifest snapshots on Synology. find "${SYNOLOGY_BACKUP_DIR}" -maxdepth 1 -type f \( \ -name 'postgres-*.dump' -o \ -name 'config-*.tar.gz' -o \ -name 'logs-*.tar.gz' -o \ -name 'backup-*.manifest' \ \) -mtime +"${RETENTION_DAYS}" -delete fi echo "Created backup set:" echo " ${BACKUP_DIR}/${postgres_file}" echo " ${BACKUP_DIR}/${manifest_file}" if [ -n "${SYNOLOGY_BACKUP_DIR}" ]; then echo "Synology artifacts:" echo " ${SYNOLOGY_BACKUP_DIR}/${postgres_file}" echo " ${SYNOLOGY_BACKUP_DIR}/${config_file}" echo " ${SYNOLOGY_BACKUP_DIR}/${logs_file}" echo " ${SYNOLOGY_BACKUP_DIR}/uploads/{homepage.md,documents/,photos/} (incremental)" echo " ${SYNOLOGY_BACKUP_DIR}/${manifest_file}" else echo "SYNOLOGY_BACKUP_DIR not set; skipped Synology copy." fi