Gerando backup automático do Minecraft quando o servidor estiver vazio (Linux/Bash)

Gerando backup automático do Minecraft quando o servidor estiver vazio (Linux/Bash)

Overview

Neste post superinteressante, você vai descobrir como proteger o seu mundo no Minecraft de desastres inesperados com um script de backup bastante eficaz. Se o seu servidor não é dos mais confiáveis, ou se simplesmente quer garantir que todo o seu esforço construindo e explorando não vá por água abaixo, você está no lugar certo! Através de um guia detalhado, com passos claros e objetivos, você aprenderá a implementar uma solução de backup que roda de forma automática, sem necessidade da sua intervenção constante. Preparado para evitar dores de cabeça e garantir que seu mundo no Minecraft esteja sempre seguro? Então, siga com a leitura!

Um dos problemas de ter um servidor de Minecraft hospedado em um servidor não muito confiável (tipo o CloudAtCost) é que você corre o risco de perder o progresso do seu mundo e ter que começar tudo de novo. Neste post, mostro o exemplo do script que eu fiz para automatizar o backup.

Se a ideia de um backup automático é interessante para você, então leia este post. Ele pode te dar algum insight.

O que acontece é o seguinte: A cada 6 horas, o script verifica se o servidor está vazio (sem ninguém conectado). Se estiver, ele gera um novo backup (archive) e apaga os velhos (para não ficar muito pesado no lado do armazenamento).

A automatização utiliza apenas um bash script, considera uma instalação do Minecraft com o MineOS e adiciona algumas linhas no log do Minecraft, para você conseguir acompanhar quando um backup foi feito. Sei que ele não é perfeito, pois o backup ainda fica armazenado na própria maquina do servidor. Em um post futuro, vou fazer outra versão deste script que seja integrado com o Dropbox ou Onedrive…

Vamos ao script.

Definição de variáveis

Primeiro passo é definir as variáveis que vamos precisar:

# Base config
minecraft_folder="/var/games/minecraft"
servers_folder="servers"
archives_folder="archive"
logs_folder="logs"
world_name="WorldOfOurCraft"
latest_log_folder="$minecraft_folder/$servers_folder/$world_name/$logs_folder"
latest_log="$latest_log_folder/latest.log"
text_to_search="left the game"
backup_filename="server_$world_name$(date +"_%Y%m%d_%H%M%S").tar.gz"
backup_file="$minecraft_folder/$archives_folder/$world_name/$backup_filename"
backup_source_files="$minecraft_folder/$servers_folder/$world_name"
max_backup_days=14

Uma explicação rápida para cada uma destas variáveis:

  1. minecraft_folder: Diretório onde está instalado o Minecraft
  2. servers_folder: Diretório onde ficam os servidores
  3. archives_folder: Diretório onde ficam os backups (archive)
  4. logs_folder: Diretório de logs
  5. world_name: Nome do seu servidor
  6. latest_log_folder: Diretório onde está o log “latest.log”
  7. latest_log: Caminho completo para o arquivo “latest.log”
  8. text_to_search: Texto que será procurado no log
  9. backup_filename: Nome do backup que vai ser gerado. ele inclui um timestamp com o formato: aaaammdd_hhmmss
  10. backup_file: Caminho completo para o arquivo de backup
  11. backup_source_files: Caminho para os arquivos que serão incluídos no backup.
  12. max_backup_days: Número máximo de dias que um backup pode ter. Arquivos criados ha mais tempo (em dias) do que o valor desta variável, serão apagados.

Seria possível diminuir a quantidade de variáveis, mas achei assim mais simples/didático. você deve alterar as que forem pertinentes para a sua instalação.

Verificação do log

O segundo passo é extrair a última linha do log atual (latest.log), se ela possuir um determinado texto:

last_log_line=$(tail  -n 1 $latest_log | grep -a "$text_to_search")

Este comando vai ler o arquivo e salvar a ultima linha do log, se ela possuir o texto “left the game”, que é o texto padrão que o Minecraft escreve quando um usuário se desconecta do servidor. O pulo do gato está neste ponto. Enquanto as pessoas estão jogando ou quando o mundo está sendo carregado, o servidor escreve diversas coisas no log. Assim que um usuário se desconecta, ele escreve “<nome do jogador> left the game” e se ninguém mais estiver jogando, esta será a última linha do log.

O comando em si é bem simples:

  1. Primeiro utilizo o tail para recuperar a última linha do log
  2. Depois utilizo o grep para “filtrar” se a linha e verificar se ela possui o texto que estamos procurando ($text_to_search). Se o texto não for encontrado, a variável fica vazia.

Verificação de pacotes obrigatórios

Neste passo, verifico se o pacote tar está instalado.

tar_exists=$(dpkg -l | grep -c "tar archiving")

A lógica aqui é bem semelhante a do passo anterior:

  1. Listo os pacotes instalados (dpkg -l);
  2. Procuro pelo texto “tar archiving” na lista (grep -c “tar archiving”). A diferença é que o argumento -c do grep vai retornar o número de ocorrências. Sendo assim, se a variável tar_exists for igual a zero, o pacote não está instalado.

Esta parte é meio que um preciosismo meu. Não acho que alguém vai utilizando uma instalação do linux sem o pacote tar, mas ok…

Criando funções auxiliares

Para organizar as coisas, criei duas funções auxiliares:

add_line_to_log() {
    echo "[$(date +"%T")] [Backup thread/INFO]: $1" >> $latest_log
}

A função acima adiciona um texto no log atual (latest.log) com timestamp e o indicador de que é o serviço de backup (Backup thread/INFO)

A segunda:

remove_old_backups() {
    find $minecraft_folder/$archives_folder/$world_name* -mtime +$max_backup_days -exec rm {} \;
}

Esta função remove os backups antigos. Expliquei ela com detalhes no post “Apagando arquivos com mais de X dias (Linux/Bash)”.

Criando parte de execução do script

A primeira parte da execução é verificar se o pacote tar está instalado. Para isso, utilizo a variável tar_exists (criada anteriormente:

# Pre backup...
if [[ $tar_exists = 0 ]]; then
    echo "ERROR: Tar package isnt installed! We need that..."
    echo "Try: apt-get install tar"
    exit -1
fi

Se ela for igual a zero, o pacote não está instalado e o script é encerrado.

Agora verifico se a variável last_log_line está vazia. Se estiver, a última linha do log não possuir o texto “left the game”, não está na hora de fazer backup. Esta verificação fica assim:

# Backup routine...
if [[ "$last_log_line" = "" ]]; then
    # Probably somebody has played or is playing...
    echo "Someone is playing. Maybe later..."
else 
    # Assuming the server is empty...
    # Someone has left and nothing else happened. It's safe to make a backup...probably.
    echo "Server empty. Backing stuff up..."
    add_line_to_log "Automatic backup in progress..."

    # Creates the archive
    tar --exclude="./*.log" --exclude="./$logs_folder/*.log" --exclude="./$logs_folder/*.log.gz" -zcvf "$backup_file" "$backup_source_files"

    # Removing old backups
    remove_old_backups

    # Adding another line to the log, to show everythings OK.
    add_line_to_log "Automatic backup finished successfully!"    
    
fi

A clausula else é onde ocorrerá o backup.

Explicação para os comandos que são executados:

add_line_to_log "Automatic backup in progress..."

Adiciona uma linha no log atual (latest.log), informando que o backup automático está sendo feito.

tar --exclude="./*.log" --exclude="./$logs_folder/*.log" --exclude="./$logs_folder/*.log.gz" -zcvf "$backup_file" "$backup_source_files"

O comando acima cria o arquivo de backup. Como ele está com vários argumentos, vou detalhar melhor este comando:

  1. –exclude="***": Tudo que for indicado nestes argumentos é ignorado na hora de criar o arquivo. Sendo assim, estou excluindo os logs dos arquivos de backup.
  2. -zcvf: Cada uma destas letras representa uma configuração..
    z: Compacta o arquivo utilizando gzip;
    c: Cria arquivo (em oposição ao x, que extrai o conteúdo de um arquivo compactado)
    v: Mostra o progresso da operação. Se for omitido, o arquivo vai ser criado “silenciosamente”
    f: Indica que será especificado um nome para o arquivo compactado que está sendo criado.

Os próximos dois argumentos são, respectivamente, o nome do arquivo que será criado e o local onde estão os arquivos que serão incluídos no backup.

remove_old_backups

Chama a função criada anteriormente, que vai apagar os backups que tem mais de 14 dias.

add_line_to_log "Automatic backup finished successfully!"

Adiciona outra linha no arquivo de log, informando que o backup foi feito com sucesso.

Se o script passar deste ponto, encerro a execução retornando o código de sucesso:

# OK
exit 0

O script completo está no meu Github.

Automatizando o backup

O script está feito, mas ele ainda não está sendo executando a automaticamente, ou seja, o “fazedor de backups” existe, ele só não é automático… ainda.

Supondo que você tenha salvado o script no caminho /scripts/backcraft.sh

A primeira coisa que você tem que fazer é marcar este script como executável com o comando abaixo:

chmod +x /scripts/backcraft.sh

Agora temos que editar o crontab para inserir este novo job com o comando:

crontab -e

Adicione a seguinte linha ao crontab:

0 */6 * * * /script/backcraft.sh

Salve as alterações e pronto! Backup automatizado!

Espero ter ajudado!