Резервная копия, которую ни разу не восстанавливали, — это надежда, а не стратегия. И в GLPI восстановление чаще всего срывается не из-за дампа базы, а из-за glpicrypt.key. При сопровождении клиентских сред мы уже видели «идеальное» восстановление базы, после которого никто не мог войти через LDAP и отправить e-mail: данные вернулись, но ключ, расшифровывающий пароли LDAP, SMTP и сборщика почты, остался позади. В этом руководстве собран план резервного копирования, ротации, тестового восстановления и аварийного восстановления, который мы применяем в продуктиве, с указанием мест, где всё действительно ломается.
Что действительно должно попасть в резервную копию
У GLPI три слоя состояния, и все три должны вернуться вместе и согласованно:
- База данных — заявки, активы, пользователи, правила и настройки. Это сердце системы, но одна она среду не поднимет.
- Каталог файлов (
files/) — вложенные документы (files/_documents), изображения, XML-инвентаризации и данные плагинов. Если в базе есть строка документа, а сам файл не вернулся, пользователь нажимает на него и получает ошибку. - Конфигурация (
config/) —config_db.php(хост, база и учётные данные) и, главное,glpicrypt.key. Этот ключ расшифровывает пароли, хранящиеся в базе: bind LDAP, сборщик почты (mailcollector), SMTP для уведомлений и секреты OAuth. Восстановление базы без него превращает все эти пароли в нерасшифровываемый мусор.
Внутри files/ резервировать нужно не всё. Временные каталоги вроде _cache, _tmp, _sessions, _cron и _lock создаются заново автоматически и только раздувают копию — исключите их. Сохранять важно _documents, _pictures, _uploads, _inventories и _plugins.
Согласованный дамп базы
GLPI 10 и 11 используют InnoDB во всех таблицах, поэтому --single-transaction делает согласованный снимок без блокировки приложения — пользователи продолжают создавать заявки во время резервного копирования. --quick не даёт загружать огромные таблицы в память, а --default-character-set=utf8mb4 предотвращает порчу диакритики и эмодзи. Никогда не передавайте пароль в командной строке (он виден в ps и в логах); используйте файл учётных данных с ограниченным доступом:
# ~/.my.cnf (chmod 600) - evita a senha no 'ps' e nos logs
[client]
host = 127.0.0.1
user = glpi
password = ...senha_do_glpi...
Встроенное резервное копирование GLPI (Администрирование > Обслуживание) записывает .sql в files/_dumps, но на больших базах оно обычно упирается в лимиты времени и памяти PHP. Для продуктива плановый mysqldump надёжнее.
Скрипт резервного копирования с ротацией
Единый скрипт, который обрабатывает базу, файлы и конфигурацию в правильном порядке и при этом удаляет всё старше 30 дней:
#!/usr/bin/env bash
set -euo pipefail
# Credenciais em ~/.my.cnf (chmod 600), nunca na linha de comando
DATA=$(date +%F)
DEST="/backup/glpi/${DATA}"
mkdir -p "${DEST}"
# Banco: snapshot consistente de InnoDB, sem travar a aplicacao
mysqldump --single-transaction --quick --routines --triggers \
--default-character-set=utf8mb4 glpi \
| gzip -6 > "${DEST}/glpi_db.sql.gz"
# Arquivos + config DEPOIS do dump (arquivo a mais e inofensivo;
# linha no banco apontando para arquivo ausente, 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}"
Обратите внимание на порядок: дамп идёт до tar. Файл, появившийся на диске после дампа, при восстановлении безвреден; обратная ситуация — строка в базе, указывающая на файл, которого ещё не было, когда запускался tar, — превращается в битое вложение. Добавьте задание в cron:
# /etc/cron.d/glpi-backup - diario as 02h15
15 2 * * * root /opt/scripts/backup-glpi.sh >> /var/log/glpi-backup.log 2>&1
Матрица решений: RPO и RTO
Прежде чем определять частоту и срок хранения, ответьте на два вопроса: сколько данных бизнес готов потерять (RPO) и за какое время система должна снова заработать (RTO). Ответ зависит от критичности:
| Профиль среды | Целевой RPO | Целевой RTO | Частота для базы | Срок хранения | Внешняя площадка |
|---|---|---|---|---|---|
| Тестовая / приёмочная | 24 ч | дни | ежедневно | 7 дней | по желанию |
| Стандартный продуктив | 24 ч | 4 ч | ежедневно | 14–30 дней | да (облако) |
| Критичный продуктив (SLA) | 15 мин | 1 ч | ежедневно + binlog или реплика | 30–90 дней | да, в зашифрованном виде |
Это честные диапазоны, а не обещания. RPO в 15 минут требует binlog MariaDB/MySQL или реплики — одного ежедневного дампа для этого недостаточно.
Тестовое восстановление: шаг, который почти никто не делает
Резервная копия, которую ни разу не восстанавливали, — это цифра в отчёте, а не гарантия. Регулярно репетируйте восстановление в одноразовой среде — Docker идеально подходит — и никогда поверх продуктива:
# 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) Banco
zcat glpi_db.sql.gz | mysql --default-character-set=utf8mb4 -u root glpi_restore
# 2) Arquivos + config (INCLUI o config/glpicrypt.key)
tar -xzf glpi_files.tar.gz -C /var/www/glpi
# 3) Codigo mais novo que o dump? aplica a migracao de schema
php bin/console db:update --no-interaction
# 4) Limpa o cache e sobe para validar login/LDAP/e-mail
php bin/console cache:clear
После восстановления убедитесь, что состояние соответствует действительности, прежде чем ему доверять. Два быстрых запроса уже выявляют самые частые проблемы:
-- Versao gravada no banco (precisa casar com a do codigo antes do db:update)
SELECT value AS versao_db
FROM glpi_configs
WHERE context = 'core' AND name = 'version';
-- Quantos documentos apontam para um arquivo fisico em files/_documents
SELECT COUNT(*) AS docs_com_arquivo
FROM glpi_documents
WHERE filepath <> '';
Первый показывает версию, записанную в базе: если она ниже версии кода, схему согласует db:update. Второй считает документы, для которых ожидается файл на диске, — сравните с тем, что действительно пришло в files/_documents. В Docker те же шаги выполняются через docker exec -u www-data glpi php bin/console ....
Настоящее аварийное восстановление
Резервное копирование — это команда; аварийное восстановление — это план. Разумный минимум — правило 3-2-1: три копии на двух разных носителях, одна из них вне площадки. И здесь кроется типичная ошибка: сложить дамп базы и config/ (с glpicrypt.key) в один незашифрованный .tar и отправить его в бакет. Тот, кто получит этот файл, получит всю базу и ключ, расшифровывающий пароли LDAP, SMTP и сборщика почты, — то есть инфраструктурные учётные данные клиента в восстановимом виде. Внешняя резервная копия должна быть зашифрована (например, с помощью age или gpg) и иметь ограниченный доступ.
Завершите план письменным регламентом (runbook) — где лежат копии, в каком порядке восстанавливать, кто запускает процесс — и RTO, замеренным на реальной репетиции. При сопровождении разница между испугом и катастрофой никогда не сводилась к наличию резервной копии: решало то, что эту копию заранее восстановили с секундомером в руках и знают, что она поднимается за 40 минут, а не за «не знаю сколько».
Если ваш GLPI критичен и вы ни разу не замеряли полное восстановление — база, файлы и ключ шифрования вместе, — NexTool спроектирует и будет вести процесс резервного копирования и аварийного восстановления вашей среды с отрепетированным восстановлением и зашифрованной внешней копией. Обсудите с нами поддержку и сопровождение GLPI.
Проверено командой NexTool Solutions.