Add rcon
This commit is contained in:
parent
904e6c3887
commit
11aa6bfe53
2 changed files with 136 additions and 11 deletions
34
README.md
34
README.md
|
@ -1,5 +1,9 @@
|
||||||
# Minecraft Backup
|
# Minecraft Backup
|
||||||
Backup script for Linux servers running a Minecraft server in a GNU Screen or tmux
|

|
||||||
|
[](https://codecov.io/gh/nicolaschan/minecraft-backup)
|
||||||
|
|
||||||
|
Backup script for Linux servers running a Minecraft server.
|
||||||
|
Supports servers running in [GNU screen](https://en.wikipedia.org/wiki/GNU_Screen), [tmux](https://en.wikipedia.org/wiki/Tmux), or with [rcon](https://wiki.vg/RCON) enabled.
|
||||||
|
|
||||||
### Disclaimer
|
### 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.
|
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.
|
||||||
|
@ -12,17 +16,26 @@ 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
|
- "thin" - keep last 24 hourly, last 30 daily, and use remaining space for monthly backups
|
||||||
- "sequential" - delete oldest backup
|
- "sequential" - delete oldest backup
|
||||||
- Choose your own compression algorithm (tested with: `gzip`, `xz`, `zstd`)
|
- Choose your own compression algorithm (tested with: `gzip`, `xz`, `zstd`)
|
||||||
|
- Works on vanilla -- no plugins required
|
||||||
- Able to print backup status and info to the Minecraft chat
|
- Able to print backup status and info to the Minecraft chat
|
||||||
|
|
||||||
|
## Why not just use `tar` directly?
|
||||||
|
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 script also manages deleting old backups.
|
||||||
|
|
||||||
## Requirements
|
## Requirements
|
||||||
- Linux computer (tested on Ubuntu)
|
- Linux computer (tested on Ubuntu)
|
||||||
- GNU Screen (running your Minecraft server)
|
- GNU Screen (running your Minecraft server)
|
||||||
- Minecraft server (tested with Vanilla 1.10.2 only)
|
- Minecraft server
|
||||||
|
|
||||||
## Installation
|
## Quick Start
|
||||||
1. Download the script: `$ wget https://raw.githubusercontent.com/nicolaschan/minecraft-backup/master/backup.sh`
|
```bash
|
||||||
2. Mark as executable: `$ chmod +x backup.sh`
|
wget https://raw.githubusercontent.com/nicolaschan/minecraft-backup/master/backup.sh`
|
||||||
3. Use the command line options or configure default values at the top of `backup.sh`:
|
chmod +x backup.sh
|
||||||
|
```
|
||||||
|
|
||||||
Command line options:
|
Command line options:
|
||||||
```text
|
```text
|
||||||
|
@ -47,11 +60,11 @@ Example usage of command line options:
|
||||||
```bash
|
```bash
|
||||||
./backup.sh -c -i /home/server/minecraft-server/world -o /mnt/external-storage/minecraft-backups -s minecraft
|
./backup.sh -c -i /home/server/minecraft-server/world -o /mnt/external-storage/minecraft-backups -s minecraft
|
||||||
```
|
```
|
||||||
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.
|
This will 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:
|
### Create a cron job to automatically backup:
|
||||||
- Edit the crontab: `$ crontab -e`
|
- Edit the crontab with `crontab -e`
|
||||||
- Example for hourly backups: `00 * * * * /path/to/backup.sh`
|
- Example for hourly backups: `00 * * * * /path/to/backup.sh ...`
|
||||||
|
|
||||||
## Retrieving Backups
|
## 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`:
|
||||||
|
@ -70,6 +83,5 @@ Then you can move your restored world (`restored-world` in this case) to your Mi
|
||||||
- Make sure your compression algorithm is in the crontab's PATH
|
- 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
|
- 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
|
- 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`
|
- 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"
|
- If "thin" delete method is behaving weirdly, try emptying your backup directory or switch to "sequential"
|
||||||
|
|
113
rcon.sh
Executable file
113
rcon.sh
Executable file
|
@ -0,0 +1,113 @@
|
||||||
|
#!/usr/bin/env bash
|
||||||
|
|
||||||
|
reverse-hex-endian () {
|
||||||
|
# Given a 4-byte hex integer, reverse endianness
|
||||||
|
while read -r -d '' -N 8 INTEGER; do
|
||||||
|
echo "$INTEGER" | sed -E 's/(..)(..)(..)(..)/\4\3\2\1/'
|
||||||
|
done
|
||||||
|
}
|
||||||
|
|
||||||
|
decode-hex-int () {
|
||||||
|
# decode little-endian hex integer
|
||||||
|
while read -r -d '' -N 8 INTEGER; do
|
||||||
|
BIG_ENDIAN_HEX=$(echo "$INTEGER" | reverse-hex-endian)
|
||||||
|
echo "$((16#$BIG_ENDIAN_HEX))"
|
||||||
|
done
|
||||||
|
}
|
||||||
|
|
||||||
|
encode-int () {
|
||||||
|
# Encode an integer as 4 bytes in little endian and return as hex
|
||||||
|
INT="$1"
|
||||||
|
# Source: https://stackoverflow.com/a/9955198
|
||||||
|
printf "%08x" "$INT" | sed -E 's/(..)(..)(..)(..)/\4\3\2\1/'
|
||||||
|
}
|
||||||
|
|
||||||
|
encode () {
|
||||||
|
# Encode a packet type and payload for the rcon protocol
|
||||||
|
TYPE="$1"
|
||||||
|
PAYLOAD="$2"
|
||||||
|
REQUEST_ID="$3"
|
||||||
|
PAYLOAD_LENGTH="${#PAYLOAD}"
|
||||||
|
TOTAL_LENGTH="$((4 + 4 + PAYLOAD_LENGTH + 1 + 1))"
|
||||||
|
|
||||||
|
OUTPUT=""
|
||||||
|
OUTPUT+=$(encode-int "$TOTAL_LENGTH")
|
||||||
|
OUTPUT+=$(encode-int "$REQUEST_ID")
|
||||||
|
OUTPUT+=$(encode-int "$TYPE")
|
||||||
|
OUTPUT+=$(echo -n "$PAYLOAD" | xxd -ps)
|
||||||
|
OUTPUT+="0000"
|
||||||
|
|
||||||
|
echo -n "$OUTPUT" | xxd -ps -r
|
||||||
|
}
|
||||||
|
|
||||||
|
read-response () {
|
||||||
|
# read next response packet and return the payload text
|
||||||
|
IN_PIPE="$1"
|
||||||
|
# HEX_LENGTH=$(head -c4 "$IN_PIPE" | xxd -ps | reverse-hex-endian)
|
||||||
|
HEX_LENGTH=$(head -c4 <&3 | xxd -ps | reverse-hex-endian)
|
||||||
|
LENGTH=$((16#$HEX_LENGTH))
|
||||||
|
|
||||||
|
RESPONSE_PAYLOAD=$(head -c $LENGTH <&3 | xxd -ps)
|
||||||
|
echo -n "$RESPONSE_PAYLOAD"
|
||||||
|
}
|
||||||
|
|
||||||
|
response-request-id () {
|
||||||
|
echo -n "${1:0:8}" | decode-hex-int
|
||||||
|
}
|
||||||
|
|
||||||
|
response-type () {
|
||||||
|
echo -n "${1:8:8}" | decode-hex-int
|
||||||
|
}
|
||||||
|
|
||||||
|
response-payload () {
|
||||||
|
echo -n "${1:16:-4}" | xxd -r -ps
|
||||||
|
}
|
||||||
|
|
||||||
|
login () {
|
||||||
|
PASSWORD="$1"
|
||||||
|
encode 3 "$PASSWORD" 12 >&3
|
||||||
|
|
||||||
|
RESPONSE=$(read-response "$IN_PIPE")
|
||||||
|
|
||||||
|
RESPONSE_REQUEST_ID=$(response-request-id "$RESPONSE")
|
||||||
|
if [ "$RESPONSE_REQUEST_ID" -eq -1 ] || [ "$RESPONSE_REQUEST_ID" -eq 4294967295 ]; then
|
||||||
|
echo "Authentication failed: Wrong RCON password" 1>&2
|
||||||
|
return 1
|
||||||
|
fi
|
||||||
|
}
|
||||||
|
|
||||||
|
run-command () {
|
||||||
|
COMMAND="$1"
|
||||||
|
|
||||||
|
# encode 2 "$COMMAND" 13 >> "$OUT_PIPE"
|
||||||
|
encode 2 "$COMMAND" 13 >&3
|
||||||
|
|
||||||
|
RESPONSE=$(read-response "$IN_PIPE")
|
||||||
|
response-payload "$RESPONSE"
|
||||||
|
}
|
||||||
|
|
||||||
|
rcon-command () {
|
||||||
|
HOST="$1"
|
||||||
|
PORT="$2"
|
||||||
|
PASSWORD="$3"
|
||||||
|
COMMAND="$4"
|
||||||
|
|
||||||
|
# Open a TCP socket
|
||||||
|
# Source: https://www.xmodulo.com/tcp-udp-socket-bash-shell.html
|
||||||
|
exec 3<>/dev/tcp/"$HOST"/"$PORT"
|
||||||
|
|
||||||
|
login "$PASSWORD" || return 1
|
||||||
|
run-command "$COMMAND"
|
||||||
|
|
||||||
|
# Close the socket
|
||||||
|
exec 3<&-
|
||||||
|
exec 3>&-
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
|
HOST="$1"
|
||||||
|
PORT="$2"
|
||||||
|
PASSWORD="$3"
|
||||||
|
COMMAND="$4"
|
||||||
|
|
||||||
|
rcon-command "$HOST" "$PORT" "$PASSWORD" "$COMMAND"
|
Loading…
Add table
Reference in a new issue