Paperless-ngx на сервере: частые ошибки и решения
Paperless-ngx на бумаге — идеальное решение: скинул скан в папку, через минуту документ уже в поисковом архиве с распознанным текстом и тегами. На практике первая неделя эксплуатации обычно уходит на борьбу с зависшим OCR, файлами, которые не подхватываются, и редисом, который то и дело отваливается. Ниже — конкретные причины и решения для самых частых проблем, с которыми сталкиваются на VPS и выделенных серверах.
Содержание
Обсудить статью, задать вопрос или начать новую тему
Есть вопрос по этой статье, идея для обсуждения или просто хотите поделиться опытом? Сообщество MAATRIX ждёт. Для общения, пожалуйста, зарегистрируйтесь в нашем личном кабинете.
Перейти в сообщество →Базовый docker-compose и переменные окружения
Большинство проблем закладывается ещё на этапе конфигурации. Рабочий минимальный стек — три контейнера: webserver, redis (брокер для очереди задач) и postgres (основная БД, хотя можно и на sqlite, но для сервера это не вариант — блокировки при параллельной обработке).
services:
broker:
image: docker.io/library/redis:7
restart: unless-stopped
volumes:
- redisdata:/data
db:
image: docker.io/library/postgres:16
restart: unless-stopped
volumes:
- pgdata:/var/lib/postgresql/data
environment:
POSTGRES_DB: paperless
POSTGRES_USER: paperless
POSTGRES_PASSWORD: change_me_strong
webserver:
image: ghcr.io/paperless-ngx/paperless-ngx:latest
restart: unless-stopped
depends_on:
- db
- broker
ports:
- "8010:8000"
volumes:
- data:/usr/src/paperless/data
- media:/usr/src/paperless/media
- ./export:/usr/src/paperless/export
- ./consume:/usr/src/paperless/consume
environment:
PAPERLESS_REDIS: redis://broker:6379
PAPERLESS_DBHOST: db
PAPERLESS_DBUSER: paperless
PAPERLESS_DBPASS: change_me_strong
PAPERLESS_SECRET_KEY: сгенерируйте_своё_значение
PAPERLESS_URL: https://docs.example.com
PAPERLESS_TIME_ZONE: Europe/Moscow
PAPERLESS_OCR_LANGUAGE: rus+eng
USERMAP_UID: 1000
USERMAP_GID: 1000
volumes:
pgdata:
redisdata:
data:
media:
Три момента, на которых спотыкаются чаще всего:
PAPERLESS_SECRET_KEYпустой или дефолтный. Контейнер стартует, но сессии слетают при каждом рестарте, а иногда приложение просто не поднимает веб-интерфейс. Сгенерируйте случайную строку (openssl rand -base64 32) и зафиксируйте её — при смене ключа все активные сессии обнуляются.USERMAP_UID/USERMAP_GIDне совпадают с владельцем папок на хосте. Контейнер пишет вmediaиdataот имени этого UID. Если папки на сервере созданы от root, а в переменной стоит 1000 — получаетеPermissionErrorв логах воркера при попытке сохранить обработанный файл.- Postgres и Redis подняты позже webserver.
depends_onв Compose не ждёт готовности сервиса, только его старта. Postgres может ещё не принимать соединения, когда веб-контейнер уже пытается накатить миграции — первый запуск иногда падает именно из-за этого. Решение — healthcheck наdbиcondition: service_healthyвdepends_on, либо простоdocker compose upво второй раз (это не поломка, а гонка при первом старте).
Подробно про типичные проблемы самого Postgres, если база у вас общая для нескольких сервисов, — в статье PostgreSQL на сервере: частые ошибки и решения.
Consume-папка не подхватывает файлы
Кладёте PDF в ./consume, а он так и лежит нетронутым. Три типичные причины по убыванию частоты:
- Права на файл. Если файл скопирован с правами, недоступными для чтения тому UID, от которого работает контейнер, Paperless его просто не увидит — в логах будет тихо, без явной ошибки. Проверьте:
ls -la consume/и сравните владельца сUSERMAP_UID. - inotify не срабатывает на сетевых хранилищах. Если
consumeсмонтирован через NFS, SMB или это bind-mount из сетевой папки, файловые события inotify часто не долетают до контейнера. Симптом — файл лежит бесконечно, пока вы вручную не тронете содержимое папки. Решение — включить polling вместо inotify:
environment:
PAPERLESS_CONSUMER_POLLING: 30
Это заставляет consumer каждые 30 секунд сканировать папку вручную, а не полагаться на события ядра. Расход CPU минимальный, зато надёжно на любой файловой системе.
- Файл ещё дописывается. Если скрипт сканера или облачный синк пишет файл долго (например, большой multi-page TIFF), Paperless может попытаться забрать его раньше, чем запись завершится, и получить битый документ. Используйте
PAPERLESS_CONSUMER_RECURSIVE: trueвместе с записью через временное имя и последующимmv— атомарное переименование гарантирует, что consumer увидит файл только целиком.
Нужен сервер под эту задачу?
Разверните VPS MAATRIX за пару минут: NVMe, AMD EPYC, root-доступ, локации UK, США, Франция и РФ. Оплата картой РФ и по СБП.
Арендовать серверOCR падает или пропускает документы
Самая частая жалоба — статус задачи "Failed" без внятной причины в интерфейсе. Загляните в логи именно воркера, не веб-контейнера:
docker compose logs -f webserver | grep -i ocrmypdf
Типичные сценарии:
- Не хватает языкового пакета.
PAPERLESS_OCR_LANGUAGE: rus+engтребует, чтобы оба языка Tesseract были установлены в образе. Официальный образghcr.io/paperless-ngx/paperless-ngxвключает основные языки, но если вы используете кастомную сборку или урезанный образ — получите ошибкуFailed loading language 'rus'. Проверка внутри контейнера:
docker compose exec webserver tesseract --list-langs
- OCR уже был выполнен, но не устроил. Если PDF пришёл со встроенным (плохим) текстовым слоем, по умолчанию Paperless его не трогает (
PAPERLESS_OCR_MODE: skip). Чтобы принудительно распознать заново поверх кривого слоя, поставьтеPAPERLESS_OCR_MODE: redo(пересоздаёт текстовый слой) илиforce(полностью игнорирует существующий слой и OCR-ит с нуля, включая растеризацию). - Нехватка памяти на слабом VPS. OCR — не столько CPU-, сколько RAM-затратная операция, особенно на многостраничных сканах с высоким DPI. На тарифах 2 ГБ ОЗУ параллельная обработка 2-3 документов может уронить контейнер по OOM. Смотрите
dmesg | grep -i oom— если видите тамpaperlessилиpython3, снижайте параллелизм:
environment:
PAPERLESS_OCR_MAX_WORKERS: 1
PAPERLESS_TASK_WORKERS: 1
Ориентировочно: для комфортной обработки офисных сканов формата A4 достаточно 2 ГБ ОЗУ при одном воркере, но конкретная цифра сильно зависит от DPI и количества страниц в документе — у вас может отличаться в разы, проверяйте по факту через docker stats.
Redis и Postgres теряют соединение
redis.exceptions.ConnectionError в логах — почти всегда одно из двух: контейнер broker не запущен (проверьте docker compose ps), либо имя хоста в PAPERLESS_REDIS не совпадает с именем сервиса в Compose. Если вы переименовали сервис broker во что-то другое, не забудьте поправить переменную — Paperless резолвит хост через внутреннюю docker-сеть по имени сервиса, не по IP.
С Postgres чаще встречается FATAL: password authentication failed после смены пароля в .env — том с данными БД уже создан со старым паролем, и Postgres его не переинициализирует автоматически. Если меняли POSTGRES_PASSWORD уже после первого запуска, пароль нужно поменять и внутри самой БД:
docker compose exec db psql -U paperless -c "ALTER USER paperless WITH PASSWORD 'новый_пароль';"
После этого обновите PAPERLESS_DBPASS в переменных окружения webserver и перезапустите контейнер.
Реверс-прокси, HTTPS и ошибка CSRF
Если Paperless стоит за Nginx или Traefik и вы получаете 403 Forbidden — CSRF verification failed при попытке залогиниться, причина почти всегда одна: приложение не знает свой внешний адрес и не доверяет источнику запроса. Начиная с современных версий Paperless-ngx (Django 4+) нужно явно указать доверенные origin'ы:
environment:
PAPERLESS_URL: https://docs.example.com
Этой переменной обычно достаточно — она автоматически формирует CSRF_TRUSTED_ORIGINS и ALLOWED_HOSTS. Плюс важно, чтобы прокси прокидывал заголовок протокола:
location / {
proxy_pass http://127.0.0.1:8010;
proxy_set_header Host $host;
proxy_set_header X-Forwarded-For $proxy_add_x_forwarded_for;
proxy_set_header X-Forwarded-Proto $scheme;
}
Без X-Forwarded-Proto приложение думает, что работает по HTTP, даже если снаружи HTTPS, и часть проверок безопасности (включая CSRF) начинает вести себя непредсказуемо. Если используете Traefik — там своя специфика с middleware и лейблами, разобрана в статье Traefik на сервере: частые ошибки и решения.
Диск заполняется быстрее, чем ожидалось
Архив документов растёт незаметно: каждый скан хранится минимум дважды — оригинал в media/documents/originals и обработанная версия с текстовым слоем в media/documents/archive, плюс миниатюры и полнотекстовый индекс. На объёме в несколько тысяч документов легко набегают десятки гигабайт.
Что реально экономит место:
- Снизить DPI сканирования до 300 — для OCR этого достаточно, а 600 DPI раздувает архив почти вчетверо без ощутимого прироста качества распознавания.
PAPERLESS_OCR_PAGES, если нужно распознавать только первые N страниц длинных документов (например, для многостраничных приложений к договорам, где важна первая страница-обложка).- Проверять реальное потребление тома регулярно:
docker system df -vпокажет, сколько места съедает конкретный volume, а не контейнер в целом.
Если место на диске уже кончилось и контейнер не стартует — это отдельная и довольно частая история, разобрана в статье Docker занимает всё место на диске: причины и решение. На практике для домашнего архива на 5-10 тысяч документов с запасом хватает 40-60 ГБ диска, но если сканируете цветные развороты в высоком разрешении — закладывайте больше.
Бэкап и восстановление
Экспортёр документов — единственный способ бэкапа, который переживает смену версии Paperless (структура БД между релизами может меняться, а document_exporter сохраняет данные в переносимом формате с манифестом):
docker compose exec webserver document_exporter ../export
Команда выгружает все документы, метаданные и thumbnails в папку export, которая уже смонтирована как volume — то есть окажется на хосте. Восстановление — обратная команда:
docker compose exec webserver document_importer ../export
Для регулярного автобэкапа добавьте это в cron на хосте раз в сутки и синхронизируйте папку export на отдельное хранилище (S3-совместимое или другой сервер) — держать бэкап на том же диске, что и оригинал, бессмысленно при отказе диска. Общие практики автоматизации бэкапов Docker-томов, применимые и к media-папке Paperless, — в статье Как настроить бэкап Docker volume на VPS.
Нужен сервер под эту задачу?
Разверните VPS MAATRIX за пару минут: NVMe, AMD EPYC, root-доступ, локации UK, США, Франция и РФ. Оплата картой РФ и по СБП.
Арендовать серверНужны сами нейросети для контента?
Генерируйте изображения, видео и озвучку нейросетями на falapi.io — десятки моделей в одном окне. Оплата картой РФ и по СБП.
Частые вопросы
Paperless-ngx работает без Docker, напрямую на сервере?
Да, есть bare-metal установка через pip/venv, но она требует ручной настройки Tesseract, Redis, Postgres и systemd-юнитов для воркеров. Docker Compose закрывает всё это одной командой и остаётся рекомендуемым способом даже в официальной документации проекта.
Почему интерфейс открывается, но документы не ищутся по тексту?
Обычно причина в том, что полнотекстовый индекс не пересобран после массового импорта. Запустите docker compose exec webserver document_index reindex — команда пересоздаёт поисковый индекс с нуля.
Можно ли распознавать документы на нескольких языках одновременно?
Да, PAPERLESS_OCR_LANGUAGE: rus+eng+deu и так далее — Tesseract попробует все указанные языки и выберет лучший результат, но это заметно увеличивает время OCR на каждый документ.
Сколько ресурсов сервера нужно для 20-30 сканов в день?
Для такого потока хватает 2 vCPU и 2-4 ГБ ОЗУ на одном воркере — сама по себе задача не постоянная, а пиковая, нагрузка приходится только на момент обработки новой партии.
Что делать, если после обновления образа воркеры зависли в статусе "Started"?
Чаще всего это старая задача в очереди Redis, которая ссылается на несуществующий уже task ID. Помогает docker compose exec broker redis-cli FLUSHDB — очистит очередь задач (сами документы и БД это не затрагивает) — и перезапуск webserver.
Обсудить статью, задать вопрос или начать новую тему
Есть вопрос по этой статье, идея для обсуждения или просто хотите поделиться опытом? Сообщество MAATRIX ждёт. Для общения, пожалуйста, зарегистрируйтесь в нашем личном кабинете.
Перейти в сообщество →