Minecraft custom Linux backups using Crontab and Screen

deathcat99

New Member
Jul 29, 2019
6
0
0
Please READ ALL OF THE INTRO BIT first:

INTRO:
Basic world backup in script form with crontab(preps for the more advanced bit)
Most linux servers have crontab installed by default. Crontab is a scheduler program, it basically just lets you run scripts/programs/commands at certain times, days, weeks, months, etc. So to start you need to plan out how often you want to backup, for this example I will show you a backup every hour.
To start off you need to make a shell file, (ext .sh, basically linux's .bat file) so just open up your favorite text editor and save a file as .sh. For windows users using notepad when you go to save, set the "Set as type: to All files (*)" and call it whatever, again for this example I will call mine hourlycp.sh.

Once done lets begin:
It's best practice to make sure to set your directory to the folder that contains your minecraft server folder, not the minecraft server folder itself. My FTBsrv folder in the my user profile /home/deathcat99 so we will start with cd /home/deathcat99

Next the copying itself:
cp -vrf FTBsrv/ backup/ (this will just copy over itself every time the backup script runs. Not ideal, but for this intro it will do.

Now to setup Crontab:
first thing you want to do is type crontab -l most linux environments will return blank, but some will have a brief how to that is commented out (in crontab anything that starts with # is commented and not seen by the system) whether you have something that existing or not, the next step is to edit your current crontab using the command 'crontab -e'
Crontab's use is minute hour day-of-month month day-of-week command so for the use here we would want to add the following line to the file "00 * * * sh /home/deathcat99/hourlycp.sh" ( change the path to your script as neccessary) this will now run the copy script once every hour of every day.

So wrapping up the intro:

hourlycp.sh shuld look like
cd /home/deathcat99
cp -vrf FTBsrv/ backup/

and our crontab should look like
00 * * * sh /home/deathcat99/hourly.sh

Now why am I going this route? Because if we really wanted to we could jut make a crontab entry to:
"00 * * * cp /home/deathcat99/FTBsrv /home/deathcat99/backup" and do the same thing. Because this is expandable as well as wel can do quite a bit more. Thus starts the Advanced bit.
ADVANCED BIT:
Backup script with the ability to send commands to the minecraft server, i.e. save-off, save-all, save-on, say, and so on an so forth.
Well what if you want to do more? like maybe stop saving while you do the copy to make sure everying gets backed up properly and to cut down on lag, or maybe server messages while you back up, well lets start there.

FIRST things first:
For most minecraft server admins that have a minecraft server up 24/7 we use screen. Screen allow you to make a session that allows you to run whatever you want in its own environment without needing user control. (so you can log off) Screen is simple enough to work around. The basics "screen -l" list current screens, "screen -r 'pid or name" attach to a screen using its pid or name, and "ctrl+a+d" disconnect a session without exiting it. So to start run the command screen -ls, this should find nothing unless you already using screen for other things. next just type "screen" and hit enter. This will display a brief how-to(feel free to read though this) but for now just hit enter again, you will be returned to what looks like the normal prompt User@server~$ where you would be entering commands, but if you press the combo ctrl+a+d you will disconnect the session and see a message detached from 'number'.'tty'.'name or host'. Lets take a better look at that, type screen -ls again, now you should see something that look like "1570.pts-1.minecraft (05/13/2014 01:00:23 PM) (Detached)" (if not type screen again, enter through it and try the key combo again) to break this down what you need to know is the 1570. The 1570 or what ever number you have is the pid or process ID, and we will use this to reattach the screen session, ex. screen -r 1570. This will take you back to the previous prompt here you can do anything, start your minecraft server, whatever and it will stay running whether you are logged in or not. Just use the key comb "Ctrl+a+d" to detach at any time and go on with what you were doing.

For this find and attach to your screen session(screen -ls and screen -r pid), or make a new one if you don't have one up(just run screen) then go to your minecraft server folder and start your server Ex. sh Startserver.sh (most ftb server packs). Now that we can get minecraft server to run independently lets get back to the backup script.

SECOND things.
Now we have way more options and a bit more screen commands to utilize. Go back to your backup script and lets add some thing. With screen up and running we can pass commands to our minecraft server using screen. The Use is screen -S pidhere -X stuff 'minecraft command here'$'\n'. So if we wanted to send a server message saying the backup was going to start we could do:
screen -S 1570 -X stuff 'say Server backup starting'$'\n'
Two things to note:
the " $'\n' " is very important, that is the command for the enter key basically
the minecraft command has to be in single not double quotes and the quotes end before the $​
So for example, we want to Alert the players and stop saving on the server, force a save, and then restart saving after the backup...

It would look something like this:
cd /home/deathcat99/
screen -S minecraft -X stuff 'say Server going Read-Only'$'\n'
screen -S minecraft -X stuff 'save-off'$'\n'
screen -S minecraft -X stuff 'save-all'$'\n'
cp -vrf FTBsrv/ backup/
screen -S minecraft -X stuff 'save-on'$'\n'
screen -S minecraft -X stuff 'say Backup Successful'$'\n'

So in wrap up, we didn't have to change the crontab at all, it should still look like this:
00 * * * sh /home/deathcat99/hourlycp.sh

And hourlycp.sh now looks like as it does above.
LOGGING:
Advance script, with output a to a time stamped log file each time.
Okay, for you server admins out there... the script is all well an good, but wheres the proof? How do you know it's backing up regularly and what it's backing up? Well here is an adaptation of the backup script you might like. it saves logs to /home/deathcat99/scripts/logs/hourlycp with the filename hourlycpTIMESTAMPHERE.txt

(cd /home/deathcat99/ ;
echo server msg ;
screen -S minecraft -X stuff 'say Server going Read-Only.'$'\n' ;
echo save-off ;
screen -S minecraft -X stuff 'save-off'$'\n' ;
echo save-all ;
screen -S minecraft -X stuff 'save-all'$'\n' ;
echo copy ;
cp -vrf FTBsrv/ backup/ ;
echo save-on ;
screen -S minecraft -X stuff 'save-on'$'\n' ;
echo copied sucessfully ;
screen -S minecraft -X stuff 'say Backup Successful'$'\n' ;
echo end ;) > scripts/logs/hourlycp/hourlycp$(date +%m.%d.%Y@%H.%M).txt

I'll let you read through that, it should be self explanatory. the output log looks like:
server msg
save-off
save-all
copy
"FILES IT COPIED"
save-on
copied sucessfully
end
And that's that, I hope this helps people. Sorry it's a bit rough, I don't write things like this often. I am more than open to suggestions and comments. If you have any questions feel free to comment. Also I run minecraft from a ramdisk on my linux server, does that interest people?

::CHEAT SHEET::
Basic crontab commands:
crontab -l
list current crontabs​
crontab-e
edit crontab​

Basic screen commands:
screen -ls
list current screen sessions​
screen -r
connect to a screen USE: screen -r 'pid or name'​
screen -S "pid here" -X stuff ' "minecraft server cmd with single quotes" '$'\n'
pass command to minecraft server running in screen session​
 
Last edited:

keybounce

New Member
Jul 29, 2019
1,925
0
0
Very interesting.

I have been doing something similar with cron on an hourly backup, but I have noticed that while it does back up the world chunks well enough, it does not back up any player data for players that are logged on (the player.dat files don't update until the person logs off). Does this technique -- save-off and save-all -- back up the active players as well as the world chunks?
 

deathcat99

New Member
Jul 29, 2019
6
0
0
The basic, "intro" does not, that's just a quick and dirty copy job, but if you look at the advanced bit, you have to be using screen(I assume most do, but if not there's a basic crash course), but that one does. You can pass any commands to the minecraft server you want, including save-off, save-all, and save-on. (See advanced bit)

I added a description to my headers for easier use and recognition.
 
Last edited:

HaoSs

New Member
Jul 29, 2019
290
0
0
Nice script.
I run my FTB using Gamecp so there is no screen windows . So i made a script for my needs
TheCore is my world name. This script is made so you don't have to turn save-off but it dose use more space
Script has 4 parts :
Sync the world in use to a separate Backup folder
Archive the Folder
Move to a external Backup server (same local network)
Delete archives older then 3 days

Code:
#!/bin/bash
echo "Backup Minecraft Worlds"
cd /home/ftbxgamers/service103
sleep 3
echo "Sync World and configs to Backup folder"
sleep 3
rsync -avr TheCore TheCoreBACKUP
sleep 3
rsync -avr plugins TheCoreBACKUP
sleep 3
rsync -avr config TheCoreBACKUP
sleep 3

echo "Sync finished. Making Backup archive,this may take a minute. "
tar -pczf /var/backupFTB/TheCore-$(date +%Y%m%d).tar.gz TheCoreBACKUP/
sleep 3


echo "Moving final backup to external server"
find /var/backupFTB -mtime 0 -print | awk '{print "scp "$0" insert-backup-server-ip-here:/var/backup/FTB/"}' | sh
sleep 3
echo "Backup saved in remote backup server"
sleep 3

echo "Deleting files older than 3 days"
sleep 2
find /var/backupFTB/ -mtime +3 -type f -exec rm -f {} \;
sleep 3
echo "Deleting files older than 3 days finished"
echo "Exiting"

Every time the script runs. It will re-sync only changed files from world / config / plugins folder to backup folder and make archive :)


Also adding to crontab ,using vi editor:
in console type :
crontab -e
press " i "( to start editing )
type: 00 4 * * * /root/backup.sh (runs script every day at 4 AM )
press " escape "
type : " :wq "
 
Last edited:

keybounce

New Member
Jul 29, 2019
1,925
0
0
Warning: player files (inventories, etc) are not saved out without doing the save-all. (Might be saved on dimension change, but I'm not certain).

So anyone active and on-line will not have their information updated.

(I speak from experience; I do exactly this and have learned the limitations.)
 

Connor Gavitt

New Member
Jul 29, 2019
1,091
-1
0
Warning: player files (inventories, etc) are not saved out without doing the save-all. (Might be saved on dimension change, but I'm not certain).

So anyone active and on-line will not have their information updated.

(I speak from experience; I do exactly this and have learned the limitations.)
Player inventories aren't saved during dim change, only during shutdown and save-all however you can schedule saved every few min or have a save scheduled 3 seconds before the backup starts.
 

belgabor

New Member
Jul 29, 2019
574
0
0
Does that "save-all" line actually block script execution until everything is saved? Otherwise the cp could copy content in a half-saved state.
 

Phyrax

New Member
Jul 29, 2019
78
0
0
A simple solution would be to put a sleep in the script after the save-all is ran.
 

smenes

New Member
Jul 29, 2019
167
0
1
there is the script I use using Cron job for backup:
config.cfg
Code:
#!/bin/bash

# Location of minecraft server
MCDIR="/home/downcube/downcube"

# DateTime stamp format that is used in the tar file names.
STAMP=`date +%d-%m-%Y_%H%M%S`

# The screen session name, this is so the script knows where to send the save-all command (for autosave)
SCREENNAME="downcube"

# Whether the script should tell your server to save before backup (requires the server to be running in a screen $
AUTOSAVE=1

# Notify the server when a backup is running.
NOTIFY=1

# Backups DIR name (NOT FILE PATH)
BACKUPDIR="backups"

# MineCraft server properties file name
PROPFILE="server.properties"

# Enable/Disable (0/1) Automatic CronJob Manager
CRONJOB=1

# Update every 'n' Hours (0 to 23)
UPDATEHOURS=3

# Delete backups older than 'n' DAYS
OLDBACKUPS=3

# Enable/Disable Logging (This will just echo each stage the script reaches, for debugging purposes)
LOGIT=1

backup.sh
Code:
#!/bin/bash

# Move into the directory with all Linux-Minecraft-Scripts
cd "$( dirname $0 )"

# Read configuration file
source $PWD/config.cfg

# Set script Directory
SHDIR=$PWD

# *-------------------------* SCRIPT *-------------------------*

cd $MCDIR

# Set todays backup dir

if [ $LOGIT -eq 1 ]
then
  echo "$(date +"%G-%m-%d %H:%M:%S") [LOG] Starting AutoBackup Script.."
  echo "$(date +"%G-%m-%d %H:%M:%S") [LOG] Working in directory: $PWD."
fi

BACKUPDATE=`date +%d-%m-%Y`
FINALDIR="$BACKUPDIR/$BACKUPDATE"

if [ $LOGIT -eq 1 ]
then
  echo "$(date +"%G-%m-%d %H:%M:%S") [LOG] Checking if backup folders exist, if not then create them."
fi

cd $MCDIR

if [ -d $BACKUPDIR ]
then
  echo -n < /dev/null
else
  mkdir "$BACKUPDIR"

  if [ $LOGIT -eq 1 ]
  then
      echo "$(date +"%G-%m-%d %H:%M:%S") [LOG] Created Folder: $BACKUPDIR"
  fi

fi

if [ -d "$FINALDIR" ]
then
  echo -n < /dev/null
else
  mkdir "$FINALDIR"
 
  if [ $LOGIT -eq 1 ]
  then
      echo "$(date +"%G-%m-%d %H:%M:%S") [LOG] Created Folder: $FINALDIR"
  fi

fi

if [ $OLDBACKUPS -lt 0 ]
then
  OLDBACKUPS=3
fi

# Deletes backups that are 'n' days old
if [ $LOGIT -eq 1 ]
then
  echo "$(date +"%G-%m-%d %H:%M:%S") [LOG] Removing backups older than 3 days."
fi
OLDBACKUP=`find $PWD/$BACKUPDIR -type d -mtime +$OLDBACKUPS | grep -v -x "$PWD/$BACKUPDIR" | xargs rm -rf`

#Get level-name
if [ $LOGIT -eq 1 ]
then
  echo "$(date +"%G-%m-%d %H:%M:%S") [LOG] Fetching Level Name.."
fi

while read line
do
  VARI=`echo $line | cut -d= -f1`
  if [ "$VARI" == "level-name" ]
  then
      WORLD=`echo $line | cut -d= -f2`
  fi
done < "$PROPFILE"

if [ $LOGIT -eq 1 ]
then
  echo "$(date +"%G-%m-%d %H:%M:%S") [LOG] Level-Name is $WORLD"
fi

BFILE="$WORLD.$STAMP.tar.gz"
CMD="tar -czf $FINALDIR/$BFILE $WORLD"
BFILEC="config.$STAMP.tar.gz"
CMDC="tar -czf $FINALDIR/$BFILEC config"

if [ $LOGIT -eq 1 ]
then
  echo "$(date +"%G-%m-%d %H:%M:%S") [LOG] Packing and compressing folder: $WORLD to tar file: $FINALDIR/$BFILE"
  echo "$(date +"%G-%m-%d %H:%M:%S") [LOG] Packing and compressing folder: config to tar file: $FINALDIR/$BFILEC"
fi

if [ $NOTIFY -eq 1 ]
then
  screen -x $SCREENNAME -X stuff "`printf "say Backing up world: \'$WORLD\' Server go in readonly\r"`"
fi

#put the server in readonly mode to reduce the chance of backing up half of a chunk.
  screen -x $SCREENNAME -X stuff `printf "save-off\r"`

#Send save-all to the console
if [ $AUTOSAVE -eq 1 ]
then
  screen -x $SCREENNAME -X stuff `printf "save-all\r"`
  sleep 2
fi

# Run backup command
$CMD
$CMDC
screen -x $SCREENNAME -X stuff "`printf "save-on\r"`"

if [ $NOTIFY -eq 1 ]
then
  # Tell server the backup was completed.
  screen -x $SCREENNAME -X stuff "`printf "say Backup Completed.\r"`"
fi

# --Cron Job Install--

cd $SHDIR

if [ $CRONJOB -eq 1 ]
then

  #Work out crontime
  if [ $UPDATEHOURS -eq 0 -o $UPDATEHOURS -lt 0 ]
  then
      MINS="*"
      HOURS="*"
  else
      MINS="0"
      HOURS="*/$UPDATEHOURS"
  fi

  #Check if cronjob exists, if not then create.
  crontab -l > .crons
  EXIST=`crontab -l | grep $0 | cut -d";" -f2`
  CRONSET="$MINS $HOURS * * * cd $PDW;$0"

  if [ "$EXIST" == "$0" ]
  then

      #Check if cron needs updating.
      THECRON=`crontab -l | grep $0`
      if [ "$THECRON" != "$CRONSET" ]
      then
        CRONS=`crontab -l | grep -v "$0"`
        echo "$CRONS" > .crons
        echo "$CRONSET" >> .crons
        crontab .crons
        echo "Cronjob has been updated"
      fi

      rm .crons
      exit
  else
      crontab -l > .crons
      echo "$CRONSET" >> .crons
      crontab .crons
      rm .crons
      echo "Autobackup has been installed."
      exit
  fi

fi