MAATRIX / Блог / CryptPad на сервере: частые ошибки и решения

CryptPad на сервере: частые ошибки и решения

MAATRIX

CryptPad — редкий случай, когда «облачный офис» реально не видит содержимое ваших документов: шифрование происходит в браузере, сервер хранит только зашифрованные блобы. Расплата за это — специфичный стек (Node.js-процесс + WebSocket-соединения + собственная файловая база вместо привычной SQL), который ломается не так, как обычный PHP-сайт. Если у вас страница CryptPad крутит спиннер вечно, документы не сохраняются или админка ругается на неверный ключ — ниже разобраны конкретные причины и что с ними делать.

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

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

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

Спиннер загрузки крутится бесконечно, редактор не открывается

Это самая частая жалоба, и в 90% случаев дело не в самом CryptPad, а в прокси перед ним. CryptPad — это не классическое HTTP-приложение, а связка из основного HTTP-сервера (по умолчанию порт 3000) и отдельного WebSocket/API-сокета (порт 3003 в конфигурации по умолчанию). Если reverse-proxy настроен только на проксирование HTTP-запросов, а апгрейд соединения до WebSocket не пробрасывается — интерфейс загрузится, но не сможет установить realtime-канал, и редактор документа так и останется на заставке.

Проверьте в браузере консоль разработчика (F12 → Network → фильтр WS): если сокет висит в состоянии pending или сразу закрывается с кодом 1006 — проблема именно в проксировании апгрейда соединения.

Для nginx нужен полный набор заголовков апгрейда, а не только proxy_pass:

location / {
    proxy_pass http://127.0.0.1:3000;
    proxy_http_version 1.1;
    proxy_set_header Upgrade $http_upgrade;
    proxy_set_header Connection "upgrade";
    proxy_set_header Host $host;
    proxy_set_header X-Real-IP $remote_addr;
    proxy_set_header X-Forwarded-For $proxy_add_x_forwarded_for;
    proxy_set_header X-Forwarded-Proto $scheme;
    proxy_read_timeout 3600s;
}

proxy_read_timeout увеличен намеренно: WebSocket-соединение живёт часами, и дефолтные 60 секунд nginx его периодически рвёт, из-за чего совместное редактирование «зависает» посреди работы. Если вы используете Traefik, апгрейд WebSocket он поддерживает из коробки через обычный PathPrefix-роутер, но убедитесь, что таймаут idle-соединений в traefik.yml тоже поднят (respondingTimeouts.idleTimeout), иначе будет та же картина с обрывами.

Ошибка «Insufficient storage» или документ не сохраняется

CryptPad хранит данные не в базе данных, а в файловой системе — каталог datastore/ (блобы документов, зашифрованные) и blob/ (вложения, файлы). У этой схемы есть неприятное следствие: сервер сам следит за квотами по конфигу, и если в config/config.js задан лимит defaultStorageLimit, а свободного места на диске меньше, чем нужно для операции записи — CryptPad может выдать ошибку сохранения, даже если формально диск ещё не полон.

Первым делом проверьте реальное место на диске:

df -h /path/to/cryptpad
du -sh /path/to/cryptpad/datastore /path/to/cryptpad/blob

Если раздел с CryptPad физически заполняется — это уже вопрос ресурсов сервера, а не конфигурации. На небольшом VPS с 20-25 ГБ диска CryptPad с активной командой (десяток пользователей, регулярные вложения) забивает диск быстрее, чем кажется — особенно если не настроена периодическая очистка неиспользуемых блобов через встроенный decree-скрипт архивации.

Второй частый источник — не хватает inode или прав на запись после переноса/восстановления из бэкапа:

ls -la /path/to/cryptpad/datastore
sudo chown -R cryptpad:cryptpad /path/to/cryptpad/datastore /path/to/cryptpad/blob

CryptPad обычно запускается от отдельного системного пользователя (не root — и это правильно), и после rsync или восстановления бэкапа владелец файлов часто «слетает» на root, из-за чего процесс не может писать в собственную папку данных.

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

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

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

Realtime-редактирование рассинхронизируется между участниками

Если два человека правят документ одновременно и видят разные версии текста, а не единый поток изменений — почти всегда причина в нескольких экземплярах Node.js-процесса CryptPad за одним доменом без общего состояния. CryptPad не проектировался как stateless-сервис за балансировщиком с несколькими репликами: WebSocket-канал и очередь операций (CRDT-подобный netflux-протокол) живут в памяти одного процесса.

Если вы запускали несколько инстансов CryptPad в Docker Compose с replicas: 2 или разносили нагрузку на два контейнера за одним nginx upstream «для отказоустойчивости» — уберите репликацию. Правильная схема — один процесс CryptPad плюс горячий бэкап данных, а не горизонтальное масштабирование одного и того же realtime-состояния:

services:
  cryptpad:
    image: cryptpad/cryptpad:5.x
    restart: unless-stopped
    deploy:
      replicas: 1   # намеренно, не 2 и не 3
    volumes:
      - ./cryptpad-data:/cryptpad/datastore
      - ./cryptpad-blob:/cryptpad/blob
      - ./cryptpad-config:/cryptpad/config

Если нагрузка реально большая (сотни одновременных редакторов), CryptPad поддерживает разделение sandbox-домена, но это архитектурное решение, а не быстрый фикс — для команды до 30-50 человек одного процесса на VPS с 2-4 vCPU обычно достаточно с запасом.

Sandbox iframe заблокирован, файлы не отображаются или не открываются

CryptPad использует второй домен (sandbox-домен) для iframe, в котором рендерится непосредственно содержимое документов — это часть модели безопасности: основной домен не может напрямую читать содержимое зашифрованных данных из iframe. Если в config.js не задан отдельный sandboxDomain, либо задан, но DNS для него не настроен, браузер либо блокирует iframe политикой Same-Origin, либо CryptPad сам откатывается на менее безопасный режим с предупреждением в консоли.

// config/config.js
httpUnsafeOrigin: 'https://pad.example.com',
httpSafeOrigin: 'https://pad-sandbox.example.com',

Оба домена должны указывать на один и тот же сервер (можно даже на один и тот же порт nginx), но обязаны быть разными доменными именами или хотя бы разными сабдоменами — не путём в рамках одного домена. И на sandbox-домен тоже нужен валидный SSL-сертификат: смешанный контент (HTTPS-страница, пытающаяся загрузить HTTP-iframe) браузер заблокирует молча, без внятной ошибки на экране. Для выпуска сертификатов на оба домена сразу удобно оформить SAN-сертификат через certbot с флагом -d, повторённым для каждого домена, — если сомневаетесь между certbot и acme.sh, вот сравнение: certbot или acme.sh — что выбрать для сервера.

Ошибка при входе администратора или невозможно попасть в admin-панель

CryptPad не хранит пароль администратора в базе — доступ к панели /admin/ привязывается к публичному ключу конкретного зарегистрированного аккаунта, который прописывается в конфиге вручную:

// config/config.js
adminKeys: [
    "[cryptpad-user1@pad.example.com/YOUR-PUBLIC-SIGNING-KEY]",
],

Строку с ключом нужно скопировать из настроек аккаунта в самом CryptPad (Settings → раздел с публичным ключом), а не придумывать вручную — это криптографический идентификатор, а не логин. Частая ошибка — вписать email вместо ключа или скопировать ключ с лишним пробелом на конце строки: конфиг подхватится без ошибок запуска, но проверка доступа в админку молча не пройдёт. После правки конфига процесс нужно перезапустить полностью, горячая перезагрузка конфига не поддерживается:

docker compose restart cryptpad
# или для systemd-варианта
sudo systemctl restart cryptpad

Высокое потребление памяти и падения процесса под нагрузкой

Node.js-процесс CryptPad держит активные документы и метаданные в памяти, и на серверах с 1-2 ГБ RAM при нескольких одновременно открытых больших таблицах или документах процесс может упираться в лимит памяти и падать с OOM. Это не утечка, а особенность архитектуры realtime-редактора: чем больше активных сессий и чем крупнее документы, тем больше нужно оперативной памяти.

Что реально помогает:

  • Не экономить на RAM — для стабильной работы команды в 10-15 человек комфортно чувствует себя сервер от 4 ГБ, для 30+ активных пользователей — от 8 ГБ.
  • Настроить своп как страховку от жёсткого OOM-килла, а не как основной ресурс (подробно про настройку свопа — в статье про swap и производительность на Ubuntu/Debian).
  • Ограничить размер загружаемых файлов через config.js (maxUploadSize), если сервис используется в основном для текстовых документов, а не как файлохранилище.
  • Если CryptPad запущен в Docker — задать mem_limit в compose-файле, чтобы контейнер падал предсказуемо и перезапускался через restart: unless-stopped, а не утаскивал за собой весь сервер по OOM.
services:
  cryptpad:
    mem_limit: 2g
    restart: unless-stopped

Также стоит проверить лимит открытых файловых дескрипторов — при большом числе одновременных WebSocket-соединений дефолтный ulimit в 1024 дескриптора на процесс исчерпывается быстрее, чем можно ожидать; как его поднять правильно (через systemd LimitNOFILE, а не только /etc/security/limits.conf), разобрано в статье про настройку лимитов открытых файлов.

Данные не восстанавливаются из бэкапа или ключи шифрования «теряются»

Здесь важно понимать саму модель CryptPad: ключи шифрования документов не хранятся на сервере вообще — они выводятся из ссылки на документ (точнее, из части URL после #, которая физически никогда не уходит на сервер по протоколу HTTP). Это значит, что бэкап сервера без сохранённых ссылок пользователей на их документы — это бэкап нечитаемого набора зашифрованных блобов. Сам сервер восстановить сможет, а расшифровать содержимое без оригинальных ссылок — нет, и это не баг, а прямое следствие end-to-end модели.

Практические выводы для бэкапа:

  • Бэкапьте не только datastore/ и blob/, но и data/ (в ней CryptPad хранит служебные метаданные и привязки аккаунтов) и сам config.js.
  • Просите пользователей сохранять ссылки на важные документы отдельно (например, через встроенную функцию «My Drive» — она как раз и существует для того, чтобы не терять доступ к документам, привязывая их к аккаунту, а не только к разовой ссылке).
  • Тестируйте восстановление бэкапа на отдельном сервере хотя бы раз — типичная ошибка в проде: бэкап делается регулярно, но при восстановлении выясняется, что права на каталоги не совпадают с тем пользователем, от которого запущен процесс (см. раздел про chown выше).

Общий подход к бэкапам сервисов на Docker Compose — тот же, что и для остальных приложений: Docker Compose для продакшена — частые ошибки и решения разбирает, как настроить том-бэкапы и не потерять состояние контейнера при обновлении образа.

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

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

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

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

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

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

Можно ли поставить CryptPad на сервер с 1 ГБ RAM?

Формально запустится, но под реальную работу нескольких человек с документами закончится память и OOM-килл процесса. Для теста хватит, для рабочего использования закладывайте от 2-4 ГБ.

Нужен ли отдельный домен под sandbox или можно обойтись поддиректорией?

Нужен именно отдельный домен или поддомен, а не путь — это требование модели безопасности CryptPad, поддиректория не сработает из-за политики Same-Origin для iframe.

Почему CryptPad не использует PostgreSQL или MySQL как остальные CMS?

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

WebSocket работает локально, но не работает через Cloudflare — почему?

Проверьте, что прокси (оранжевое облако) в Cloudflare не блокирует WebSocket на вашем тарифе, и что SSL-режим выставлен в Full (strict), а не Flexible — при Flexible соединение между Cloudflare и вашим сервером идёт по HTTP, и апгрейд до WSS часто рвётся.

Как понять, что причина именно в прокси, а не в самом CryptPad?

Зайдите на сервис напрямую по IP и порту (http://ваш-ip:3000), минуя nginx/Traefik. Если редактор открывается и сохраняет документы — проблема в конфигурации reverse-proxy, а не в CryptPad.

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

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

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