Update backup script
This commit is contained in:
273
scripts/backup.sh
Executable file
273
scripts/backup.sh
Executable file
@@ -0,0 +1,273 @@
|
||||
#!/usr/bin/env sh
|
||||
|
||||
# Adjustable parameters
|
||||
## The number of backups to keep
|
||||
BACKUPS_KEEP=24
|
||||
|
||||
# Global variables (Do NOT change)
|
||||
CLEANUP_FABRIC=false
|
||||
CLEANUP_LUCKPERMS=false
|
||||
CLEANUP_PAPER=false
|
||||
|
||||
main() {
|
||||
log_info "=== Backup run started at $(date -u '+%Y-%m-%dT%H:%M:%SZ') ==="
|
||||
log_info "Keeping last $BACKUPS_KEEP backups"
|
||||
|
||||
check_root_permissions
|
||||
init_backup
|
||||
|
||||
broadcast_status started
|
||||
|
||||
backup_bluemap || cleanup_failure
|
||||
backup_fabric || cleanup_failure
|
||||
backup_luckperms || cleanup_failure
|
||||
backup_paper || cleanup_failure
|
||||
backup_schematics || cleanup_failure
|
||||
backup_velocity || cleanup_failure
|
||||
|
||||
finalize_backup || cleanup_failure
|
||||
prune_backups
|
||||
cleanup_success
|
||||
|
||||
broadcast_status finished
|
||||
|
||||
log_info "=== Backup run completed successfully at $(date -u '+%Y-%m-%dT%H:%M:%SZ') ==="
|
||||
}
|
||||
|
||||
check_root_permissions() {
|
||||
if [ "$EUID" -ne 0 ]; then
|
||||
log_error "This script must be run by the root user"
|
||||
exit 1
|
||||
fi
|
||||
|
||||
log_info "Running as root (EUID=$EUID)"
|
||||
}
|
||||
|
||||
init_backup() {
|
||||
BACKUP_ID="$(date -u +%Y-%m-%dT%H-%M-%SZ)"
|
||||
BACKUP_DIR="/backups/$BACKUP_ID"
|
||||
|
||||
log_info "Creating backup directory: $BACKUP_DIR"
|
||||
|
||||
docker compose run --rm init sh -c '
|
||||
mkdir -p "$1" &&
|
||||
chown minecraft_server:minecraft_server "$1"
|
||||
' -- "$BACKUP_DIR" || {
|
||||
log_error "Failed to create backup directory $BACKUP_DIR"
|
||||
exit 1
|
||||
}
|
||||
|
||||
log_info "Backup directory created and ownership set"
|
||||
}
|
||||
|
||||
broadcast_status() {
|
||||
STATUS="$1"
|
||||
log_info "Broadcasting backup status: $STATUS"
|
||||
|
||||
if docker compose exec -T fabric true > /dev/null 2>&1; then
|
||||
docker compose exec -T fabric rcon-cli "tellraw @a [{\"text\":\"Server\",\"color\":\"light_purple\"},{\"text\":\": Backup $STATUS.\",\"color\":\"white\"}]" > /dev/null 2>&1
|
||||
fi
|
||||
if docker compose exec -T paper true > /dev/null 2>&1; then
|
||||
docker compose exec -T paper rcon-cli "tellraw @a [{\"text\":\"Server\",\"color\":\"light_purple\"},{\"text\":\": Backup $STATUS.\",\"color\":\"white\"}]" > /dev/null 2>&1
|
||||
fi
|
||||
}
|
||||
|
||||
backup_bluemap() {
|
||||
log_info "Starting Bluemap backup..."
|
||||
|
||||
docker compose run --rm init sh -c '
|
||||
cp -a --reflink=auto /bluemap_data "$1" &&
|
||||
cp -a --reflink=auto /bluemap_maps "$1" &&
|
||||
cp -a --reflink=auto /bluemap_web "$1"
|
||||
' -- "$BACKUP_DIR" || return 1
|
||||
|
||||
log_info "Finished Bluemap backup"
|
||||
}
|
||||
|
||||
backup_fabric() {
|
||||
log_info "Starting Fabric backup..."
|
||||
|
||||
CLEANUP_FABRIC=false
|
||||
if docker compose exec -T fabric true > /dev/null 2>&1; then
|
||||
CLEANUP_FABRIC=true
|
||||
log_info "Fabric server detected, disabling saves"
|
||||
|
||||
docker compose exec -T fabric rcon-cli save-off > /dev/null 2>&1
|
||||
docker compose exec -T fabric rcon-cli save-all > /dev/null 2>&1
|
||||
fi
|
||||
|
||||
docker compose run --rm init sh -c '
|
||||
mkdir -p "$1"/fabric_data &&
|
||||
cp -a --reflink=auto /fabric_data/g4mespeed "$1"/fabric_data &&
|
||||
cp -a --reflink=auto /fabric_data/fabric-essentials.json "$1"/fabric_data &&
|
||||
cp -a --reflink=auto /fabric_data/world "$1"/fabric_data
|
||||
' -- "$BACKUP_DIR" || return 1
|
||||
|
||||
log_info "Finished Fabric backup"
|
||||
}
|
||||
|
||||
backup_luckperms() {
|
||||
log_info "Starting LuckPerms backup..."
|
||||
|
||||
CLEANUP_LUCKPERMS=false
|
||||
if ! docker compose exec -T luckperms true > /dev/null 2>&1; then
|
||||
CLEANUP_LUCKPERMS=true
|
||||
log_info "LuckPerms not running, starting temporary container"
|
||||
|
||||
docker compose up --wait luckperms > /dev/null 2>&1
|
||||
fi
|
||||
|
||||
docker compose exec luckperms sh -c '
|
||||
pg_dump -U luckperms luckperms > "$1"/luckperms.sql
|
||||
' -- "$BACKUP_DIR" || return 1
|
||||
|
||||
log_info "Finished LuckPerms backup"
|
||||
}
|
||||
|
||||
backup_paper() {
|
||||
log_info "Starting Paper backup..."
|
||||
|
||||
CLEANUP_PAPER=false
|
||||
if docker compose exec -T paper true > /dev/null 2>&1; then
|
||||
CLEANUP_PAPER=true
|
||||
log_info "Paper server detected, disabling saves"
|
||||
|
||||
docker compose exec -T paper rcon-cli save-off > /dev/null 2>&1
|
||||
docker compose exec -T paper rcon-cli save-all > /dev/null 2>&1
|
||||
fi
|
||||
|
||||
docker compose run --rm init sh -c '
|
||||
mkdir -p "$1"/paper_data/plugins &&
|
||||
cp -a --reflink=auto /paper_data/plugins/Multiverse-Inventories "$1"/paper_data/plugins &&
|
||||
cp -a --reflink=auto /paper_data/plugins/Essentials "$1"/paper_data/plugins &&
|
||||
cp -a --reflink=auto /paper_data/plugins/PlotSquared "$1"/paper_data/plugins &&
|
||||
cp -a --reflink=auto /paper_data/creative "$1"/paper_data &&
|
||||
cp -a --reflink=auto /paper_data/creative_nether "$1"/paper_data &&
|
||||
cp -a --reflink=auto /paper_data/survival "$1"/paper_data &&
|
||||
cp -a --reflink=auto /paper_data/survival_nether "$1"/paper_data &&
|
||||
cp -a --reflink=auto /paper_data/survival_the_end "$1"/paper_data
|
||||
' -- "$BACKUP_DIR" || return 1
|
||||
|
||||
log_info "Finished Paper backup"
|
||||
}
|
||||
|
||||
backup_schematics() {
|
||||
log_info "Starting schematics backup..."
|
||||
|
||||
docker compose run --rm init sh -c '
|
||||
cp -a --reflink=auto /schematics "$1"
|
||||
' -- "$BACKUP_DIR" || return 1
|
||||
|
||||
log_info "Finished schematics backup"
|
||||
}
|
||||
|
||||
backup_velocity() {
|
||||
log_info "Starting Velocity backup..."
|
||||
|
||||
docker compose run --rm init sh -c 'mkdir -p "$1"/velocity_data/plugins/dclink-velocity' -- "$BACKUP_DIR" || return 1
|
||||
|
||||
docker compose run --rm sqlite_helper \
|
||||
/velocity_data/plugins/dclink-velocity/dclink.db \
|
||||
".backup $BACKUP_DIR/velocity_data/plugins/dclink-velocity/dclink.db" || return 1
|
||||
|
||||
log_info "Finished Velocity backup"
|
||||
}
|
||||
|
||||
finalize_backup() {
|
||||
log_info "Finalizing backup $BACKUP_ID"
|
||||
|
||||
docker compose run --rm init chown -R minecraft_server:minecraft_server "$BACKUP_DIR" || {
|
||||
log_error "Failed to update ownership of backup files"
|
||||
return 1
|
||||
}
|
||||
|
||||
log_info "Backup ownership updated"
|
||||
|
||||
docker compose run --rm init sh -c '
|
||||
ln -sfn "$1" /backups/.latest_tmp &&
|
||||
mv -Tf /backups/.latest_tmp /backups/latest
|
||||
' -- "$BACKUP_DIR" || {
|
||||
log_error "Failed to update /backups/latest symlink"
|
||||
return 1
|
||||
}
|
||||
|
||||
log_info "Updated /backups/latest symlink"
|
||||
}
|
||||
|
||||
prune_backups() {
|
||||
BACKUPS_ALL=$(docker compose run --rm init sh -c '
|
||||
find /backups -mindepth 1 -maxdepth 1 -type d \
|
||||
-name "????-??-??T??-??-??Z" | sort
|
||||
')
|
||||
|
||||
BACKUPS_TOTAL=$(echo "$BACKUPS_ALL" | wc -l)
|
||||
BACKUPS_PRUNE=$((BACKUPS_TOTAL - BACKUPS_KEEP))
|
||||
|
||||
[ "$BACKUPS_PRUNE" -le 0 ] && BACKUPS_PRUNE=0
|
||||
|
||||
log_info "Total backups found: $BACKUPS_TOTAL"
|
||||
log_info "Backups to prune: $BACKUPS_PRUNE"
|
||||
|
||||
echo "$BACKUPS_ALL" | head -n "$BACKUPS_PRUNE" | while read -r OLD_BACKUP_DIR; do
|
||||
log_info "Removing old backup: $OLD_BACKUP_DIR"
|
||||
docker compose run --rm init rm -rf "$OLD_BACKUP_DIR"
|
||||
done
|
||||
}
|
||||
|
||||
trap cleanup_trap HUP INT QUIT ABRT TERM
|
||||
cleanup_trap() {
|
||||
log_info "Backup cancelled by signal"
|
||||
broadcast_status cancelled
|
||||
cleanup
|
||||
delete_backup
|
||||
exit 0
|
||||
}
|
||||
|
||||
cleanup_failure() {
|
||||
log_info "Running cleanup due to failure"
|
||||
broadcast_status failed
|
||||
cleanup
|
||||
delete_backup
|
||||
exit 1
|
||||
}
|
||||
|
||||
cleanup_success() {
|
||||
log_info "Running cleanup"
|
||||
cleanup
|
||||
}
|
||||
|
||||
cleanup() {
|
||||
# Ignore specified conditions to ensure cleanup runs to completion uninterrupted
|
||||
trap '' HUP INT QUIT ABRT TERM
|
||||
|
||||
if [ "$CLEANUP_FABRIC" = true ]; then
|
||||
log_info "Re-enabling Fabric saves"
|
||||
docker compose exec -T fabric rcon-cli save-on > /dev/null 2>&1
|
||||
fi
|
||||
|
||||
if [ "$CLEANUP_LUCKPERMS" = true ]; then
|
||||
log_info "Bringing down temporary LuckPerms container"
|
||||
docker compose stop luckperms > /dev/null 2>&1
|
||||
fi
|
||||
|
||||
if [ "$CLEANUP_PAPER" = true ]; then
|
||||
log_info "Re-enabling Paper saves"
|
||||
docker compose exec -T paper rcon-cli save-on > /dev/null 2>&1
|
||||
fi
|
||||
}
|
||||
|
||||
delete_backup() {
|
||||
if ! docker compose run --rm init rm -rf "$BACKUP_DIR"; then
|
||||
log_error "Failed to remove $BACKUP_DIR"
|
||||
fi
|
||||
}
|
||||
|
||||
log_info() {
|
||||
echo "[$(date -u '+%Y-%m-%dT%H:%M:%SZ')] INFO: $*"
|
||||
}
|
||||
|
||||
log_error() {
|
||||
echo "[$(date -u '+%Y-%m-%dT%H:%M:%SZ')] ERROR: $*" >&2
|
||||
}
|
||||
|
||||
main
|
||||
45
scripts/init.sh
Executable file
45
scripts/init.sh
Executable file
@@ -0,0 +1,45 @@
|
||||
#!/usr/bin/env sh
|
||||
|
||||
# Define a helper function that runs a command
|
||||
# If the command fails, the script prints an error message
|
||||
# and exits immediately.
|
||||
run() {
|
||||
# "$@" expands to all arguments passed to this function
|
||||
# and preserves proper word splitting and quoting.
|
||||
"$@" || {
|
||||
echo "Error: command failed: $*" >&2
|
||||
exit 1
|
||||
}
|
||||
}
|
||||
|
||||
# Make sure volumes have correct permissions
|
||||
run chown minecraft_server:minecraft_server /bluemap_data
|
||||
run chown minecraft_server:minecraft_server /bluemap_web
|
||||
run chown minecraft_server:minecraft_server /bluemap_maps
|
||||
run chown minecraft_server:minecraft_server /fabric_data
|
||||
run chown minecraft_server:minecraft_server /luckperms_data
|
||||
run chown minecraft_server:minecraft_server /paper_data
|
||||
run chown minecraft_server:minecraft_server /schematics
|
||||
run chown minecraft_server:minecraft_server /velocity_data
|
||||
|
||||
# Make sure nested volume mount points exist
|
||||
run mkdir -p /fabric_data/bluemap/web/maps
|
||||
run chown minecraft_server:minecraft_server /fabric_data/bluemap
|
||||
run chown minecraft_server:minecraft_server /fabric_data/bluemap/web
|
||||
run chown minecraft_server:minecraft_server /fabric_data/bluemap/web/maps
|
||||
|
||||
run mkdir -p /fabric_data/config/worldedit/schematics
|
||||
run chown minecraft_server:minecraft_server /fabric_data/config
|
||||
run chown minecraft_server:minecraft_server /fabric_data/config/worldedit
|
||||
run chown minecraft_server:minecraft_server /fabric_data/config/worldedit/schematics
|
||||
|
||||
run mkdir -p /paper_data/bluemap/web/maps
|
||||
run chown minecraft_server:minecraft_server /paper_data/bluemap
|
||||
run chown minecraft_server:minecraft_server /paper_data/bluemap/web
|
||||
run chown minecraft_server:minecraft_server /paper_data/bluemap/web/maps
|
||||
|
||||
run mkdir -p /paper_data/plugins/WorldEdit/schematics
|
||||
run chown minecraft_server:minecraft_server /paper_data/plugins
|
||||
run chown minecraft_server:minecraft_server /paper_data/plugins/WorldEdit
|
||||
run chown minecraft_server:minecraft_server /paper_data/plugins/WorldEdit/schematics
|
||||
|
||||
@@ -1,30 +0,0 @@
|
||||
#!/usr/bin/env sh
|
||||
|
||||
# Define a helper function that runs a command
|
||||
# If the command fails, the script prints an error message
|
||||
# and exits immediately.
|
||||
run() {
|
||||
# "$@" expands to all arguments passed to this function
|
||||
# and preserves proper word splitting and quoting.
|
||||
"$@" || {
|
||||
echo "Error: command failed: $*" >&2
|
||||
exit 1
|
||||
}
|
||||
}
|
||||
|
||||
# Ensure required directories exist
|
||||
run mkdir -p /fabric_data/bluemap/web/maps
|
||||
run mkdir -p /fabric_data/config/worldedit/schematics
|
||||
run mkdir -p /paper_data/bluemap/web/maps
|
||||
run mkdir -p /paper_data/plugins/WorldEdit/schematics
|
||||
|
||||
# Ensure correct permissions of docker volumes
|
||||
run chown -R minecraft_server:minecraft_server /bluemap_data
|
||||
run chown -R minecraft_server:minecraft_server /bluemap_web
|
||||
run chown -R minecraft_server:minecraft_server /bluemap_maps
|
||||
run chown -R minecraft_server:minecraft_server /fabric_data
|
||||
run chown -R minecraft_server:minecraft_server /luckperms_data
|
||||
run chown -R minecraft_server:minecraft_server /paper_data
|
||||
run chown -R minecraft_server:minecraft_server /schematics
|
||||
run chown -R minecraft_server:minecraft_server /velocity_data
|
||||
|
||||
@@ -43,7 +43,7 @@ docker exec illegal_crime_paper rcon-cli save-all
|
||||
PG_USER="luckperms"
|
||||
PG_DB="luckperms"
|
||||
BACKUP_DIR_CONTAINER="/backups/$DATE"
|
||||
docker exec illegal_crime_luckperms_db pg_dump -U "$PG_USER" -F c -b -v -f "$BACKUP_DIR_CONTAINER/luckperms.sql" "$PG_DB"
|
||||
docker exec illegal_crime_luckperms pg_dump -U "$PG_USER" -F c -b -v -f "$BACKUP_DIR_CONTAINER/luckperms.sql" "$PG_DB"
|
||||
|
||||
# Copy WorldEdit schematics
|
||||
cp -r "$PROJECT_DIR/schematics" "$BACKUP_DIR_HOST/"
|
||||
@@ -109,4 +109,3 @@ fi
|
||||
# Update permissions of backed up files
|
||||
chown -R "$PUID:$PGID" "$BACKUPS_DIR_HOST"
|
||||
chmod -R 770 "$BACKUPS_DIR_HOST"
|
||||
|
||||
|
||||
Reference in New Issue
Block a user