Backup e Disaster Recovery do GLPI: Guia Definitivo

Manual de produção para cópia de segurança e disaster recovery do GLPI: dump consistente, o glpicrypt.key que quase toda a gente esquece, rotação, teste de restauro ensaiado e matriz de decisão RPO/RTO.

Uma cópia de segurança que nunca foi restaurada é esperança, não estratégia - e no GLPI a parte que mais estraga o restauro não é o dump da base de dados, é o glpicrypt.key. Na sustentação de ambientes de clientes já vimos um restauro "perfeito" da base em que ninguém mais conseguia autenticar-se por LDAP nem enviar e-mail: os dados voltaram, mas a chave que decifra as palavras-passe de LDAP, SMTP e coletor de e-mail ficou para trás. Este guia consolida a rotina de cópia de segurança, rotação, teste de restauro e disaster recovery que aplicamos em produção, com os pontos onde as coisas realmente partem.

O que tem mesmo de entrar na cópia

O GLPI tem três camadas de estado, e as três têm de voltar juntas e coerentes:

  • Base de dados - pedidos, ativos, utilizadores, regras e configurações. É o coração, mas sozinha não reergue o ambiente.
  • Diretório de ficheiros (files/) - documentos anexados (files/_documents), imagens, inventários XML e dados de plugins. Se a base tem a linha do documento mas o ficheiro não voltou, o utilizador clica e recebe um erro.
  • Configuração (config/) - o config_db.php (anfitrião, base e credenciais) e, sobretudo, o glpicrypt.key. Essa chave decifra as palavras-passe gravadas na base: bind do LDAP, coletor de e-mail, SMTP das notificações e segredos de OAuth. Restaurar a base sem ela deixa todas essas palavras-passe como lixo indecifrável.

Dentro de files/ nem tudo precisa de cópia. Diretórios voláteis como _cache, _tmp, _sessions, _cron e _lock regeneram-se sozinhos e só incham a cópia - exclua-os. O que importa preservar é _documents, _pictures, _uploads, _inventories e _plugins.

Um dump consistente da base

O GLPI 10 e 11 usam InnoDB em todas as tabelas, por isso o --single-transaction tira um snapshot coerente sem bloquear a aplicação - os utilizadores continuam a abrir pedidos durante a cópia. O --quick evita carregar tabelas enormes na memória e o --default-character-set=utf8mb4 impede a corrupção de acentos e emojis. Nunca passe a palavra-passe na linha de comandos (aparece no ps e nos registos); use um ficheiro de credenciais restrito:

# ~/.my.cnf (chmod 600) - evita a palavra-passe no 'ps' e nos registos
[client]
host = 127.0.0.1
user = glpi
password = ...palavra_passe_glpi...

A cópia nativa do GLPI (Administração > Manutenção) grava um .sql em files/_dumps, mas em bases grandes tende a estourar os limites de tempo e memória do PHP. Para produção, um mysqldump agendado é mais fiável.

Script de cópia com rotação

Um único script que trata da base, dos ficheiros e da config pela ordem certa e ainda limpa o que passou dos 30 dias:

#!/usr/bin/env bash
set -euo pipefail

# Credenciais em ~/.my.cnf (chmod 600), nunca na linha de comandos
DATA=$(date +%F)
DEST="/backup/glpi/${DATA}"
mkdir -p "${DEST}"

# Base de dados: snapshot consistente de InnoDB, sem bloquear a aplicacao
mysqldump --single-transaction --quick --routines --triggers \
  --default-character-set=utf8mb4 glpi \
  | gzip -6 > "${DEST}/glpi_db.sql.gz"

# Ficheiros + config DEPOIS do dump (um ficheiro a mais e inofensivo;
# uma linha na base a apontar para um ficheiro em falta, nao)
tar -czf "${DEST}/glpi_files.tar.gz" \
  --exclude='files/_cache' --exclude='files/_tmp' \
  --exclude='files/_sessions' --exclude='files/_lock' \
  -C /var/www/glpi files config

# Rotacao: manter 30 dias
find /backup/glpi -maxdepth 1 -type d -mtime +30 -exec rm -rf {} +

echo "Backup OK: ${DEST}"

Repare na ordem: o dump vem antes do tar. Um ficheiro que caiu no disco depois do dump é inofensivo no restauro; o contrário - uma linha na base a apontar para um ficheiro que ainda não existia quando o tar correu - torna-se um anexo partido. Agende no cron:

# /etc/cron.d/glpi-backup - diario as 02h15
15 2 * * * root /opt/scripts/backup-glpi.sh >> /var/log/glpi-backup.log 2>&1

Matriz de decisão: RPO x RTO

Antes de fechar frequência e retenção, responda a duas perguntas: quantos dados o negócio pode dar-se ao luxo de perder (RPO) e em quanto tempo tem de estar de pé (RTO). A resposta muda consoante a criticidade:

Perfil do ambienteRPO alvoRTO alvoFrequência da baseRetençãoOffsite
Pré-produção / teste24 hdiasdiário7 diasopcional
Produção padrão24 h4 hdiário14-30 diassim (nuvem)
Produção crítica (SLA)15 min1 hdiário + binlog ou réplica30-90 diassim, cifrado

São intervalos honestos, não promessas. Um RPO de 15 minutos exige binlog do MariaDB/MySQL ou uma réplica - o dump diário sozinho não o entrega.

Teste de restauro: o passo que quase ninguém faz

Uma cópia que nunca foi restaurada é um número num relatório, não uma garantia. Ensaie o restauro periodicamente num ambiente descartável - Docker é ideal - e nunca por cima da produção:

# Ambiente DESCARTAVEL (Docker). Nunca ensaie por cima da producao.
mysql -u root -e "CREATE DATABASE glpi_restore CHARACTER SET utf8mb4 COLLATE utf8mb4_unicode_ci"

# 1) Base de dados
zcat glpi_db.sql.gz | mysql --default-character-set=utf8mb4 -u root glpi_restore

# 2) Ficheiros + config (INCLUI o config/glpicrypt.key)
tar -xzf glpi_files.tar.gz -C /var/www/glpi

# 3) Codigo mais recente que o dump? aplica a migracao de esquema
php bin/console db:update --no-interaction

# 4) Limpa a cache e arranca para validar login/LDAP/e-mail
php bin/console cache:clear

Depois do restauro, confirme que o estado corresponde à realidade antes de confiar. Duas consultas rápidas já apanham os problemas mais comuns:

-- Versao gravada na base (tem de coincidir com a do codigo antes do db:update)
SELECT value AS versao_bd
FROM glpi_configs
WHERE context = 'core' AND name = 'version';

-- Quantos documentos apontam para um ficheiro fisico em files/_documents
SELECT COUNT(*) AS docs_com_ficheiro
FROM glpi_documents
WHERE filepath <> '';

A primeira mostra a versão gravada na base: se for inferior à do código, é o db:update que reconcilia o esquema. A segunda conta os documentos que esperam um ficheiro em disco - compare com o que realmente veio no files/_documents. Em Docker, os mesmos passos correm com docker exec -u www-data glpi php bin/console ....

Disaster recovery a sério

Uma cópia é um comando; o disaster recovery é um plano. O mínimo saudável é a regra 3-2-1: três cópias, em dois suportes diferentes, uma delas offsite. E aqui está o erro comum: meter o dump da base e o config/ (com o glpicrypt.key) no mesmo .tar sem cifrar e enviar para um bucket. Quem puser a mão nesse ficheiro tem a base inteira e a chave que decifra as palavras-passe de LDAP, SMTP e coletor - ou seja, credenciais de infraestrutura do cliente em texto recuperável. A cópia offsite tem de ir cifrada (por exemplo com age ou gpg) e com acesso restrito.

Feche o plano com um runbook escrito - onde estão as cópias, qual a ordem de restauro, quem aciona - e com o RTO cronometrado num ensaio real. Na sustentação, o que separa um susto de uma catástrofe nunca foi ter cópia; foi ter restaurado essa cópia antes, com relógio na mão, e saber que ela volta em 40 minutos e não em "não sei".

Se o seu GLPI é crítico e nunca cronometrou um restauro completo - base, ficheiros e a chave de cifra juntos - a NexTool desenha e opera a rotina de cópia de segurança e disaster recovery do seu ambiente, com restauro ensaiado e cópias offsite cifradas. Fale connosco sobre suporte e sustentação de GLPI.


Este conteúdo foi produzido com auxílio de inteligência artificial e revisto pela equipa Nextool Solutions.

Perguntas Frequentes

Use mysqldump --single-transaction: como o GLPI 10 e 11 são todos InnoDB, o dump sai consistente sem bloquear a aplicação, e os utilizadores continuam a abrir pedidos. Faça a cópia dos ficheiros (files/) e da configuração logo a seguir, no mesmo script agendado por cron.

É a chave que decifra as palavras-passe guardadas na base: bind do LDAP, coletor de e-mail, SMTP das notificações e segredos de OAuth. Se restaurar a base mas perdeu o config/glpicrypt.key, essas palavras-passe tornam-se lixo indecifrável e o login por LDAP e o envio de e-mail param. Faça sempre cópia do config/ juntamente com a base.

Base de dados: diária no mínimo, em produção. Ficheiros: diária ou semanal, conforme o volume de anexos. Para um RPO curto (15 a 30 minutos) precisa de binlog do MariaDB ou de uma réplica; só o dump diário dá um RPO até 24 horas.

Restaure-a periodicamente num ambiente descartável (Docker), nunca por cima da produção. Arranque o GLPI, faça login, abra um pedido antigo com anexo e verifique LDAP e o envio de e-mail. Cronometre o processo: esse tempo é o seu RTO real. Uma cópia nunca restaurada não é garantia.

Sim, desde que o código seja igual ou mais recente que o dump. Restaure a base e depois execute php bin/console db:update para migrar o esquema. Nunca restaure um dump mais recente sobre código mais antigo: a estrutura não recua e o ambiente parte.

Mesmo princípio: docker exec no contentor da base para o mysqldump e tar dos volumes montados de files/ e config/. Fixe a versão da imagem (não use :latest) para que o restauro caia num código compatível com o dump.

Precisa de ajuda?