SSD Nodes Learn Hosting plans →
Руководства Matt ConnorАвтор: Matt Connor · Обновлено 2026-10-12

Установка Paperless-ngx на VPS через Docker Compose

Пошаговое руководство по развертыванию Paperless-ngx на удаленном сервере. Настройка Postgres, переменных PAPERLESS_URL, OCR, HTTPS и организация резервного копирования данных.

Что вы создаете

Paperless-ngx на VPS превращает папку со сканами документов в архив с возможностью поиска. Вы помещаете PDF в отслеживаемую директорию, сервер выполняет OCR (оптическое распознавание символов), извлекает текст, определяет дату и корреспондента, а затем сохраняет файл. Установка состоит из одного файла Docker Compose с четырьмя сервисами. Все последующие действия — это настройка, и данное руководство уделяет ей основное внимание, так как именно здесь чаще всего возникают сбои. Это не фотогалерея: OCR и определение корреспондента бесполезны для папки с праздничными JPEG-файлами, поэтому храните их в специализированном фотосервере, а Paperless оставьте для документов. С видео ситуация аналогична: коллекция оцифрованных фильмов должна находиться на медиасервере, где, например, интерфейс Jellyfin, стилизованный под видеопрокат 90-х, делает акцент на просмотре, а не на поиске.

Paperless-ngx — это поддерживаемый сообществом форк оригинального проекта Paperless. Он бесплатен, предназначен для self-hosted размещения и хранит документы в виде обычных файлов на диске, поэтому вы никогда не потеряете доступ к своему архиву. Запуск на VPS, а не на домашнем сервере, означает, что ваши сканы доступны из любого места без открытия портов на домашнем роутере. Это решение хорошо сочетается с личным экземпляром Nextcloud для файлов, не являющихся документами. Тот же принцип применим к компьютеру, к которому подключен сканер, поскольку собственный ретранслятор RustDesk на этом VPS позволяет управлять этой машиной извне, не создавая брешей в защите роутера.

Что именно запускает стек

Официальный compose-файл запускает четыре контейнера. Понимание функций каждого из них помогает при чтении логов.

  • webserver: сам образ paperless-ngx. Он запускает веб-интерфейс, API, потребителя (consumer), который отслеживает вашу папку входящих документов, и рабочие процессы Celery, выполняющие OCR.
  • db: PostgreSQL. В нём хранятся метаданные, теги, корреспонденты и таблицы полнотекстового поискового индекса. Сами PDF-файлы здесь не хранятся.
  • broker: Valkey, хранилище типа «ключ-значение», совместимое с Redis. Оно служит очередью задач между веб-процессом и рабочими процессами.
  • gotenberg и tika: опциональные компоненты, присутствуют только в вариантах compose -tika. Они преобразуют документы Office (.docx, .xlsx, .odt) в формат PDF, чтобы paperless мог их индексировать.

По состоянию на октябрь 2026 года compose-файл для postgres фиксирует версии docker.io/library/postgres:18 и docker.io/valkey/valkey:9-alpine, а само приложение загружается из ghcr.io/paperless-ngx/paperless-ngx:latest.

Предварительные требования

  • VPS на базе Ubuntu 24.04 с KVM, доступом sudo и установленным Docker с плагином Compose. Если вы с этим еще не работали, начните с основ Docker Compose для VPS и вернитесь сюда.
  • Доменное имя с A-записью, указывающей на ваш VPS. Paperless не разрешит вход по HTTPS для имени хоста, которое не было задано в конфигурации, поэтому это важно сделать раньше, чем вы ожидаете.
  • Оперативная память — основной ограничивающий фактор. PostgreSQL, Valkey, веб-сервер Granian и воркер Tesseract OCR при одновременной работе требуют 2 GB для легкой нагрузки. Выделите 4 GB, если планируете импортировать большой архив из сотен сканов, так как OCR для объемных многостраничных PDF вызывает скачок потребления памяти, из-за которого ядро может принудительно завершить процесс (OOM killer).
  • Диск: ваш архив хранится в двух экземплярах — исходный файл и PDF с распознанным текстом, поэтому планируйте объем хранилища примерно в два раза больше размера ваших сканов.

Получение официальных compose-файлов

Существует интерактивный установщик:

bash -c "$(curl --location --silent --show-error https://raw.githubusercontent.com/paperless-ngx/paperless-ngx/main/install-paperless-ngx.sh)"

Он задает вопросы и создает файлы за вас. Ручная настройка состоит из четырех команд и позволяет точно знать расположение всех компонентов, что необходимо для сервера, который вы будете обслуживать.

mkdir -p ~/paperless && cd ~/paperless
curl -fsSL -o docker-compose.yml https://raw.githubusercontent.com/paperless-ngx/paperless-ngx/main/docker/compose/docker-compose.postgres.yml
curl -fsSL -o docker-compose.env https://raw.githubusercontent.com/paperless-ngx/paperless-ngx/main/docker/compose/docker-compose.env
curl -fsSL -o .env https://raw.githubusercontent.com/paperless-ngx/paperless-ngx/main/docker/compose/.env

Варианты находятся в одном каталоге: docker-compose.sqlite.yml, docker-compose.mariadb.yml и -tika-версия для каждого из них. Выбирайте postgres для новой установки. SQLite подходит для нескольких сотен документов, но индекс полнотекстового поиска начинает работать медленно значительно раньше, чем в случае с PostgreSQL.

Файл .env содержит одну строку: COMPOSE_PROJECT_NAME=paperless. Это имя становится префиксом для каждого контейнера и тома, поэтому не удаляйте его, чтобы потом не гадать, почему docker compose down -v не может найти ваши данные.

Настройка docker-compose.env перед первым запуском

Два параметра являются обязательными. Сгенерируйте секретный ключ с помощью команды, указанной в документации проекта:

python3 -c "import secrets; print(secrets.token_urlsafe(64))"

Затем отредактируйте docker-compose.env:

PAPERLESS_SECRET_KEY=<the long string you just generated>
PAPERLESS_URL=https://paperless.example.com
PAPERLESS_TIME_ZONE=Europe/Berlin
PAPERLESS_OCR_LANGUAGE=deu+eng
USERMAP_UID=1000
USERMAP_GID=1000

PAPERLESS_SECRET_KEY поставляется со значением change-me. Оно используется для подписи токенов сессии, и текущие релизы считают это значение не заданным: paperless отказывается запускаться, если ключ отсутствует, пуст или всё ещё имеет значение change-me, поэтому стек не поднимется, пока вы его не замените. Установите его до первого запуска, так как изменение ключа позже приведет к выходу из системы всех пользователей.

PAPERLESS_URL — это параметр, который сэкономит вам час времени. Paperless является приложением на Django, а Django проверяет как заголовок Host, так и источник (origin), который сообщает браузер при отправке формы входа. Установите PAPERLESS_URL, и приложение автоматически добавит ваш адрес в ALLOWED_HOSTS, CORS_ALLOWED_HOSTS и CSRF_TRUSTED_ORIGINS. Если оставить его пустым и направить домен на сервер, страница входа всё равно загрузится, так как PAPERLESS_ALLOWED_HOSTS по умолчанию имеет значение *, но попытка входа по HTTPS завершится ошибкой CSRF verification failed. Request aborted., поскольку ваш домен не является доверенным источником. Укажите адрес без слеша в конце и без пути.

USERMAP_UID и USERMAP_GID определяют пользователя, от имени которого работает контейнер. Установите их в соответствии с вашей учетной записью, которую можно проверить командами id -u и id -g. Если они не совпадают, файлы, которые вы копируете в папку consume, будут недоступны для чтения потребителю, а в логах вместо импорта появится ошибка доступа.

Запуск стека и создание первого пользователя

docker compose pull
docker compose up -d
docker compose run --rm webserver createsuperuser
docker compose logs -f webserver

createsuperuser запрашивает имя пользователя, адрес электронной почты и пароль. Учётные данные по умолчанию отсутствуют. Если пропустить этот шаг, веб-интерфейс предложит первому открывшему его пользователю создать учётную запись суперпользователя. Поскольку порт 8000 в этот момент открыт для доступа из Интернета, этим пользователем можете оказаться не вы, поэтому создайте учётную запись через командную строку сразу. Дождитесь появления в логах сообщения о том, что сервер ожидает подключений на порту 8000, прежде чем открывать браузер. При самом первом запуске также выполняются миграции базы данных, что занимает одну-две минуты.

Проверьте работу локально, прежде чем подключать домен:

curl -I http://127.0.0.1:8000

Перенаправление 302 на /accounts/login/ означает, что стек функционирует корректно.

Настройка HTTPS перед сервисом

Стандартный файл compose публикует 8000:8000, который привязывается ко всем сетевым интерфейсам. На публичном VPS это означает, что весь ваш архив документов передается по обычному HTTP любому, кто узнает адрес. Измените строку с портом, чтобы привязать его только к loopback-интерфейсу:

    ports:
      - "127.0.0.1:8000:8000"

Затем настройте TLS (transport layer security) на reverse proxy и перенаправляйте трафик на 127.0.0.1:8000. Если это единственное приложение на сервере, подойдет любой прокси с клиентом ACME (automatic certificate management environment). Если вы запускаете несколько контейнеров за одной конфигурацией сертификатов, используйте шаблон reverse proxy Traefik для нескольких приложений Docker Compose и подключите сервис webserver к сети прокси без публикации портов.

Какой бы прокси вы ни использовали, проверка источника (origin check) в форме входа — это место, где конфигурации HTTPS часто дают сбой. Paperless игнорирует X-Forwarded-Proto, если вы не зададите PAPERLESS_PROXY_SSL_HEADER (по умолчанию эта настройка выключена). В результате Django воспринимает каждый проксируемый запрос как обычный HTTP, а заголовок https://, который отправляет ваш браузер, проходит проверку только в том случае, если он указан как доверенный. Параметр PAPERLESS_URL, установленный в точное значение https://, которое вы вводите в браузере, добавляет его в этот список. Без этого вы получите ошибку CSRF verification failed. Request aborted. на странице, которая выглядит корректно.

Также увеличьте лимит размера загружаемых файлов в настройках прокси. Скан размером 40 МБ, проходящий через прокси с ограничением тела запроса в 1 МБ, будет отклонен еще до того, как попадет в paperless, а браузер сообщит об общей ошибке загрузки.

Как работает каталог consume

Файл compose выполняет bind-mount каталога ./consume из директории compose внутрь контейнера. Любой файл, помещенный туда, импортируется и затем удаляется из папки, так как файл теперь хранится в томе media под управлением paperless.

cp ~/scan-2026-07-14.pdf ~/paperless/consume/
docker compose logs -f webserver

Вы должны увидеть, как потребитель (consumer) считывает имя файла, выполняет OCR и завершает работу строкой с отчетом о добавлении документа. Весь цикл занимает несколько секунд для одностраничного скана и может длиться минуту или дольше для объемного документа.

Две настройки меняют способ поиска файлов. PAPERLESS_CONSUMER_RECURSIVE=true заставляет paperless искать файлы во вложенных папках, а PAPERLESS_CONSUMER_SUBDIRS_AS_TAGS=true превращает имя каждой вложенной папки в тег, поэтому при перемещении файла в consume/invoices/2026/ он получает теги invoices и 2026. Это самая простая система архивации, которую вы когда-либо создадите.

Обнаружение — это вторая часть процесса. По умолчанию PAPERLESS_CONSUMER_POLLING_INTERVAL имеет значение 0, что означает, что paperless использует встроенные уведомления файловой системы, которые срабатывают мгновенно. Эти уведомления ненадежны при работе с сетевыми файловыми системами. Если ваш каталог consume является сетевым ресурсом NFS или SMB, чтобы сетевой сканер мог записывать в него файлы, они могут оставаться необнаруженными. Решение заключается в том, чтобы установить интервал в положительное число секунд, чтобы paperless сканировал папку по расписанию.

Языки OCR и их стоимость

PAPERLESS_OCR_LANGUAGE принимает трехбуквенный код Tesseract, по умолчанию используется eng. Объединяйте языки знаком «плюс», как в deu+eng. Tesseract будет использовать каждый указанный язык для каждой страницы, поэтому каждый дополнительный язык увеличивает нагрузку на CPU при сканировании. На VPS с общими vCPU это может привести к тому, что сканирование будет занимать не десять секунд, а минуту. Указывайте только те языки, на которых написаны ваши документы.

Образ поставляется с поддержкой английского, немецкого, итальянского, испанского и французского языков. Для добавления других языков укажите их в PAPERLESS_OCR_LANGUAGES в виде списка, разделенного пробелами, например PAPERLESS_OCR_LANGUAGES=tur ces, и перезапустите контейнер. Контейнер загружает пакеты данных Tesseract при запуске, поэтому первая загрузка после внесения изменений будет медленнее.

Резервное копирование базы данных и медиафайлов

Копирование Docker-томов во время работы PostgreSQL может привести к созданию резервной копии, которую не удастся восстановить. Paperless поставляется с собственным инструментом экспорта, который записывает документы и JSON-манифест со всеми метаданными в bind mount ./export:

docker compose exec -T webserver document_exporter ../export --delete --no-progress-bar

--delete удаляет экспортированные файлы, которые больше не соответствуют текущим документам, поэтому папка остается зеркальной копией, а не разрастается бесконечно. --no-progress-bar обеспечивает чистоту вывода при запуске из cron, а -T предотвращает запрос терминала со стороны Compose, так как в cron он отсутствует.

Восстановление выполняется с помощью document_importer из той же папки на новом стеке, что означает, что директория экспорта — это единственное, что необходимо хранить в безопасности. Отправляйте её на удаленное хранилище по расписанию с помощью зашифрованных дедуплицированных резервных копий restic с вашего VPS, и запускайте экспорт перед этим, чтобы restic не захватил наполовину записанный архив.

Проверяйте резервную копию, убедившись, что export/manifest.json существует и количество файлов совпадает с количеством документов в интерфейсе. Резервная копия, которую вы никогда не проверяли, — это не резервная копия. Ежедневный экспорт, который тихо перестает работать, ещё хуже, поэтому настройте cron-задачу на отправку статуса завершения на ваш собственный ntfy сервер, чтобы узнать о сбое в ту же неделю, а не в день, когда потребуется восстановление.

FAQ

Почему каждая страница возвращает "Bad Request (400)" после того, как я направил на неё свой домен?

При использовании стандартных файлов этого быть не должно, так как PAPERLESS_ALLOWED_HOSTS по умолчанию имеет значение *. Ошибка 400 с DisallowedHost в логе контейнера означает, что PAPERLESS_ALLOWED_HOSTS был задан списком, в котором отсутствует ваш домен. Установите PAPERLESS_URL=https://paperless.example.com в docker-compose.env без косой черты в конце, и paperless добавит это имя хоста в список, либо удалите строку PAPERLESS_ALLOWED_HOSTS. Затем выполните docker compose up -d, чтобы пересоздать контейнер. Редактирование только файла окружения не даст результата, так как запущенный контейнер сохраняет переменные окружения, с которыми он был запущен.

Я поместил PDF в папку consume, но ничего не произошло. В чем проблема?

Сначала проверьте docker compose logs webserver. Ошибка прав доступа означает, что USERMAP_UID и USERMAP_GID не совпадают с учетной записью, которой принадлежит файл; исправьте их и пересоздайте контейнер. Отсутствие записей в логе означает, что событие файловой системы не было получено, что случается на сетевых ресурсах, так как нативные уведомления файловой системы там работают ненадежно. Установите PAPERLESS_CONSUMER_POLLING_INTERVAL в значение, например, 30, и paperless будет сканировать папку каждые 30 секунд.

Могу ли я запустить paperless-ngx с SQLite вместо PostgreSQL?

Да, docker-compose.sqlite.yml поддерживается и потребляет меньше оперативной памяти, что подходит для небольших VPS. Недостаток проявляется по мере роста архива: полнотекстовый поиск и массовое редактирование тегов заметно замедляются при наличии тысяч документов. Миграция в будущем потребует экспорта и импорта данных, поэтому выбирайте PostgreSQL сейчас, если ожидаете, что архив будет расти.

Сколько дискового пространства нужно для архива сканов?

Примерно в два раза больше объема исходных файлов. Paperless сохраняет оригинал без изменений и создает второй PDF с OCR-слоем для поиска, а также небольшие миниатюры. Скан текста размером 200 KB остается небольшим. Цветной скан длинного контракта размером 30 MB займет около 60 MB. Добавьте сюда директорию экспорта, если вы храните её на том же диске, и один и тот же архив будет занимать место на диске трижды.

Нужны ли мне контейнеры Tika и Gotenberg?

Только если вы хотите, чтобы файлы Word, Excel или OpenDocument индексировались вместе с вашими PDF. Они преобразуют эти форматы в PDF, чтобы paperless мог выполнить OCR и поиск по ним. Они также добавляют два работающих контейнера и потребляют несколько сотен мегабайт оперативной памяти, поэтому пропустите их на маломощном сервере, если всё, что вы загружаете, — это уже PDF или изображения.

Была ли эта статья полезной?

#paperless-ngx#documents#self-hosting#docker#ocr