CryptPad на сервере: частые ошибки и решения
CryptPad — редкий случай, когда «облачный офис» реально не видит содержимое ваших документов: шифрование происходит в браузере, сервер хранит только зашифрованные блобы. Расплата за это — специфичный стек (Node.js-процесс + WebSocket-соединения + собственная файловая база вместо привычной SQL), который ломается не так, как обычный PHP-сайт. Если у вас страница CryptPad крутит спиннер вечно, документы не сохраняются или админка ругается на неверный ключ — ниже разобраны конкретные причины и что с ними делать.
Содержание
- Спиннер загрузки крутится бесконечно, редактор не открывается
- Ошибка «Insufficient storage» или документ не сохраняется
- Realtime-редактирование рассинхронизируется между участниками
- Sandbox iframe заблокирован, файлы не отображаются или не открываются
- Ошибка при входе администратора или невозможно попасть в admin-панель
- Высокое потребление памяти и падения процесса под нагрузкой
- Данные не восстанавливаются из бэкапа или ключи шифрования «теряются»
Обсудить статью, задать вопрос или начать новую тему
Есть вопрос по этой статье, идея для обсуждения или просто хотите поделиться опытом? Сообщество 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 ждёт. Для общения, пожалуйста, зарегистрируйтесь в нашем личном кабинете.
Перейти в сообщество →