Самостоятельный хостинг Paperless-ngx на VPS с Docker Compose
Разверните Paperless-ngx на VPS с Docker Compose, PostgreSQL и Redis. Настройте языки и режимы OCR, правила автоматической разметки, получение документов по email и стратегию резервного копирования с удалённой синхронизацией.
Paperless-ngx превращает VPS в архив документов с полнотекстовым поиском. Сканируешь или загружаешь документы, Paperless-ngx прогоняет их через OCR, делает доступными для поиска и автоматически расставляет теги и корреспондентов. Работает как Docker Compose-стек с PostgreSQL, Redis и Gotenberg для конвертации документов.
Это руководство разворачивает Paperless-ngx на VPS, где уже установлены Docker и reverse proxy. Если этой базы ещё нет, начни с нашего руководства по настройке базового Docker-стека.
Какие ресурсы нужны Paperless-ngx на VPS?
Paperless-ngx требует минимум 2 ГБ RAM, рекомендуется 4 ГБ. Стек запускает PostgreSQL, Redis, Gotenberg, Tika и веб-сервер. В простое общее потребление памяти около 800 МБ. Во время OCR-обработки отсканированных PDF нагрузка CPU поднимается до 100% на одном ядре, а потребление RAM растёт до 1,5-2 ГБ. Дисковое пространство в среднем 5-10 МБ на документ (оригинал + архив + миниатюра).
| Компонент | RAM (простой) | RAM макс. (OCR) | Диск на 1000 документов |
|---|---|---|---|
| Paperless-ngx webserver | ~300 МБ | ~900 МБ | 5-10 ГБ |
| PostgreSQL | ~50 МБ | ~100 МБ | ~500 МБ |
| Redis | ~10 МБ | ~10 МБ | пренебрежимо |
| Gotenberg | ~150 МБ | ~300 МБ | — |
| Tika | ~250 МБ | ~400 МБ | — |
| Итого | ~760 МБ | ~1 710 МБ | 5-10 ГБ |
Планируй дисковое пространство исходя из объёма документов. Домашнему пользователю, сканирующему 50 документов в месяц, нужно около 6 ГБ в год. Малому бизнесу с 500 документами/месяц стоит закладывать 50-60 ГБ в год.
Как развернуть Paperless-ngx с Docker Compose на VPS?
Создай директорию для стека, сгенерируй секреты и напиши Compose-файл. Для каждого сервиса настроен health check, чтобы Docker автоматически перезапускал проблемные контейнеры.
Создать директорию проекта
mkdir -p /opt/paperless-ngx && cd /opt/paperless-ngx
Сгенерировать секреты
Никогда не используй пароли по умолчанию. Сгенерируй надёжный пароль для базы данных и секретный ключ Django:
openssl rand -base64 32 > .db_password
openssl rand -base64 48 > .secret_key
chmod 600 .db_password .secret_key
Файлы остаются на диске с ограниченными правами. Compose-файл читает их при старте контейнеров.
Написать файл окружения
cat > .env << 'EOF'
COMPOSE_PROJECT_NAME=paperless
EOF
Написать Compose-файл
# docker-compose.yml
services:
broker:
image: docker.io/library/redis:8
restart: unless-stopped
volumes:
- redisdata:/data
healthcheck:
test: ["CMD", "redis-cli", "ping"]
interval: 30s
timeout: 5s
retries: 3
db:
image: docker.io/library/postgres:18
restart: unless-stopped
volumes:
- pgdata:/var/lib/postgresql/data
environment:
POSTGRES_DB: paperless
POSTGRES_USER: paperless
POSTGRES_PASSWORD_FILE: /run/secrets/db_password
secrets:
- db_password
healthcheck:
test: ["CMD-SHELL", "pg_isready -U paperless"]
interval: 30s
timeout: 5s
retries: 3
gotenberg:
image: docker.io/gotenberg/gotenberg:8
restart: unless-stopped
command:
- "gotenberg"
- "--chromium-disable-javascript=true"
- "--chromium-allow-list=file:///tmp/.*"
healthcheck:
test: ["CMD", "curl", "-f", "http://localhost:3000/health"]
interval: 30s
timeout: 5s
retries: 3
tika:
image: docker.io/apache/tika:latest
restart: unless-stopped
healthcheck:
test: ["CMD", "curl", "-f", "http://localhost:9998/"]
interval: 30s
timeout: 5s
retries: 3
webserver:
image: ghcr.io/paperless-ngx/paperless-ngx:latest
restart: unless-stopped
depends_on:
db:
condition: service_healthy
broker:
condition: service_healthy
gotenberg:
condition: service_healthy
tika:
condition: service_healthy
ports:
- "127.0.0.1:8000: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_FILE: /run/secrets/db_password
PAPERLESS_TIKA_ENABLED: 1
PAPERLESS_TIKA_GOTENBERG_ENDPOINT: http://gotenberg:3000
PAPERLESS_TIKA_ENDPOINT: http://tika:9998
PAPERLESS_SECRET_KEY_FILE: /run/secrets/secret_key
PAPERLESS_OCR_LANGUAGE: eng
PAPERLESS_OCR_MODE: skip
PAPERLESS_OCR_OUTPUT_TYPE: pdfa
PAPERLESS_FILENAME_FORMAT: "{created_year}/{correspondent}/{title}"
PAPERLESS_URL: https://paperless.example.com
USERMAP_UID: 1000
USERMAP_GID: 1000
secrets:
- db_password
- secret_key
healthcheck:
test: ["CMD", "curl", "-f", "http://localhost:8000"]
interval: 30s
timeout: 10s
retries: 5
start_period: 60s
secrets:
db_password:
file: .db_password
secret_key:
file: .secret_key
volumes:
data:
media:
pgdata:
redisdata:
Об этой конфигурации:
- Порты привязаны только к 127.0.0.1. Reverse proxy обеспечивает публичный доступ по HTTPS. Если открыть порт 8000 на
0.0.0.0, это обойдёт TLS и файрвол. - Секреты используют Docker secrets (переменные с суффиксом
_FILE). Пароли не появляются в выводеdocker inspectили в списке процессов. USERMAP_UID/USERMAP_GIDмаппят пользователя контейнера на UID 1000 на хосте. Файлы, создаваемые в директориях consume и export, принадлежат этому пользователю.PAPERLESS_URLдолжен совпадать с публичным доменом. Paperless-ngx использует его для генерации ссылок и URL в письмах. Замениpaperless.example.comна свой реальный домен.
Запустить стек
docker compose up -d
Подожди около 60 секунд, пока все сервисы инициализируются. Проверь, что каждый контейнер здоров:
docker compose ps
NAME SERVICE STATUS PORTS
paperless-broker-1 broker running (healthy)
paperless-db-1 db running (healthy)
paperless-gotenberg-1 gotenberg running (healthy)
paperless-tika-1 tika running (healthy)
paperless-webserver-1 webserver running (healthy) 127.0.0.1:8000->8000/tcp
Все пять контейнеров должны показывать (healthy). Если какой-то показывает (health: starting), подожди ещё 30 секунд. Если контейнер остаётся (unhealthy), проверь его логи:
docker compose logs gotenberg --tail 20
Создать суперпользователя
docker compose exec webserver createsuperuser
Следуй подсказкам для ввода имени пользователя, email и пароля. Это твой аккаунт администратора для веб-интерфейса.
Доступ к веб-интерфейсу
Если reverse proxy настроен, открой https://paperless.example.com в браузере. Загрузится страница входа Paperless-ngx. Если reverse proxy ещё не настроен, проверь локально:
curl -s -o /dev/null -w "%{http_code}" http://127.0.0.1:8000
200
Какие языки и режимы OCR настроить?
Paperless-ngx использует Tesseract для OCR. Язык и режим обработки настраиваются через переменные окружения. Значения по умолчанию подходят для документов на английском, но большинству пользователей нужно их изменить.
Язык OCR
Установи PAPERLESS_OCR_LANGUAGE в трёхбуквенный код языка Tesseract для твоих документов. Для нескольких языков соедини их через +:
# Один язык
PAPERLESS_OCR_LANGUAGE: rus
# Несколько языков
PAPERLESS_OCR_LANGUAGE: rus+eng+deu
Распространённые коды языков: eng (английский), deu (немецкий), fra (французский), spa (испанский), ita (итальянский), nld (нидерландский), por (португальский), rus (русский). Полный список в документации Tesseract.
Образ контейнера включает большинство языковых пакетов. Добавление языков в PAPERLESS_OCR_LANGUAGE увеличивает время OCR-обработки на страницу.
Режимы OCR
Параметр PAPERLESS_OCR_MODE определяет, как Paperless-ngx обрабатывает документы, которые уже содержат текстовый слой (типично для PDF, созданных цифровым способом).
| Режим | Поведение | Когда использовать |
|---|---|---|
skip |
OCR только для страниц без текста. Всегда создаёт архивную копию. | По умолчанию. Подходит для смешанного ввода: сканы + цифровые PDF. |
skip_noarchive |
Как skip, но без создания архива для документов с текстом. |
Нужно сэкономить место на цифровых PDF. |
redo |
Повторный OCR всех страниц с заменой существующих текстовых слоёв. | Получаешь документы с плохим OCR от сканеров. |
force |
Растеризация документа и OCR с нуля. Уничтожает исходный текст. | Крайний случай. Создаёт файлы большего размера с менее чётким текстом. |
Для большинства установок skip — правильный выбор. Обрабатывает и сканы, и цифровые документы, не тратя CPU на повторную обработку уже индексированных документов.
Если получаешь документы от сканера с собственным (плохим) OCR, переключи режим на redo. Учти, что redo несовместим с PAPERLESS_OCR_CLEAN и PAPERLESS_OCR_DESKEW.
Тип вывода OCR
PAPERLESS_OCR_OUTPUT_TYPE: pdfa (по умолчанию) создаёт файлы PDF/A — архивный стандарт. Они самодостаточны и содержат встроенные шрифты. Оставь эту настройку, если нет веской причины менять.
После изменения любых настроек OCR перезапусти контейнер webserver:
docker compose restart webserver
Существующие документы не обрабатываются повторно. Чтобы повторно запустить OCR для документа, используй действие «Redo OCR» в веб-интерфейсе.
Как работает автоматическая разметка в Paperless-ngx?
Paperless-ngx поддерживает шесть алгоритмов сопоставления для тегов, корреспондентов и типов документов. Когда документ поступает, каждый тег сверяет содержимое со своим шаблоном. Если шаблон совпадает, тег применяется автоматически.
| Алгоритм | Как работает | Когда использовать | Пример |
|---|---|---|---|
| Any | Совпадает, если любое слово из поля совпадения встречается. | Широкие категории. | invoice receipt bill |
| All | Совпадает, если все слова встречаются (в любом порядке). | Более точное сопоставление без привязки к позиции. | electricity quarterly |
| Exact | Точное совпадение фразы по порядку. | Названия компаний, номера счетов. | Acme Corp |
| Regular Expression | Полноценное сопоставление по регулярному выражению. | Структурированные данные: даты, номера, суммы. | Invoice\s+#?\d{4,} |
| Fuzzy | Приблизительное совпадение с настраиваемым порогом. | Нестабильный OCR, мелкие опечатки. | Stadtwerke (совпадает с Stadtwenke) |
| Auto | ML-классификатор, обучающийся на твоих ручных назначениях. | После ~50+ документов, размеченных вручную. | (учится на твоих исправлениях) |
Создание тегов с правилами сопоставления
В веб-интерфейсе перейди в Manage > Tags и создай тег. Установи алгоритм сопоставления и поле Match. Несколько практических примеров:
- Тег: Invoice, Алгоритм:
Any, Match:invoice rechnung facture счёт(ловит счета на разных языках) - Тег: Bank, Алгоритм:
Regular Expression, Match:IBAN\s*[A-Z]{2}\d{2}(совпадает с любым номером IBAN) - Тег: Medical, Алгоритм:
All, Match:patient diagnosis(требует оба слова) - Корреспондент: Electric Company, Алгоритм:
Exact, Match:Springfield Energy Inc
Обучение Auto-классификатора
Алгоритм Auto использует ML-классификатор, который Paperless-ngx переобучает автоматически. Для обучения:
- Вручную разметь как минимум 50 документов по категориям
- Убедись, что эти документы не во входящих (классификатор игнорирует документы из входящих)
- Классификатор переобучается по расписанию (по умолчанию: каждый час через
document_create_classifier) - Новые документы начинают получать автоматические назначения
Можно запустить переобучение вручную:
docker compose exec webserver document_create_classifier
Классификатор улучшается с каждым исправлением. Каждое исправление попадает в следующий цикл обучения.
Как настроить приём документов в Paperless-ngx?
Paperless-ngx принимает документы по трём каналам: ручная загрузка через веб-интерфейс, отслеживаемая папка на диске и получение email по IMAP.
Загрузка через веб-интерфейс
Перетащи файлы в веб-интерфейс. Работает сразу после установки. Поддерживаемые форматы: PDF, PNG, JPEG, TIFF и (при включённом Tika) DOCX, XLSX, ODT и другие офисные форматы.
Отслеживаемая папка (директория consume)
Директория ./consume, смонтированная в Compose-файле, отслеживается через inotify. Положи файл — и Paperless-ngx подхватит его за секунды.
cp /tmp/scan-001.pdf /opt/paperless-ngx/consume/
Файл исчезает из директории consume после завершения обработки. Чтобы организовать приём по тегам, включи теги по подпапкам:
PAPERLESS_CONSUMER_RECURSIVE: true
PAPERLESS_CONSUMER_SUBDIRS_AS_TAGS: true
С этой настройкой файл в consume/invoices/scan.pdf автоматически получит тег invoices.
Приём email (IMAP)
Приём email настраивается целиком в веб-интерфейсе в разделе Manage > Mail. Добавляешь почтовые аккаунты и правила.
Добавить почтовый аккаунт:
- Перейди в Manage > Mail > Mail Accounts
- Укажи IMAP-сервер, порт (993 для TLS), имя пользователя и пароль
- Укажи папку для мониторинга (например,
INBOX)
Добавить правило:
- Перейди в Manage > Mail > Mail Rules
- Выбери почтовый аккаунт
- Выбери, что принимать: только вложения или всё письмо как PDF
- Задай действие для обработанных писем: пометить как прочитанное, переместить в папку или удалить
- Опционально назначь тег, корреспондента или тип документа
Типичная настройка: пересылай документы на выделенный email (например, scan@tvoidomen.ru), настрой Paperless-ngx на мониторинг этого ящика и приём вложений. Оригиналы после обработки перемещаются в IMAP-папку «Archived».
Как организовать пути хранения и имена файлов?
Paperless-ngx хранит документы в двух местах: том media содержит файлы на диске, а PostgreSQL управляет метаданными. Переменная PAPERLESS_FILENAME_FORMAT определяет именование архивных файлов в директории media.
Compose-файл выше использует:
PAPERLESS_FILENAME_FORMAT: "{created_year}/{correspondent}/{title}"
Это создаёт структуру вида:
media/documents/archive/
2026/
Springfield Energy Inc/
Electricity Bill January 2026.pdf
Dr. Smith/
Lab Results March 2026.pdf
Доступные переменные шаблона: {created_year}, {created_month}, {created_day}, {correspondent}, {document_type}, {title}, {tag_list} и {owner_username}. Если переменная пуста (корреспондент не назначен), Paperless-ngx заменяет её на none.
После изменения формата имён примени его к существующим документам:
docker compose exec webserver document_renamer
Какая стратегия резервного копирования лучше для Paperless-ngx?
Рабочий бэкап покрывает базу данных PostgreSQL, файлы документов (оригиналы + архивы + миниатюры) и метаданные Paperless-ngx (теги, корреспонденты, правила сопоставления). Экспортёр документов фиксирует всё это в переносимом формате. Дополни его дампом базы данных для более быстрого восстановления только БД.
Дамп базы данных
docker compose exec db pg_dump -U paperless paperless | gzip > /opt/paperless-ngx/backups/db-$(date +%Y%m%d).sql.gz
Экспортёр документов
Экспортёр создаёт полный снапшот: документы, метаданные и манифест. Это каноническая процедура бэкапа.
docker compose exec webserver document_exporter ../export -c -d
Флаг -c сравнивает контрольные суммы (экспортирует только изменённые файлы). Флаг -d удаляет из экспорта файлы, которых больше нет в Paperless-ngx. Вместе они поддерживают директорию экспорта как зеркало текущего состояния.
Автоматизация через cron
Создай скрипт бэкапа:
cat > /opt/paperless-ngx/backup.sh << 'SCRIPT'
#!/bin/bash
set -euo pipefail
BACKUP_DIR="/opt/paperless-ngx/backups"
EXPORT_DIR="/opt/paperless-ngx/export"
mkdir -p "$BACKUP_DIR"
# Database dump
docker compose -f /opt/paperless-ngx/docker-compose.yml exec -T db \
pg_dump -U paperless paperless | gzip > "$BACKUP_DIR/db-$(date +%Y%m%d).sql.gz"
# Document exporter
docker compose -f /opt/paperless-ngx/docker-compose.yml exec -T webserver \
document_exporter ../export -c -d
# Remove database dumps older than 30 days
find "$BACKUP_DIR" -name "db-*.sql.gz" -mtime +30 -delete
echo "[$(date -Is)] Backup completed" >> "$BACKUP_DIR/backup.log"
SCRIPT
chmod 700 /opt/paperless-ngx/backup.sh
Запланируй через cron (существующие записи crontab сохраняются):
(crontab -l 2>/dev/null; echo "0 3 * * * /opt/paperless-ngx/backup.sh") | crontab -
Это добавляет ежедневную задачу в 03:00.
Удалённая синхронизация
Директория экспорта и дампы базы должны покинуть сервер. Используй rsync или rclone для отправки на второй сервер. Для S3-совместимого хранилища:
rclone sync /opt/paperless-ngx/export remote:paperless-backup/export
rclone sync /opt/paperless-ngx/backups remote:paperless-backup/db-dumps
Для другого сервера по SSH:
rsync -az --delete /opt/paperless-ngx/export/ backup-server:/backups/paperless/export/
rsync -az /opt/paperless-ngx/backups/ backup-server:/backups/paperless/db-dumps/
Подробнее о стратегиях бэкапа Docker-томов — в нашем руководстве по бэкапу Docker-томов.
Как восстановить бэкап Paperless-ngx?
Восстановление требует чистой установки Paperless-ngx. Подними стек, затем импортируй.
Восстановление только базы данных (быстрее, при повреждении БД или миграции):
gunzip < /opt/paperless-ngx/backups/db-20260320.sql.gz | \
docker compose exec -T db psql -U paperless paperless
Полное восстановление из экспортёра (документы, теги, корреспонденты, всё):
docker compose exec webserver document_importer ../export
Запускай импортёр на пустой базе данных. Он воссоздаёт все метаданные и связывает файлы из директории экспорта.
Регулярно проверяй восстановление. Бэкап, который ты ни разу не восстанавливал — это не бэкап.
Как укрепить безопасность контейнеров Paperless-ngx?
Compose-файл выше уже покрывает основы: файлы секретов вместо паролей в открытом виде, привязка порта к localhost и маппинг пользователя. Вот дополнительные меры.
Убрать лишние capabilities
Добавь параметры безопасности к сервису webserver:
webserver:
# ... существующая конфигурация ...
security_opt:
- no-new-privileges:true
Это не позволяет процессу контейнера получать дополнительные привилегии через setuid-бинарники.
Установить лимиты ресурсов
Не дай вышедшему из-под контроля OCR-процессу сожрать все ресурсы сервера:
webserver:
# ... существующая конфигурация ...
deploy:
resources:
limits:
memory: 2g
cpus: "2.0"
reservations:
memory: 512m
Подробнее о лимитах ресурсов — в нашем руководстве по лимитам ресурсов Docker Compose.
Скрыть информацию о версии
Настрой reverse proxy на удаление заголовка Server. Для Nginx:
server_tokens off;
Сам Paperless-ngx не раскрывает версию в HTTP-заголовках, но reverse proxy может это делать.
Как обновить Paperless-ngx?
Скачай последние образы и пересоздай контейнеры. Образ Paperless-ngx запускает миграции базы данных автоматически при старте.
cd /opt/paperless-ngx
docker compose pull
docker compose up -d
После обновления проверь логи на предмет миграций:
docker compose logs webserver --tail 30
Ищи строки вида Applying documents.XXXX_migration_name... OK. Если миграции падают, контейнер останавливается. Проверяй примечания к релизу перед крупными обновлениями версий.
Всегда запускай скрипт бэкапа перед обновлением.
Что-то пошло не так?
Контейнер остаётся unhealthy: Проверь логи через docker compose logs <service> --tail 50. Частые причины: несовпадение пароля PostgreSQL (перегенерируй .db_password и пересоздай том базы данных), отказ соединения с Redis (broker ещё не запустился).
OCR выдаёт мусор: Неправильный язык. Проверь, что PAPERLESS_OCR_LANGUAGE соответствует твоим документам. Для многоязычных документов добавь все нужные коды языков через +.
Документы не появляются после загрузки: Проверь лог consumer:
docker compose logs webserver --tail 50 | grep -i consumer
Частая причина: проблема с правами доступа. Директория consume должна быть доступна для записи пользователю с UID 1000 (или значением USERMAP_UID):
chown -R 1000:1000 /opt/paperless-ngx/consume
Автоматическая разметка не работает: Классификатору нужно минимум ~50 вручную размеченных документов. Проверь, обучен ли классификатор:
docker compose exec webserver document_create_classifier
Дисковое пространство быстро растёт: Проверь, какие документы самые большие:
docker compose exec webserver document_sanity_checker
Также проверь режим OCR. Режим force создаёт архивные файлы значительно большего размера, чем skip.
Приём email не работает: Проверь IMAP-данные в веб-интерфейсе. Запусти ручное получение, чтобы увидеть ошибки:
docker compose exec webserver mail_fetcher
Другие руководства по self-hosting — см. наше руководство по Immich для управления фотографиями на том же стеке.
Авторское право 2026 Virtua.Cloud. Все права защищены. Данный контент является оригинальным произведением команды Virtua.Cloud. Воспроизведение, повторная публикация или распространение без письменного разрешения запрещены.
Готовы попробовать?
Разверните свой сервер за секунды. Linux, Windows или FreeBSD.
Смотреть тарифы VPS