Skip to content

Paperless-ngx — Setup

Self-hosted document management system with OCR, full-text search, and auto-classification. Runs as a Docker Compose stack (Paperless + PostgreSQL + Redis) on a dedicated Debian LXC (124). OIDC via PocketID. Document files stored on urahara, DB and search index on heavy-pool SSD.

Infrastructure

Host LXC ID Internal External CPU RAM Disk
Debian LXC 124 192.168.1.124:8000 https://paperless.eva-00.network 2 cores 2 GiB 16 GiB

Storage Layout

Path Pool Type Purpose
/opt/paperless/database/ heavy-pool (SSD) PostgreSQL data Fast random I/O for queries
/opt/paperless/data/ heavy-pool (SSD) Search index + classification models Fast reads for snappy search
/opt/paperless/redis/ heavy-pool (SSD) Redis persistence Task queue state
/mnt/paperless/media/ urahara (HDD) Original + archived documents Write-once bulk storage
/opt/paperless/consume/ heavy-pool (SSD) Ingestion directory Temporary — files move to media after processing
/opt/paperless/export/ heavy-pool (SSD) Document export directory On-demand exports

Bind mount: /mnt/pve/urahara/paperless/media/mnt/paperless/media

Observability

Logs

Container logs are collected via Grafana Alloy Docker discovery and shipped to Loki.

Query Purpose
{container="paperless"} Paperless-ngx app logs
{container="paperless-postgres"} PostgreSQL logs
{container="paperless-redis"} Redis logs
{container=~"paperless.*"} \|= "error" All errors
{container="paperless"} \|= "ocr" OCR processing

Access: Grafana → Explore → Loki → Enter query

Metrics

Paperless-ngx does not export Prometheus metrics by default. Use Loki logs to diagnose issues.

IaC

Artifact Path
Playbook ansible/playbooks/paperless.yml
Workflow .forgejo/workflows/paperless.yml
Docker Compose services/paperless/docker-compose.yml
Caddy entry services/caddy/Caddyfilepaperless.eva-00.network
Glance entry services/glance/glance.yml → Knowledge section
Gatus entry services/gatus/config.yaml → Paperless-ngx endpoint

The playbook manages the full lifecycle:

  1. Provisions LXC 124 on Proxmox (if not exists)
  2. Installs Docker
  3. Fetches secrets from Vault
  4. Creates directories (/opt/paperless/{data,database,redis,export,consume})
  5. Deploys Docker Compose stack (Paperless + PostgreSQL + Redis)
  6. Auto-creates superuser via PAPERLESS_ADMIN_USER env var (first run only)
  7. SSO via PocketID OIDC — internal login disabled

No first-run UI wizard. Everything is configured via environment variables.

Auth

Component Details
OIDC Provider PocketID (auth.eva-00.network)
Method Native django-allauth (no oauth2-proxy sidecar)
Callback URL https://paperless.eva-00.network/accounts/oidc/pocketid/login/callback/
Auth mode OIDC-only (PAPERLESS_DISABLE_REGULAR_LOGIN=true)
Auto-redirect Enabled (PAPERLESS_REDIRECT_LOGIN_TO_SSO=true)

PocketID Setup

Create an OIDC client in PocketID:

Field Value
Name paperless
Redirect URI https://paperless.eva-00.network/accounts/oidc/pocketid/login/callback/

Store the client ID and secret in Vault at secret/paperless.

Secrets

Vault path: secret/data/paperless

Key Purpose
secret_key Django secret key for session signing
db_password PostgreSQL password
admin_user Superuser username (used on first run)
admin_password Superuser password (used on first run)
pocketid_client_id OIDC client ID
pocketid_client_secret OIDC client secret

Seeding Vault

# Via vault-write workflow or direct API:
vault kv put secret/paperless \
  secret_key="$(openssl rand -hex 32)" \
  db_password="$(openssl rand -hex 16)" \
  admin_user="claude" \
  admin_password="$(openssl rand -hex 16)" \
  pocketid_client_id="<from PocketID>" \
  pocketid_client_secret="<from PocketID>"

Containers

Container Image Purpose
paperless ghcr.io/paperless-ngx/paperless-ngx:2.16 Web app + OCR + consumer
paperless-postgres postgres:16-alpine Document metadata database
paperless-redis redis:7-alpine Task queue broker

Document Permissions & Sharing

Paperless-ngx has per-document permissions. Each document has an owner (the uploader) plus optional view/edit grants.

Sharing a document

Open a document → Permissions tab:

Field Purpose
Owner Full control (only one user)
View users / groups Read-only access
Edit users / groups Can modify metadata, tags, etc.

Bulk permissions

Select multiple documents from the list → use the bulk edit toolbar to set permissions on all at once.

Default permissions

Each user can configure defaults under Settings → Permissions:

Setting Effect
Default owner Auto-set on new uploads (usually self)
Default view users/groups Auto-grant view access on every upload
Default edit users/groups Auto-grant edit access on every upload

Example: set milton's default view users to include holo, so holo can always see milton's uploads without manual sharing.

Bot account (claude)

The claude bot user (used by Paperless-AI) has default_owner: None, so AI-created tags, correspondents, and document types are public — visible to all users. Documents keep their original owner.

AI Integration

Paperless-ngx can be extended with local AI via companion containers. See the Paperless AI Setup Guide for connecting to Ollama on LXC 107.