MAATRIX / Блог / Бэкап и восстановление Joplin Server

Бэкап и восстановление Joplin Server

MAATRIX

Если вы подняли Joplin Server как замену Dropbox или Google Keep для синхронизации заметок, рано или поздно встанет вопрос: а что будет, если сервер умрёт? Заметки — это не файлы, которые можно скачать заново, это годы записей, и без бэкапа их вернуть неоткуда. Ниже — рабочая схема бэкапа и восстановления Joplin Server на своём VPS: что именно копировать, как автоматизировать и как разворачиваться заново, если сервер пропал совсем.

Обсудить статью, задать вопрос или начать новую тему

Есть вопрос по этой статье, идея для обсуждения или просто хотите поделиться опытом? Сообщество MAATRIX ждёт. Для общения, пожалуйста, зарегистрируйтесь в нашем личном кабинете.

Перейти в сообщество →

Что на самом деле нужно бэкапить в Joplin Server

Joplin Server — это не файловое хранилище в привычном смысле. Клиенты Joplin синхронизируются с сервером по собственному протоколу, а сам сервер хранит все данные — заметки, блокноты, теги, вложения — в реляционной базе данных. Стандартная поставка joplin/server работает с PostgreSQL (SQLite тоже поддерживается, но для продакшена и многопользовательской синхронизации разработчики прямо рекомендуют Postgres).

Из этого следует простой вывод: 95% ценности лежит в базе данных, а не в файловой системе контейнера. Структура типового развёртывания:

/opt/joplin/
├── docker-compose.yml
├── .env
└── data/
    └── postgres/        # volume с данными PostgreSQL

Что нужно бэкапить:

  • Дамп PostgreSQL — таблицы с заметками, ресурсами (вложениями, они тоже лежат в БД как blob'ы), пользователями и правами доступа.
  • .env и docker-compose.yml — без них восстановленный сервер не поднимется с теми же портами, доменом и учётными данными БД.
  • Сертификаты reverse-proxy (если Let's Encrypt настроен через отдельный контейнер, а не через внешний Traefik/Nginx Proxy Manager с собственным бэкапом).

Файлового volume с вложениями отдельно бэкапить не нужно — если вы не переключали Joplin Server на S3-хранилище через переменную STORAGE_DRIVER. Если переключали — добавьте синхронизацию S3-бакета в схему ниже.

Бэкап базы данных PostgreSQL

Дамп базы делается штатной утилитой pg_dump изнутри контейнера. Предположим, контейнер БД называется joplin-db, а сама база — joplin:

docker exec -t joplin-db pg_dump -U joplin -d joplin -F c -f /tmp/joplin.dump
docker cp joplin-db:/tmp/joplin.dump /opt/joplin/backups/joplin_$(date +%Y%m%d_%H%M).dump
docker exec joplin-db rm /tmp/joplin.dump

Флаг -F c — формат custom, он сжат по умолчанию и восстанавливается через pg_restore, что даёт больше гибкости, чем плоский SQL-дамп (можно восстановить отдельные таблицы, распараллелить pg_restore -j).

Если база уже разрослась (у активных пользователей с историей версий заметок за годы дамп может достигать нескольких гигабайт), добавьте сжатие и вынесите промежуточный файл сразу за пределы контейнера через пайп, не создавая временный файл внутри:

docker exec -t joplin-db pg_dump -U joplin -d joplin -F c \
  | gzip > /opt/joplin/backups/joplin_$(date +%Y%m%d_%H%M).dump.gz

Проверяйте код возврата — молчаливо оборвавшийся pg_dump из-за нехватки места на диске контейнера превратит бэкап в бесполезный обрубленный файл:

if [ ${PIPESTATUS[0]} -ne 0 ]; then
  echo "pg_dump failed" | mail -s "Joplin backup FAILED" you@example.com
  exit 1
fi

Нужен сервер под эту задачу?

Разверните VPS MAATRIX за пару минут: NVMe, AMD EPYC, root-доступ, локации UK, США, Франция и РФ. Оплата картой РФ и по СБП.

Арендовать сервер

Бэкап конфигурации: .env, compose-файл, volume-мета

Дамп базы бесполезен без контекста, в котором сервер был развёрнут. Сохраняйте вместе с дампом:

tar czf /opt/joplin/backups/config_$(date +%Y%m%d).tar.gz \
  /opt/joplin/docker-compose.yml \
  /opt/joplin/.env

В .env для Joplin Server обычно лежат критичные для восстановления параметры:

APP_PORT=22300
APP_BASE_URL=https://notes.example.com
DB_CLIENT=pg
POSTGRES_DATABASE=joplin
POSTGRES_USER=joplin
POSTGRES_PASSWORD=<пароль>
POSTGRES_HOST=joplin-db
POSTGRES_PORT=5432
MAILER_ENABLED=0

Если POSTGRES_PASSWORD при восстановлении не совпадёт с паролем, зашитым в дамп базы (роль и права создаются вместе с дампом при pg_restore --create или должны существовать заранее), сервер не подключится к БД — это самая частая причина «бэкап есть, а поднять не могу» у тех, кто хранил только сам дамп.

Секреты в .env — это чувствительные данные. Если бэкапы уходят во внешнее хранилище, шифруйте архив с конфигом отдельно от дампа базы (или используйте restic/borg с шифрованием «из коробки», см. ниже).

Автоматизация: cron-скрипт с ротацией и выгрузкой наружу

Локальные бэкапы на том же диске, что и сам сервер, не защищают от отказа диска или сноса VPS целиком. Полная схема — локальный дамп → ротация → синхронизация во внешнее хранилище.

Скрипт /opt/joplin/backup.sh:

#!/bin/bash
set -euo pipefail

BACKUP_DIR=/opt/joplin/backups
DATE=$(date +%Y%m%d_%H%M)
KEEP_DAYS=14

mkdir -p "$BACKUP_DIR"

docker exec -t joplin-db pg_dump -U joplin -d joplin -F c \
  | gzip > "$BACKUP_DIR/joplin_$DATE.dump.gz"

tar czf "$BACKUP_DIR/config_$DATE.tar.gz" \
  /opt/joplin/docker-compose.yml /opt/joplin/.env

# ротация: удаляем локальные бэкапы старше KEEP_DAYS
find "$BACKUP_DIR" -type f -mtime +"$KEEP_DAYS" -delete

# выгрузка во внешнее хранилище (пример с rclone на S3-совместимый бакет)
rclone copy "$BACKUP_DIR" remote:joplin-backups --min-age 5m

Права на выполнение и задача в cron:

chmod +x /opt/joplin/backup.sh
crontab -e
0 3 * * * /opt/joplin/backup.sh >> /var/log/joplin-backup.log 2>&1

Ежедневного бэкапа в 3 ночи достаточно для большинства персональных и небольших командных инсталляций — Joplin синхронизирует изменения инкрементально, и потеря максимум суток правок при полном отказе сервера — приемлемый риск для заметок (не для банковской транзакции). Если для вас это критично, дробите интервал до нескольких раз в день — pg_dump с базой в несколько сотен мегабайт выполняется секунды, нагрузка на сервер незаметна.

Про настройку самого rclone и альтернативы вроде restic с шифрованием и дедупликацией — в отдельном разборе: как установить и настроить Restic на VPS и сравнение Restic или BorgBackup — что выгоднее.

Восстановление Joplin Server из бэкапа

Сценарий: старый сервер недоступен, разворачиваем Joplin Server заново на чистом VPS.

1. Поднимите PostgreSQL и создайте пустую базу с теми же учётными данными, что были в .env бэкапа:

docker compose up -d joplin-db
sleep 5
docker exec -it joplin-db psql -U postgres -c \
  "CREATE USER joplin WITH PASSWORD '<тот_же_пароль>';"
docker exec -it joplin-db psql -U postgres -c \
  "CREATE DATABASE joplin OWNER joplin;"

2. Распакуйте и восстановите дамп:

gunzip -c joplin_20260828_0300.dump.gz > joplin.dump
docker cp joplin.dump joplin-db:/tmp/joplin.dump
docker exec -it joplin-db pg_restore -U joplin -d joplin --clean --if-exists /tmp/joplin.dump

Флаг --clean --if-exists пересоздаёт объекты в базе перед восстановлением — полезно, если в пустой базе уже что-то успело создаться при первом запуске Joplin Server (он сам накатывает миграции при старте).

3. Разверните конфиг и запустите Joplin Server:

tar xzf config_20260828.tar.gz -C /opt/joplin/
cd /opt/joplin
docker compose up -d
docker compose logs -f joplin-server

В логах должно появиться сообщение о применении миграций и старте на APP_PORT. Если APP_BASE_URL в новом .env изменился (переехали на другой домен) — обновите его до запуска, иначе клиенты Joplin будут получать ссылки вложений на старый адрес.

4. Проверьте синхронизацию с одного клиента, прежде чем переключать остальные устройства — откройте настольный или мобильный Joplin, укажите новый адрес сервера в настройках синхронизации и убедитесь, что блокноты и заметки подтянулись целиком, включая вложения (картинки в заметках должны открываться, а не показывать битую иконку).

Если вы переносите Joplin Server не после сбоя, а планово — например, на более производительный тариф — тот же порядок действий работает и как процедура миграции. Общий подход к переезду без потери данных описан в статье перенос сайта на новый VPS без простоя — принципы там применимы к любому сервису на Docker, не только к сайтам.

Проверка бэкапов и план на случай отказа сервера

Бэкап, который ни разу не восстанавливали, — это гипотеза, а не бэкап. Раз в один-два месяца проверяйте восстановление на отдельном тестовом VPS или локально в Docker:

docker compose -f docker-compose.test.yml up -d joplin-db-test
gunzip -c последний_дамп.dump.gz | docker exec -i joplin-db-test pg_restore -U joplin -d joplin --clean --if-exists

Если восстановление прошло без ошибок и данные читаемы — бэкап рабочий. Если нет — лучше узнать об этом сейчас, а не в момент реального отказа.

Что стоит держать под рукой на случай полного отказа сервера:

ЧтоГде хранитьЗачем
Последние N дампов БДВнешний S3/бакет через rclone или resticОсновной источник восстановления
.env и docker-compose.ymlТам же + отдельно в менеджере паролей (пароли БД)Без них не поднять сервер с теми же данными
Список версий: joplin/server image tag, версия PostgresКомментарий в docker-compose.ymlСовместимость дампа с версией схемы БД
Домен и DNS-записьРегистратор / зона DNSКлиенты обращаются по домену, не по IP

Отдельно продумайте, где физически будет жить новый сервер, если старый выйдет из строя не по вашей вине (падение хостинга, недоступность дата-центра). Держите заранее выбранный запасной регион под рукой — сравнение вариантов есть в статье лучший VPS для бэкапов.

Нужен сервер под эту задачу?

Разверните VPS MAATRIX за пару минут: NVMe, AMD EPYC, root-доступ, локации UK, США, Франция и РФ. Оплата картой РФ и по СБП.

Арендовать сервер

Нужны сами нейросети для контента?

Генерируйте изображения, видео и озвучку нейросетями на falapi.io — десятки моделей в одном окне. Оплата картой РФ и по СБП.

Частые вопросы

Достаточно ли бэкапить только volume с данными PostgreSQL, не делая pg_dump?

Технически можно копировать директорию /var/lib/postgresql/data при остановленном контейнере (холодный бэкап), но это неудобно — требует останова сервиса на время копирования и переносимо только между идентичными версиями Postgres. pg_dump в формате custom работает «на горячую», без простоя, и переживает обновление версии СУБД.

Что будет с вложениями (картинками, PDF) в заметках после восстановления?

Они хранятся как blob'ы в той же таблице ресурсов PostgreSQL, поэтому восстанавливаются вместе с дампом автоматически — отдельно копировать файлы не нужно, если вы не настраивали внешнее S3-хранилище через STORAGE_DRIVER=Storage.S3.

Как часто на самом деле нужен бэкап для персонального использования?

Раз в сутки — разумный баланс для одного-двух пользователей. Если Joplin Server используется командой с активной ежедневной работой над общими блокнотами, имеет смысл сократить интервал до нескольких часов или включить непрерывный WAL-архив PostgreSQL для восстановления на конкретный момент времени.

Нужно ли отдельно бэкапить пользователей и их пароли?

Нет, таблицы users и хэши паролей входят в общий дамп базы наравне с заметками — восстанавливая базу, вы восстанавливаете и учётные записи со всеми правами доступа к блокнотам.

Что делать, если версия joplin/server в новом окружении новее, чем была на старом сервере?

Восстановите дамп, затем запустите новый контейнер — Joplin Server сам применит недостающие миграции схемы при старте. Резкий скачок через много мажорных версий сразу лучше не делать: обновляйтесь поэтапно, сверяясь с changelog проекта.

Обсудить статью, задать вопрос или начать новую тему

Есть вопрос по этой статье, идея для обсуждения или просто хотите поделиться опытом? Сообщество MAATRIX ждёт. Для общения, пожалуйста, зарегистрируйтесь в нашем личном кабинете.

Перейти в сообщество →