Самостоятельный хостинг 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 для управления фотографиями на том же стеке.
Готовы попробовать?
Разверните свой сервер за секунды. Linux, Windows или FreeBSD. →