MAATRIX / Блог / Standard Notes в Docker Compose: готовый файл

Standard Notes в Docker Compose: готовый файл

MAATRIX

Если вы храните заметки в облачном сервисе, вы доверяете чужому серверу не только текст, но и метаданные — когда писали, как часто открывали, с какого IP. Standard Notes решает это шифрованием на клиенте: сервер видит только зашифрованный блоб, ключ не покидает ваше устройство. Но чтобы получить полный контроль, сервер должен быть тоже вашим. Ниже — рабочий docker-compose.yml для self-hosted Standard Notes Server, с пояснением каждого блока и типичными граблями.

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

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

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

Почему self-hosted, а не облако Standard Notes

Официальный Standard Notes уже шифрует данные end-to-end — это не маркетинг, а архитектура: приложение шифрует заметку локально алгоритмом XChaCha20-Poly1305 (в актуальных версиях протокола 004), и на сервер уходит уже нечитаемый контейнер. Даже если облако Standard Notes скомпрометируют, содержимое заметок не достать без вашего пароля.

Тогда зачем свой сервер? Три причины, с которыми реально сталкиваются:

  • Юрисдикция и метаданные. Сервер видит IP, время синхронизаций, размер зашифрованных блобов и структуру тегов. Для дневника это может быть неважно, для рабочих заметок с NDA — уже вопрос.
  • Лимиты бесплатного тарифа. Бесплатный аккаунт Standard Notes ограничивает историю версий и часть функций расширений — при самостоятельном хостинге таких ограничений на сервере нет (клиентские фичи, зависящие от подписки, всё равно определяются самим приложением, это стоит проверить отдельно под вашу версию).
  • Долговечность формата. Standard Notes годами держит принцип "открытый формат экспорта, который переживёт сам сервис". Свой сервер логично продолжает эту идею — вы не зависите от того, что будет с компанией через 5 лет.

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

Что входит в стек

Standard Notes Server — это не один контейнер, а набор сервисов, разговаривающих друг с другом. В официальном self-hosted репозитории (standardnotes/server) используется такая схема:

СервисРоль
syncing-server-jsосновной API синхронизации заметок
authрегистрация, логин, сессии, ключи шифрования
api-gatewayединая точка входа, маршрутизация к сервисам
db (MySQL)хранение зашифрованных данных пользователей
cache (Redis)очереди и кеш сессий
files (опционально)серверная часть для вложений через расширение Filesafe

Разворачивать всё вручную по одному контейнеру — плохая идея: сервисы жёстко завязаны на общие переменные окружения и сеть. Разработчики поддерживают готовый docker-compose.yml в репозитории проекта — берите оттуда актуальную версию, а дальше настраивайте под себя. Ниже — рабочий каркас, который стоит сверить со свежим upstream-файлом перед деплоем (структура сервисов Standard Notes меняется реже, чем у большинства self-hosted проектов, но переменные окружения — стоит перепроверять).

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

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

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

Готовый docker-compose.yml

Создайте директорию и файл окружения:

mkdir -p /opt/standardnotes && cd /opt/standardnotes

.env:

# Генерируйте случайные значения, не оставляйте примеры
DB_HOST=db
DB_PORT=3306
DB_DATABASE=standardnotes
DB_USERNAME=standardnotes
DB_PASSWORD=CHANGE_ME_STRONG_PASSWORD
REDIS_URL=redis://cache:6379

# Секреты сессий и шифрования JWT — по 32+ случайных символа каждый
JWT_SECRET=CHANGE_ME_RANDOM_32_CHARS
AUTH_JWT_SECRET=CHANGE_ME_RANDOM_32_CHARS
ENCRYPTION_SERVER_KEY=CHANGE_ME_RANDOM_32_CHARS
PSEUDO_KEY_PARAMS_KEY=CHANGE_ME_RANDOM_32_CHARS

# Публичный адрес, по которому клиенты будут стучаться к API
AUTH_JWT_TTL=60
PUBLIC_HOST=https://notes.example.com

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

openssl rand -hex 24

docker-compose.yml:

version: "3.8"

services:
  db:
    image: mysql:8.0
    restart: unless-stopped
    environment:
      MYSQL_DATABASE: ${DB_DATABASE}
      MYSQL_USER: ${DB_USERNAME}
      MYSQL_PASSWORD: ${DB_PASSWORD}
      MYSQL_ROOT_PASSWORD: ${DB_PASSWORD}
    volumes:
      - db-data:/var/lib/mysql
    networks:
      - sn-net

  cache:
    image: redis:7-alpine
    restart: unless-stopped
    volumes:
      - cache-data:/data
    networks:
      - sn-net

  auth:
    image: standardnotes/auth:latest
    restart: unless-stopped
    env_file: .env
    depends_on:
      - db
      - cache
    networks:
      - sn-net

  syncing-server-js:
    image: standardnotes/syncing-server-js:latest
    restart: unless-stopped
    env_file: .env
    depends_on:
      - db
      - cache
      - auth
    networks:
      - sn-net

  api-gateway:
    image: standardnotes/api-gateway:latest
    restart: unless-stopped
    env_file: .env
    ports:
      - "3000:3000"
    depends_on:
      - auth
      - syncing-server-js
    networks:
      - sn-net

networks:
  sn-net:
    driver: bridge

volumes:
  db-data:
  cache-data:

Запуск:

docker compose up -d
docker compose logs -f api-gateway

Если всё поднялось, api-gateway должен слушать на 3000-м порту и отвечать на health-check без ошибок подключения к MySQL и Redis.

Публикация через reverse proxy с SSL

Отдавать API напрямую по 3000-му порту без TLS нельзя — Standard Notes-клиенты требуют HTTPS для сервера синхронизации, да и открытый порт без шифрования транспорта сводит на нет весь смысл затеи с приватностью. Поставьте перед стеком reverse proxy — Caddy проще всего заводит автоматический SSL:

notes.example.com {
    reverse_proxy localhost:3000
}

Один блок конфига, и Caddy сам получит сертификат Let's Encrypt и продлит его. Если вы уже используете nginx на сервере под другие сайты, добавьте отдельный server-блок с proxy_pass http://127.0.0.1:3000; и получите сертификат через certbot. Разница подходов и когда что выбирать разобрана в статье Caddy или nginx — что выбрать для сервера.

Не забудьте прокинуть домен в DNS на IP сервера заранее — без A-записи ни Caddy, ни certbot сертификат не выпустят.

Подключение клиентов

После того как https://notes.example.com отдаёт корректный SSL, в приложении Standard Notes (веб, десктоп, мобильное) на экране входа выберите "Advanced options" → "Custom sync server" и укажите ваш адрес. Дальше — обычная регистрация: приложение сгенерирует ключи шифрования локально, на сервер уйдёт только зашифрованный контейнер данных.

Важный нюанс: если вы позже смените адрес сервера или потеряете пароль восстановления, расшифровать старые заметки без ключа не сможет никто — ни вы, ни разработчики Standard Notes, ни мы. Это плата за настоящее сквозное шифрование, а не недоработка. Сохраните пароль восстановления (recovery codes) в отдельном защищённом месте отдельно от самого сервера.

Бэкапы и обновления

Зашифрованные данные лежат в MySQL-томе db-data. Бэкапить нужно именно его — дамп базы уже содержит зашифрованный контент, расшифровать который без клиентских ключей всё равно нельзя, так что можно не переживать за хранение дампа на третьем сервере:

docker compose exec db mysqldump -u root -p${DB_PASSWORD} ${DB_DATABASE} > backup-$(date +%F).sql

Заведите это в cron и складывайте архивы за пределами сервера — на объектное хранилище или второй VPS. Если нужен инструмент посерьёзнее ежедневного dump'а, посмотрите на BorgBackup в Docker Compose — дедупликация и шифрование бэкапа "на лету" пригодятся, даже если основные данные уже зашифрованы на уровне приложения.

Обновление стека — обычная процедура для Compose-проектов:

docker compose pull
docker compose up -d

Перед обновлением на проде стоит сначала прогнать его на тестовом сервере с копией базы — у Standard Notes Server бывают миграции схемы между релизами, и откатить их назад сложнее, чем накатить вперёд.

Альтернативы, если Standard Notes не подошёл

Прежде чем разворачивать сервер, стоит понимать, чем Standard Notes отличается от соседей по нише self-hosted заметок:

  • Trilium Notes — куда богаче по структуре: иерархия заметок, связи между ними, скрипты. Шифрование там опциональное и по отдельным заметкам, а не сквозное по умолчанию. Смотрите Trilium в Docker Compose, если важнее гибкость структуры, чем приватность "из коробки".
  • CryptPad — тоже шифрование на клиенте, но заточен под совместные документы и таблицы, а не под личный архив заметок. Разворачивается через CryptPad в Docker Compose.
  • Joplin Server — синхронизация заметок с опциональным E2E-шифрованием (нужно включить отдельно, по умолчанию выключено), богатая экосистема плагинов.

Если приоритет — именно шифрование по умолчанию без возможности случайно его отключить, Standard Notes остаётся самым прямолинейным выбором среди self-hosted заметочников.

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

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

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

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

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

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

Нужен ли отдельный сервер только под Standard Notes, или можно на общем VPS?

Можно на общем — стек лёгкий (MySQL + Redis + три Node-сервиса), 1-2 GB RAM достаточно для личного и небольшого командного использования. На VPS с другими сервисами просто убедитесь, что порт 3000 не конфликтует и proxy настроен на отдельный домен.

Что будет, если я потеряю пароль от аккаунта?

Без пароля или сохранённых recovery codes расшифровать заметки невозможно в принципе — это и есть сквозное шифрование. Сервер не хранит ключ, и обойти это административно нельзя. Сохраняйте recovery codes сразу при регистрации.

Можно ли перенести заметки с облачного Standard Notes на свой сервер?

Да — в приложении есть экспорт всех заметок в незашифрованный или зашифрованный JSON-файл (Settings → Data → Export), а на новом сервере после регистрации — импорт того же файла. Это тот самый принцип "открытый формат, который переживёт сервис".

Чем self-hosted версия отличается по функциональности от облачной?

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

Стоит ли использовать сквозное шифрование, если сервер и так мой?

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

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

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

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