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

Бэкап и восстановление Standard Notes

MAATRIX

Standard Notes выбирают ради двух вещей: сквозного шифрования и обещания, что заметки не окажутся заперты в проприетарном формате. Это меняет саму логику бэкапа: сервер хранит только шифротекст, и если вы потеряете VPS без единой копии данных, расшифровывать там на самом деле будет нечего — весь смысл в том, чтобы копия существовала в двух независимых местах: у самого приложения и у вас на сервере. Разберём, что именно копировать в self-hosted стеке, как снять дамп PostgreSQL без остановки сервиса, куда девать вложения и как проверить, что восстановление реально работает, а не просто «наверное сработает».

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

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

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

Как устроено хранилище Standard Notes и что в нём критично

Self-hosted Standard Notes разворачивается из официального репозитория standardnotes/self-hosted через docker compose. В стеке — реверс-прокси Caddy с автоматическим TLS, PostgreSQL как основное хранилище и Redis для кеша, очередей и вебсокет-сессий, а поверх них набор Node.js-сервисов: API-шлюз, авторизация, синхронизация, ревизии, при необходимости — файловый сервер. Точный список контейнеров и их имена лучше свериться с docker-compose.yml конкретно вашей версии — набор сервисов между релизами менялся, и опираться на память здесь не стоит.

Важно понимать модель шифрования: содержимое заметки шифруется на устройстве клиента ключом, производным от вашего пароля, ещё до отправки на сервер. В базе PostgreSQL лежит только шифротекст плюс метаданные — UUID, тип элемента, время создания и изменения. Дамп БД без пароля от аккаунта бесполезен злоумышленнику для чтения заметок. Но это не повод обращаться с бэкапом небрежно: метаданные — тоже информация, а шифротекст при слабом пароле теоретически поддаётся offline-перебору, если утечёт.

Что реально критично для бэкапа:

КомпонентЧто содержитКритичность
PostgreSQL (volume db)зашифрованные заметки, теги, ревизии, аккаунтыобязательно
Файловый сервер (если включён)зашифрованные вложения — локальный диск или S3-совместимое хранилищеобязательно, если используете
.envсекреты сервера: JWT-ключи, пароли БД, SMTPобязательно
docker-compose.yml и оверрайдыконфигурация портов, ресурсов, доменовжелательно
Redisкеш, очереди задач, вебсокет-сессиине нужно — эфемерно
Volume с сертификатами CaddyTLS-сертификаты Let's Encryptопционально, ускоряет восстановление

Redis сознательно не в списке обязательного: это временное состояние, которое пересоберётся само при старте контейнеров, а сессии просто попросят пользователей перелогиниться.

Экспорт из приложения — ваш настоящий последний рубеж

Прежде чем говорить о бэкапе сервера, стоит закрыть более фундаментальный вопрос: что будет, если сервер потерян целиком, включая все резервные копии на нём же? Именно для этого случая у Standard Notes есть встроенный экспорт, и это не факультативная функция, а часть позиционирования продукта.

В настройках клиента — раздел Backups — есть два действия:

  • Export Backup — ручной экспорт всего аккаунта в архив. Можно выбрать «Encrypted» (полный слепок с сохранением всех типов элементов и метаданных, восстанавливается только через импорт в Standard Notes с вашим паролем) или «Decrypted, plain text» — архив, где каждая заметка лежит отдельным читаемым файлом. Именно второй вариант и есть та самая «долговечность формата»: такой архив можно открыть текстовым редактором и через десять лет, даже если сервиса Standard Notes вообще не станет.
  • Email Backups — периодическая (например, еженедельная) отправка зашифрованного бэкапа на почту, привязанную к аккаунту. Это работает независимо от вашего сервера и от того, включена ли у вас автоматизация бэкапов на VPS вообще — письмо просто улетает через SMTP, который вы настроили при разворачивании стека.

Практическая рекомендация: включите Email Backups и дополнительно раз в месяц-два делайте ручной decrypted-экспорт, складывая архив в отдельное хранилище — не на тот же сервер, где крутится сам Standard Notes. Плейнтекст-архив после экспорта — это уже расшифрованные данные, так что храните его сам зашифрованным (например, gpg -c backup.zip или сразу в зашифрованном разделе), а не просто закиньте как есть в облако.

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

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

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

Бэкап PostgreSQL — горячий дамп без остановки контейнера

Основной способ снять копию базы — pg_dump через docker compose exec, без остановки сервисов (общие приёмы работы с PostgreSQL на VPS пригодятся и здесь). Имя пользователя и базы берите из своего .env (обычно переменные вида POSTGRES_USER и POSTGRES_DB или DB_USER/DB_DATABASE — конкретные ключи зависят от версии self-hosted стека):

mkdir -p /opt/backups/standard-notes
cd /opt/standard-notes-self-hosted   # каталог с docker-compose.yml

docker compose exec -T db pg_dump -U standardnotes -d standardnotes \
  | gzip > /opt/backups/standard-notes/db_$(date +%F_%H%M).sql.gz

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

Ротация старых копий простым find:

find /opt/backups/standard-notes -name 'db_*.sql.gz' -mtime +14 -delete

Собрать это в systemd-таймер — надёжнее, чем cron, потому что видно статус выполнения через systemctl status:

# /etc/systemd/system/sn-backup.service
[Unit]
Description=Standard Notes DB backup

[Service]
Type=oneshot
WorkingDirectory=/opt/standard-notes-self-hosted
ExecStart=/opt/standard-notes-self-hosted/backup.sh
# /etc/systemd/system/sn-backup.timer
[Unit]
Description=Daily Standard Notes DB backup

[Timer]
OnCalendar=*-*-* 03:30:00
Persistent=true

[Install]
WantedBy=timers.target
systemctl daemon-reload
systemctl enable --now sn-backup.timer

Persistent=true довозит пропущенный запуск, если сервер был выключен в момент срабатывания.

Если база выросла настолько, что pg_dump заметно нагружает диск, рассмотрите pg_basebackup — но для типичной установки на несколько аккаунтов логического дампа хватает с запасом.

Что ещё нужно скопировать: .env, вложения, сертификаты

Дамп базы — это только заметки и метаданные. Без остального сервер после восстановления либо не поднимется, либо поднимется в нерабочем виде.

.env держите под рукой отдельно от каталога с остальными бэкапами и с правами chmod 600 — в нём пароли к БД, секреты подписи JWT-токенов сессий и данные SMTP. Полная потеря .env без копии не убьёт содержимое заметок (оно расшифровывается на клиенте вашим паролем аккаунта, а не серверными секретами), но означает пересоздание секретов и принудительный релогин всех устройств — та же логика, что и в бэкапе Vaultwarden, только без потери самого хранилища.

Файловый сервер (если вы включали его для зашифрованных вложений) хранит блобы либо на локальном диске в отдельном volume, либо в S3-совместимом хранилище вроде MinIO. Локальный volume копируйте tar-архивом наравне с базой:

docker run --rm \
  -v standard-notes-self-hosted_files-data:/data:ro \
  -v /opt/backups/standard-notes:/backup \
  alpine tar czf /backup/files_$(date +%F).tar.gz -C /data .

Если вложения лежат в S3-совместимом бакете — синхронизируйте его отдельно через rclone или restic с S3-бэкендом, дамп PostgreSQL к содержимому бакета отношения не имеет.

Сертификаты Caddy (volume caddy_data) бэкапить не обязательно — Let's Encrypt перевыпустит их за секунды при следующем старте. Но если у вас низкий rate limit по домену или используется DNS-01 с ручными шагами, копия сэкономит время при аварийном восстановлении.

Автоматизация и шифрование через restic

Собрать дамп, .env и вложения в один зашифрованный офсайт-бэкап удобнее всего через restic — он умеет шифрование «из коробки» и инкрементальные снапшоты, поэтому повторные запуски не гоняют мегабайты заново. Подробный разбор самого restic и альтернативы ему — в статье про шифрование бэкапов на сервере, здесь — минимальный рабочий скрипт под Standard Notes.

Репозиторий restic удобно держать на втором сервере (правило «бэкап отдельно от продакшена» соблюдается буквально), доступ — по SFTP:

export RESTIC_REPOSITORY="sftp:backup-user@backup-host:/srv/restic/standard-notes"
export RESTIC_PASSWORD="сложная-парольная-фраза-для-репозитория"

restic init   # один раз, при первом запуске

Скрипт бэкапа:

#!/usr/bin/env bash
set -euo pipefail
cd /opt/standard-notes-self-hosted

TMP=$(mktemp -d)
docker compose exec -T db pg_dump -U standardnotes -d standardnotes | gzip > "$TMP/db.sql.gz"
cp .env "$TMP/env.backup"

export RESTIC_REPOSITORY="sftp:backup-user@backup-host:/srv/restic/standard-notes"
export RESTIC_PASSWORD_FILE="/root/.restic-sn-pass"

restic backup "$TMP" /var/lib/docker/volumes/standard-notes-self-hosted_files-data \
  --tag standard-notes

restic forget --keep-daily 14 --keep-weekly 8 --keep-monthly 6 --prune

rm -rf "$TMP"

Пароль репозитория держите в /root/.restic-sn-pass с правами 600, а не в переменной окружения внутри скрипта — так он не всплывёт в ps aux. Политика хранения --keep-daily 14 --keep-weekly 8 --keep-monthly 6 — разумная отправная точка для личного или командного инстанса.

Восстановление на новом сервере — пошагово

Проверка бэкапа без реального восстановления — это не проверка. Разворачивайте на чистом VPS хотя бы раз после настройки автоматизации, чтобы не узнавать о проблеме в момент, когда сервер уже упал.

  1. Поднимите новый сервер и клонируйте self-hosted стек той же (или совместимой) версии, что использовалась изначально:
   git clone https://github.com/standardnotes/self-hosted.git /opt/standard-notes-self-hosted
   cd /opt/standard-notes-self-hosted
  1. Восстановите .env из бэкапа — на его место, с правами 600.
  2. Поднимите только базу и Redis, не трогая остальные сервисы:
   docker compose up -d db cache
  1. Восстановите дамп в чистую базу:
   gunzip -c /opt/backups/standard-notes/db_2026-08-30_0330.sql.gz \
     | docker compose exec -T db psql -U standardnotes -d standardnotes
  1. Восстановите вложения, если использовался файловый сервер:
   docker run --rm \
     -v standard-notes-self-hosted_files-data:/data \
     -v /opt/backups/standard-notes:/backup \
     alpine tar xzf /backup/files_2026-08-30.tar.gz -C /data
  1. Поднимите весь стек и проверьте статус контейнеров:
   docker compose up -d
   docker compose ps
   docker compose logs -f api-gateway
  1. Проверьте вход с клиента (веб, десктоп или мобильное приложение), указав адрес нового сервера, и убедитесь, что заметки открываются и расшифровываются вашим обычным паролем. Это единственный надёжный признак, что восстановление прошло целиком, а не только на уровне «контейнеры запустились».

Если восстановленный .env не совпадает с исходным (например, вы намеренно сгенерировали новые секреты), это не помешает расшифровать содержимое заметок — оно завязано на пароль аккаунта, а не на серверные ключи. Но все активные сессии и токены синхронизации станут недействительны, и каждому клиенту придётся войти заново.

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

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

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

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

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

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

Нужно ли шифровать бэкап PostgreSQL, если содержимое заметок и так зашифровано клиентом?

Да. В базе, помимо шифротекста, есть метаданные — типы записей, метки времени, e-mail аккаунтов. Держите бэкап в зашифрованном репозитории (restic, borg) и ограничивайте доступ так же строго, как к продакшен-серверу.

Что случится с заметками, если потерян .env, но дамп базы есть?

Содержимое останется расшифровываемым — оно зависит только от пароля аккаунта. Пересоздайте секреты сервера, восстановите дамп — клиенты попросят повторный вход, но данные не потеряются.

Как часто делать бэкап сервера?

Для активно используемого инстанса — ежедневный дамп БД с хранением 2–4 недель плюс еженедельные и месячные снапшоты через restic. И не отключайте встроенный Email Backups в приложении — это независимый канал на случай полной потери сервера вместе со всеми его бэкапами.

Можно ли восстановить заметки только из экспорта приложения, вообще без сервера?

Да. Зашифрованный экспортный архив импортируется в любой чистый инстанс Standard Notes через тот же пароль аккаунта. Плейнтекст-экспорт читается напрямую текстовым редактором — это и есть заявленная долговечность формата.

Нужно ли бэкапить Redis?

Нет. Это кеш, очередь задач и вебсокет-сессии — всё эфемерное, пересоздаётся при старте контейнеров, а сессии клиентов просто попросят перелогин.

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

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

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