Бэкап и восстановление Apache Guacamole
Guacamole незаметно становится критичной точкой инфраструктуры: через неё заходят на десятки RDP- и VNC-хостов, отдают доступ подрядчикам, иногда пишут видеозаписи сессий для аудита. Если шлюз падает вместе с сервером, вы теряете не просто веб-интерфейс — вы теряете список всех подключений, права пользователей и, если запись включена, архив сессий. Разберём, что конкретно нужно сохранять, как автоматизировать бэкап и как поднять рабочий Guacamole на новом сервере без ручного пересоздания подключений.
Содержание
Обсудить статью, задать вопрос или начать новую тему
Есть вопрос по этой статье, идея для обсуждения или просто хотите поделиться опытом? Сообщество MAATRIX ждёт. Для общения, пожалуйста, зарегистрируйтесь в нашем личном кабинете.
Перейти в сообщество →Что именно нужно бэкапить
Типичная установка Guacamole (по официальному docker-compose, как в статье про установку Apache Guacamole на VPS) состоит из трёх сервисов и нескольких мест хранения данных. Не всё в ней одинаково важно для восстановления.
| Компонент | Что хранит | Нужно бэкапить |
|---|---|---|
MySQL (volume mysql-data) | пользователей, группы, подключения (хосты, порты, учётные записи), права доступа, историю сессий | да, это основа всего |
| guacd | сам протокольный демон, состояния не хранит | нет, он безусловно эфемерный |
| каталог записей сессий (recordings) | видео RDP/VNC-сессий, если включена запись | да, если запись используется — но отдельной стратегией |
docker-compose.yml и .env / переменные MySQL | пароли к БД, версии образов, конфигурация reverse proxy | да, критично |
| расширения (extensions) — TOTP, LDAP, Duo, banner | конфигурация дополнительных jar-плагинов | да, если используются |
Главная ловушка Guacamole в том, что пароли к RDP/VNC-хостам в стандартной конфигурации хранятся в базе MySQL в открытом виде, если вы не подключили расширение шифрования атрибутов подключений. Это значит, что дамп базы — чувствительные данные наравне с паролями от самих серверов, и обращаться с ним нужно соответственно: шифровать при передаче за пределы сервера и ограничивать доступ к каталогу бэкапов.
guacd бэкапить не нужно вообще — это чистый протокольный прокси без состояния, он поднимается заново из образа за секунды.
Бэкап базы MySQL
Вся содержательная часть Guacamole — подключения, пользователи, права, история — живёт в MySQL. Дамп снимается напрямую из контейнера через mysqldump, без остановки сервисов:
cd /opt/guacamole
mkdir -p /opt/guacamole-backup/db
docker compose exec -T guac-db mysqldump \
-u root -p"СМЕНИТЕ_МЕНЯ_root" \
--single-transaction --routines --triggers \
guacamole_db > /opt/guacamole-backup/db/guacamole_$(date +%F_%H%M).sql
Флаг --single-transaction важен: он снимает консистентный снапшот InnoDB-таблиц без блокировки на запись, так что активные сессии пользователей во время бэкапа не оборвутся. Пароль лучше не держать в командной строке в открытую — вынесите его в .my.cnf внутри контейнера или читайте из переменной окружения .env, как это сделано в базовой установке.
Проверяйте, что дамп не пустой перед тем, как доверять ему в ротации:
test -s /opt/guacamole-backup/db/guacamole_$(date +%F_%H%M).sql || echo "BACKUP FAILED" >&2
Если у вас PostgreSQL вместо MySQL (образ поддерживает оба варианта) — команда аналогичная через pg_dump -Fc, принцип тот же: снапшот без блокировки записи, проверка на пустой файл, ротация.
Нужен сервер под эту задачу?
Разверните VPS MAATRIX за пару минут: NVMe, AMD EPYC, root-доступ, локации UK, США, Франция и РФ. Оплата картой РФ и по СБП.
Арендовать серверБэкап записей сессий — отдельная задача
Если в Guacamole включена запись сессий (параметр recording-path в настройках подключения), видеофайлы сессий копятся в volume на хосте и быстро перерастают размер базы данных — RDP-сессия в высоком разрешении за час может весить сотни мегабайт. Бэкапить их той же логикой, что и базу (полный tar каждую ночь), — неэффективно и дорого по месту.
Практичнее развести стратегии:
- База MySQL — полный дамп каждую ночь, файлы небольшие, ротация агрессивная.
- Recordings — инкрементальная синхронизация или бэкап с дедупликацией, потому что старые записи не меняются, а новые накапливаются.
Для recordings разумно использовать restic или BorgBackup — оба умеют дедуплицировать неизменные файлы между снапшотами, так что повторный полный бэкап каталога с сотнями видео не удваивает место на диске:
restic -r /opt/guacamole-backup/restic-repo backup \
/opt/guacamole/recordings --tag guacamole-recordings
Как это настроить с нуля и что учитывать по объёму хранилища — разобрано в статье про бэкап и восстановление Restic. Если записи сессий вам нужны только для разбора инцидентов за последние 2-3 месяца, а не бессрочно — добавьте политику удаления старых записей на самом Guacamole (recording-path с автоматической чисткой через cron) до того, как каталог разрастётся до неподъёмного размера.
Бэкап конфигурации и расширений
Конфигурация небольшая, но без неё восстановление сводится к угадыванию паролей и настроек reverse proxy заново:
mkdir -p /opt/guacamole-backup/config
cp /opt/guacamole/docker-compose.yml /opt/guacamole-backup/config/compose_$(date +%F).yml
cp -r /opt/guacamole/extensions /opt/guacamole-backup/config/extensions_$(date +%F) 2>/dev/null || true
cp /etc/nginx/sites-available/guacamole.conf /opt/guacamole-backup/config/nginx_$(date +%F).conf 2>/dev/null || true
Если используете расширения — TOTP, LDAP, кастомный banner или Duo — их jar-файлы и .properties конфиги лежат в каталоге extensions, который монтируется в контейнер guacamole. Без них после восстановления MFA и LDAP-интеграция отвалятся, даже если база восстановится штатно.
Скрипт автоматического бэкапа и cron
Собираем базу, конфиги и облегчённую версию recordings (только новые файлы через restic) в один скрипт:
#!/usr/bin/env bash
set -euo pipefail
BACKUP_DIR=/opt/guacamole-backup
DATE=$(date +%F_%H%M)
KEEP_DAYS=14
cd /opt/guacamole
mkdir -p "${BACKUP_DIR}"/{db,config}
# дамп базы
docker compose exec -T guac-db mysqldump \
-u root -p"${MYSQL_ROOT_PASSWORD}" \
--single-transaction --routines --triggers guacamole_db \
> "${BACKUP_DIR}/db/guacamole_${DATE}.sql"
test -s "${BACKUP_DIR}/db/guacamole_${DATE}.sql" || { echo "DB BACKUP FAILED" >&2; exit 1; }
# конфигурация
cp docker-compose.yml "${BACKUP_DIR}/config/compose_${DATE}.yml"
[ -d extensions ] && cp -r extensions "${BACKUP_DIR}/config/extensions_${DATE}"
# записи сессий — только новые/изменённые, через restic
if [ -d /opt/guacamole/recordings ]; then
restic -r "${BACKUP_DIR}/restic-repo" backup /opt/guacamole/recordings \
--tag guacamole-recordings --quiet
fi
# ротация локальных дампов и конфигов (recordings ротирует restic отдельно через forget)
find "${BACKUP_DIR}/db" "${BACKUP_DIR}/config" -type f -mtime +${KEEP_DAYS} -delete
Ставим в cron под пользователем с доступом к docker-сокету, дамп базы — каждую ночь, recordings можно чуть реже, если сессии пишутся нечасто:
0 3 * * * MYSQL_ROOT_PASSWORD=СМЕНИТЕ_МЕНЯ_root /opt/guacamole-backup/backup.sh >> /var/log/guacamole-backup.log 2>&1
Пароль в переменной окружения cron-задачи — не лучшее место для секрета в продакшене; надёжнее читать его из .env через source или из отдельного файла с правами 600. Каталог с бэкапами обязательно закройте от посторонних:
chmod 700 /opt/guacamole-backup
chown root:root /opt/guacamole-backup
Дамп базы и recordings обязательно должны уходить за пределы сервера — если единственная копия лежит на том же диске, что и рабочий Guacamole, при потере сервера вы теряете и данные, и бэкап одновременно. Общий подход к восстановлению из офсайт-копии для любой БД разобран в статье восстановление базы данных из бэкапа на практике.
Восстановление на новом сервере
Сценарий: старый VPS недоступен, есть последний дамп MySQL, конфиги и (опционально) restic-репозиторий с recordings.
1. Поднимите Docker и разверните конфигурацию:
mkdir -p /opt/guacamole && cd /opt/guacamole
cp /path/to/backup/config/compose_LATEST.yml docker-compose.yml
[ -d /path/to/backup/config/extensions_LATEST ] && cp -r /path/to/backup/config/extensions_LATEST extensions
Убедитесь, что пароли MySQL в docker-compose.yml совпадают с теми, что были в оригинальной установке (или что вы восстанавливаете дамп под новым паролем, но тогда не забудьте поменять его и в конфиге сервиса guacamole).
2. Поднимите только базу данных и дождитесь готовности:
docker compose up -d guac-db
docker compose logs -f guac-db # ждём "ready for connections"
3. Восстановите дамп:
docker compose exec -T guac-db mysql \
-u root -p"СМЕНИТЕ_МЕНЯ_root" guacamole_db \
< /path/to/backup/db/guacamole_LATEST.sql
Если база создаётся с нуля (volume пустой), init-скрипт схемы (init/01-initdb.sql из установки) отработает автоматически при первом старте — восстановление дампа поверх пустой схемы в этом случае безопасно, дамп содержит все данные и структуру целиком.
4. Восстановите recordings, если нужны:
mkdir -p /opt/guacamole/recordings
restic -r /path/to/backup/restic-repo restore latest \
--target /opt/guacamole/recordings --tag guacamole-recordings
5. Поднимите остальной стек и проверьте:
docker compose up -d
docker compose logs -f guacamole
curl -I http://127.0.0.1:8080/guacamole/
Зайдите в веб-интерфейс под прежним администратором, проверьте, что видны все подключения и группы пользователей. Если фронтом стоит nginx с SSL — восстановите его конфиг и убедитесь, что DNS домена уже указывает на новый IP, иначе сертификат не перевыпустится автоматически. Базовая схема reverse proxy разобрана в статье про nginx как reverse proxy на VPS.
Проверка бэкапов и типичные ошибки
Дамп, который ни разу не разворачивали на чистом сервере, — это файл неизвестного качества. Раз в месяц-два поднимайте тестовый стек в изолированной сети и восстанавливайте туда последнюю копию — только так вы заранее узнаете, что дамп битый или пароль в конфиге устарел, а не в момент реального инцидента.
Частые ошибки на практике:
- Бэкапится только база, но не recordings — если аудит сессий важен для комплаенса, потеря архива видео при восстановлении может быть большей проблемой, чем потеря самого шлюза.
- Пароль root MySQL захардкожен в скрипте бэкапа в открытом виде, и сам скрипт лежит с правами 644 — доступ к нему фактически равен доступу ко всей базе Guacamole, включая пароли от RDP/VNC-хостов.
- Бэкап и рабочий сервер на одном диске — офсайт-копия обязательна, не опция: при потере VPS целиком локальный бэкап на том же диске не спасёт.
- Никто не проверяет, что cron вообще отработал — задача может молча перестать выполняться (кончилось место, изменился пароль), а обнаружится это только при попытке восстановиться. Добавьте проверку возраста последнего файла дампа в мониторинг или хотя бы алерт на ненулевой код выхода cron-задачи.
Если Guacamole уже работает нестабильно на текущем сервере — вопрос, скорее всего, не в бэкапах, а в ресурсах: guacd и Tomcat под нагрузкой десятков параллельных RDP-сессий с записью потребляют заметно больше CPU и диска, чем в простое.
Нужен сервер под эту задачу?
Разверните VPS MAATRIX за пару минут: NVMe, AMD EPYC, root-доступ, локации UK, США, Франция и РФ. Оплата картой РФ и по СБП.
Арендовать серверНужны сами нейросети для контента?
Генерируйте изображения, видео и озвучку нейросетями на falapi.io — десятки моделей в одном окне. Оплата картой РФ и по СБП.
Частые вопросы
Нужно ли бэкапить сам контейнер guacd?
Нет, он не хранит состояния и полностью восстанавливается пересозданием из образа.
Пароли к RDP/VNC-хостам в дампе базы читаются в открытом виде?
По умолчанию да, если не подключено расширение шифрования атрибутов подключений — обращайтесь с дампом как с секретом, шифруйте его при передаче за пределы сервера.
Как часто бэкапить базу и как часто — recordings?
Базу — не реже раза в сутки, это небольшой файл. Recordings можно синхронизировать реже (например, раз в несколько часов инкрементально через restic), если запись сессий идёт постоянно и объём растёт быстро.
Можно ли восстановить дамп MySQL на сервер с более новой версией образа guacamole?
Обычно да, схема БД стабильна между минорными версиями, но безопаснее восстанавливать на ту же мажорную версию, что стояла на момент бэкапа, а затем обновляться штатно через смену тега образа.
Что делать, если восстановили базу, а расширения (TOTP, LDAP) не подхватились?
Проверьте, что каталог extensions восстановлен рядом с docker-compose.yml и примонтирован в сервис guacamole — без jar-файлов расширения интерфейс просто не покажет соответствующие настройки, но данные в базе при этом не теряются.
Нужно ли останавливать Guacamole на время снятия дампа?
Нет, mysqldump --single-transaction снимает консистентный снапшот без блокировки записи, активные сессии пользователей не прерываются.
Обсудить статью, задать вопрос или начать новую тему
Есть вопрос по этой статье, идея для обсуждения или просто хотите поделиться опытом? Сообщество MAATRIX ждёт. Для общения, пожалуйста, зарегистрируйтесь в нашем личном кабинете.
Перейти в сообщество →