Add restic backend and update readme
This commit is contained in:
parent
94e894645f
commit
7e4772006f
5 changed files with 214 additions and 25 deletions
97
README.md
97
README.md
|
@ -1,10 +1,18 @@
|
|||
# Minecraft Backup
|
||||
Backup script for Linux servers running a Minecraft server in a GNU Screen
|
||||
Backup script for Linux servers running a Minecraft server in a GNU Screen.
|
||||
|
||||
### Disclaimer
|
||||
Backups are essential to the integrity of your Minecraft world. You should automate regular backups and **check that your backups work**. While this script has been used in production for several years, it is up to you to make sure that your backups work and that you have a reliable backup policy.
|
||||
## Why?
|
||||
### Why not just put `tar` in crontab?
|
||||
If the Minecraft server is currently running, you need to disable world autosaving, or you will likely get an error like this:
|
||||
```
|
||||
tar: /some/path/here/world/region/r.1.11.mca: file changed as we read it
|
||||
```
|
||||
This script will take care of disabling and then re-enabling autosaving for you, and also alert players in the chat of successful backups or errors.
|
||||
This way, you don't have to shut down the server to take backups.
|
||||
You'll also probably need some way to delete old backups, and this script can handle keeping either a number of most recent backups, or thinning them out based on hour/day/week.
|
||||
|
||||
Please refer to the LICENSE (MIT License) for the full legal disclaimer.
|
||||
### Alternatives
|
||||
This script is developed with vanilla servers in mind. If you are running a server with plugins or mods, then you can probably find a backup plugin/mod to do a similar job.
|
||||
|
||||
## Features
|
||||
- Create backups of your world folder
|
||||
|
@ -12,18 +20,22 @@ Please refer to the LICENSE (MIT License) for the full legal disclaimer.
|
|||
- "thin" - keep last 24 hourly, last 30 daily, and use remaining space for monthly backups
|
||||
- "sequential" - delete oldest backup
|
||||
- Choose your own compression algorithm (tested with: `gzip`, `xz`, `zstd`)
|
||||
- Able to print backup status and info to the Minecraft chat
|
||||
- Print backup status and info to the Minecraft chat
|
||||
- Customizable backup backends and Minecraft server interface (currently supports restic)
|
||||
|
||||
## Requirements
|
||||
- Linux computer (tested on Ubuntu)
|
||||
- Linux computer (tested on Arch Linux)
|
||||
- GNU Screen (running your Minecraft server)
|
||||
- Minecraft server (tested with Vanilla 1.10.2 only)
|
||||
- Minecraft server
|
||||
|
||||
## Installation
|
||||
1. Download the script: `$ wget https://raw.githubusercontent.com/nicolaschan/minecraft-backup/master/backup.sh`
|
||||
2. Mark as executable: `$ chmod +x backup.sh`
|
||||
3. Use the command line options or configure default values at the top of `backup.sh`:
|
||||
```bash
|
||||
# Download the scripts
|
||||
git clone https://github.com/nicolaschan/minecraft-backup.git
|
||||
```
|
||||
*NOTE*: You will need to keep `backup.sh` in the same directory as the `src/` directory, since it looks for dependencies in `src/`.
|
||||
|
||||
## Usage Options
|
||||
Command line options:
|
||||
```text
|
||||
-a Compression algorithm (default: gzip)
|
||||
|
@ -31,6 +43,7 @@ Command line options:
|
|||
-d Delete method: thin (default), sequential, none
|
||||
-e Compression file extension, exclude leading "." (default: gz)
|
||||
-f Output file name (default is the timestamp)
|
||||
-g Do not backup (exit) if screen is not running (default: always backup)
|
||||
-h Shows this help text
|
||||
-i Input directory (path to world folder)
|
||||
-l Compression level (default: 3)
|
||||
|
@ -42,33 +55,71 @@ Command line options:
|
|||
-v Verbose mode
|
||||
```
|
||||
|
||||
Example usage of command line options:
|
||||
## Example Usage
|
||||
### One-off Example
|
||||
```bash
|
||||
./backup.sh -c -i /home/server/minecraft-server/world -o /mnt/external-storage/minecraft-backups -s minecraft
|
||||
./backup.sh -c -s minecraft -i minecraft-server/world -o backups/
|
||||
```
|
||||
In this example, we print the status to the Minecraft chat (`-c`) and save a backup of `minecraft-server/world` into `backups/` using the default thinning delete policy for old backups. While this works for performing a single backup, it is _highly_ recommended that you automate your backups.
|
||||
|
||||
### Automated using systemd timers
|
||||
|
||||
### Automated with cron
|
||||
- Edit the crontab:
|
||||
```bash
|
||||
crontab -e
|
||||
```
|
||||
- Example for hourly backups:
|
||||
```
|
||||
00 * * * * /path/to/minecraft-backup/backup.sh -c -s minecraft -i /path/to/minecraft-server/world -o /path/to/backups
|
||||
```
|
||||
This will use show chat messages (`-c`) in the screen called "minecraft" and save a backup of `/home/server/minecraft-server/world` into `/mnt/external-storage/minecraft-backups` using the default thinning delete policy for old backups.
|
||||
|
||||
4. Create a cron job to automatically backup:
|
||||
- Edit the crontab: `$ crontab -e`
|
||||
- Example for hourly backups: `00 * * * * /path/to/backup.sh`
|
||||
|
||||
## Retrieving Backups
|
||||
Always test your backups! Backups are in the `tar` format and compressed depending on the option you choose. To restore, first decompress if necessary and then extract using tar. You may be able to do this in one command if `tar` supports your compression option, as is the case with `gzip`:
|
||||
Always test your backups! Backups are in the `tar` format and compressed depending on the option you choose. To restore, first decompress if necessary and then extract using `tar`. You may be able to do this in one command if `tar` supports your compression option, as is the case with `gzip`:
|
||||
|
||||
Example:
|
||||
```bash
|
||||
mkdir restored-world
|
||||
cd restored-world
|
||||
tar -xzvf /path/to/backups/2019-04-09_02-15-01.tar.gz
|
||||
# if using gzip:
|
||||
gzip -cd 2017-07-31_00-00-00.tar.gz | tar xf - -C restored-world
|
||||
# if using zstd:
|
||||
zstd -cd 2017-07-31_00-00-00.tar.zst | tar xf - -C restored-world
|
||||
```
|
||||
|
||||
Then you can move your restored world (`restored-world` in this case) to your Minecraft server folder and rename it (usually called `world`) so the Minecraft server uses it.
|
||||
|
||||
## Using [restic](https://github.com/restic/restic)
|
||||
The `backup-restic.sh` script provides a similar interface for restic.
|
||||
To specify your repository's password, you'll need to export the `$RESTIC_PASSWORD_FILE` or `$RESTIC_PASSWORD_COMMAND` environment variable.
|
||||
|
||||
```bash
|
||||
restic init -r /path/to/restic-backups
|
||||
touch restic-password.txt # make a new file for your restic password
|
||||
chmod 600 restic-password.txt # make sure only you can read your password
|
||||
echo "my_restic-password" > restic_password.txt
|
||||
export RESTIC_PASSWORD_FILE=$(pwd)/restic_password.txt
|
||||
|
||||
/path/to/minecraft-backup/backup-restic.sh -c -s minecraft -i /path/to/minecraft-server/world -o /path/to/restic-backups
|
||||
```
|
||||
|
||||
When you automate this, you can set the environment variable in the command like so:
|
||||
```bash
|
||||
RESTIC_PASSWORD_FILE=/path/to/restic-password.txt /path/to/minecraft-backup/backup-restic.sh -c -s minecraft -i /path/to/minecraft-server/world -o /path/to/restic-backups
|
||||
```
|
||||
|
||||
## Help
|
||||
- Make sure the compression algorithm you specify is installed on your system. (zstd is not installed by default)
|
||||
- Make sure the compression algorithm you specify is installed on your system. (zstd is not always installed by default)
|
||||
- Make sure your compression algorithm is in the crontab's PATH
|
||||
- Make sure cron has permissions for all the files involved and access to the Minecraft server's GNU Screen
|
||||
- It's surprising how much space backups can take--make sure you have enough empty space
|
||||
- `SERVER_DIRECTORY` should be the server directory, not the `world` directory
|
||||
- Do not put trailing `/` in the `SERVER_DIRECTORY` or `BACKUP_DIRECTORY`
|
||||
- If "thin" delete method is behaving weirdly, try emptying your backup directory or switch to "sequential"
|
||||
|
||||
## Disclaimer
|
||||
Backups are essential to the integrity of your Minecraft world. You should automate regular backups and **check that your backups work**. It is up to you to make sure that your backups work and that you have a reliable backup policy.
|
||||
|
||||
Some backup tips:
|
||||
- Drives get corrupted or fail! Backup to a _different_ drive than the one your server is running on, so if that drive fails then you have backups.
|
||||
- _Automate_ backups so you never lose too much progress.
|
||||
- Check that your backups work from time to time.
|
||||
|
||||
Please refer to the LICENSE (MIT License) for the full legal disclaimer.
|
||||
|
|
100
backup-restic.sh
Executable file
100
backup-restic.sh
Executable file
|
@ -0,0 +1,100 @@
|
|||
#!/usr/bin/env bash
|
||||
|
||||
# Minecraft server automatic backup management script
|
||||
# by Nicolas Chan
|
||||
# https://github.com/nicolaschan/minecraft-backup
|
||||
# MIT License
|
||||
#
|
||||
# For Minecraft servers running in a GNU screen.
|
||||
# For most convenience, run automatically with cron.
|
||||
|
||||
# Default Configuration
|
||||
SCREEN_NAME="" # Name of the GNU Screen your Minecraft server is running in
|
||||
SERVER_WORLD="" # Server world directory
|
||||
BACKUP_DIRECTORY="" # Directory to save backups in
|
||||
EXIT_IF_NO_SCREEN=false # Skip backup if there is no minecraft screen running
|
||||
ENABLE_CHAT_MESSAGES=false # Tell players in Minecraft chat about backup status
|
||||
PREFIX="Backup" # Shows in the chat message
|
||||
DEBUG=false # Enable debug messages
|
||||
SUPPRESS_WARNINGS=false # Suppress warnings
|
||||
|
||||
OPTIND=1
|
||||
while getopts 'cghi:o:p:qs:v' FLAG; do
|
||||
case $FLAG in
|
||||
a) COMPRESSION_ALGORITHM=$OPTARG ;;
|
||||
c) ENABLE_CHAT_MESSAGES=true ;;
|
||||
d) DELETE_METHOD=$OPTARG ;;
|
||||
e) COMPRESSION_FILE_EXTENSION=".$OPTARG" ;;
|
||||
f) TIMESTAMP=$OPTARG ;;
|
||||
g) EXIT_IF_NO_SCREEN=true ;;
|
||||
h) echo "Minecraft Backup Script: https://github.com/nicolaschan/minecraft-backup.git"
|
||||
echo "-c Enable chat messages"
|
||||
echo "-g Do not backup (exit) if screen is not running (default: always backup)"
|
||||
echo "-h Shows this help text"
|
||||
echo "-i Input directory (path to world folder)"
|
||||
echo "-o Output directory"
|
||||
echo "-p Prefix that shows in Minecraft chat (default: Backup)"
|
||||
echo "-q Suppress warnings"
|
||||
echo "-s Minecraft server screen name"
|
||||
echo "-v Verbose mode"
|
||||
exit 0
|
||||
;;
|
||||
i) SERVER_WORLD=$OPTARG ;;
|
||||
l) COMPRESSION_LEVEL=$OPTARG ;;
|
||||
m) MAX_BACKUPS=$OPTARG ;;
|
||||
o) BACKUP_DIRECTORY=$OPTARG ;;
|
||||
p) PREFIX=$OPTARG ;;
|
||||
q) SUPPRESS_WARNINGS=true ;;
|
||||
s) SCREEN_NAME=$OPTARG ;;
|
||||
v) DEBUG=true ;;
|
||||
*) ;;
|
||||
esac
|
||||
done
|
||||
|
||||
BASE_DIR=$(dirname "$(realpath "$0")")
|
||||
|
||||
if ! [[ -d "$BASE_DIR/src" ]]; then
|
||||
echo -e "The src/ directory needs to be in the same directory as backup.sh because it contains other scripts that backup.sh depends on.\n\
|
||||
You should download the entire repository:
|
||||
git clone https://github.com/nicolaschan.com/minecraft-backup.git
|
||||
"
|
||||
exit 1
|
||||
fi
|
||||
|
||||
# shellcheck source=src/logging.sh
|
||||
source "$BASE_DIR/src/logging.sh" \
|
||||
-q "$SUPPRESS_WARNINGS" \
|
||||
-v "$DEBUG"
|
||||
|
||||
# Check for missing encouraged arguments
|
||||
if [[ $SCREEN_NAME == "" ]]; then
|
||||
log-warning "Minecraft screen name not specified (use -s)"
|
||||
fi
|
||||
|
||||
# Check for required arguments
|
||||
MISSING_CONFIGURATION=false
|
||||
if [[ $SERVER_WORLD == "" ]]; then
|
||||
log-fatal "Server world not specified (use -i)"
|
||||
MISSING_CONFIGURATION=true
|
||||
fi
|
||||
if [[ $BACKUP_DIRECTORY == "" ]]; then
|
||||
log-fatal "Backup directory not specified (use -o)"
|
||||
MISSING_CONFIGURATION=true
|
||||
fi
|
||||
if $MISSING_CONFIGURATION; then
|
||||
exit 1
|
||||
fi
|
||||
|
||||
"$BASE_DIR/src/core.sh" \
|
||||
"$BASE_DIR/src/exec-methods/screen.sh" \
|
||||
-s "$SCREEN_NAME" \
|
||||
-- \
|
||||
"$BASE_DIR/src/backup-methods/restic.sh" \
|
||||
-i "$SERVER_WORLD" \
|
||||
-o "$BACKUP_DIRECTORY" \
|
||||
-- \
|
||||
-c "$ENABLE_CHAT_MESSAGES" \
|
||||
-g "$EXIT_IF_NO_SCREEN" \
|
||||
-p "$PREFIX" \
|
||||
-q "$SUPPRESS_WARNINGS" \
|
||||
-v "$DEBUG"
|
10
backup.sh
10
backup.sh
|
@ -36,7 +36,7 @@ while getopts 'a:bcd:e:f:ghi:l:m:o:p:qs:v' FLAG; do
|
|||
e) COMPRESSION_FILE_EXTENSION=".$OPTARG" ;;
|
||||
f) TIMESTAMP=$OPTARG ;;
|
||||
g) EXIT_IF_NO_SCREEN=true ;;
|
||||
h) echo "Minecraft Backup (by Nicolas Chan)"
|
||||
h) echo "Minecraft Backup Script: https://github.com/nicolaschan/minecraft-backup.git"
|
||||
echo "-a Compression algorithm (default: gzip)"
|
||||
echo "-c Enable chat messages"
|
||||
echo "-d Delete method: thin (default), sequential, none"
|
||||
|
@ -68,6 +68,14 @@ done
|
|||
|
||||
BASE_DIR=$(dirname "$(realpath "$0")")
|
||||
|
||||
if ! [[ -d "$BASE_DIR/src" ]]; then
|
||||
echo -e "The src/ directory needs to be in the same directory as backup.sh because it contains other scripts that backup.sh depends on.\n\
|
||||
You should download the entire repository:
|
||||
git clone https://github.com/nicolaschan.com/minecraft-backup.git
|
||||
"
|
||||
exit 1
|
||||
fi
|
||||
|
||||
# shellcheck source=src/logging.sh
|
||||
source "$BASE_DIR/src/logging.sh" \
|
||||
-q "$SUPPRESS_WARNINGS" \
|
||||
|
|
29
src/backup-methods/restic.sh
Executable file
29
src/backup-methods/restic.sh
Executable file
|
@ -0,0 +1,29 @@
|
|||
#!/bin/env bash
|
||||
|
||||
# Backup to restic
|
||||
|
||||
OPTIND=1
|
||||
while getopts 'i:o:' FLAG; do
|
||||
case $FLAG in
|
||||
i) SERVER_WORLD=$OPTARG ;;
|
||||
o) RESTIC_REPO=$OPTARG ;;
|
||||
*) ;;
|
||||
esac
|
||||
done
|
||||
|
||||
minecraft-backup-backup () {
|
||||
restic backup -r "$RESTIC_REPO" "$SERVER_WORLD"
|
||||
}
|
||||
|
||||
minecraft-backup-check () {
|
||||
local WORLD_SIZE_BYTES
|
||||
WORLD_SIZE_BYTES=$(du -b --max-depth=0 "$SERVER_WORLD" | awk '{print $1}')
|
||||
local RESTIC_SIZE
|
||||
RESTIC_SIZE=$(restic stats -r "$RESTIC_REPO" | tail -n1 | awk -F' ' '{ print $3 " " $4 }')
|
||||
echo "$WORLD_SIZE_BYTES/$RESTIC_SIZE"
|
||||
}
|
||||
|
||||
minecraft-backup-epilog () {
|
||||
# do nothing
|
||||
echo -n
|
||||
}
|
|
@ -152,6 +152,7 @@ fi
|
|||
# Record start time for performance reporting
|
||||
START_TIME=$(date +"%s")
|
||||
minecraft-backup-backup
|
||||
BACKUP_RESULT=$?
|
||||
END_TIME=$(date +"%s")
|
||||
|
||||
clean-up
|
||||
|
@ -160,7 +161,7 @@ TIME_DELTA=$((END_TIME - START_TIME))
|
|||
CHECK_MESSAGE=$(minecraft-backup-check)
|
||||
CHECK_RESULT=$?
|
||||
|
||||
if [[ $CHECK_RESULT != "0" ]]; then
|
||||
if [[ $BACKUP_RESULT != "0" ]] || [[ $CHECK_RESULT != "0" ]]; then
|
||||
message-players-error "Backup failed!" "Please notify an admin."
|
||||
exit $CHECK_RESULT
|
||||
fi
|
||||
|
|
Loading…
Add table
Reference in a new issue