Apps & Software

Paperless-ngx Self-Hosted: What It Costs to Run

Self-hosting Paperless-ngx: which of its four compose files to copy, whether a Raspberry Pi can keep up with OCR, and what a real backup has to include.

Paperless-ngx self-hosted — compose files, OCR cost, where documents live, and what a backup must include

⚡ The short version

Paperless-ngx is two containers for most people, not five. The extra two exist only to read Word and Excel files, and the third is a database you can skip. The real cost is not the container count: it is OCR time on weak hardware, and a backup that has to be an export rather than a volume copy if you ever want to restore it onto a different machine.

Open three document-management guides and you get a five-service stack, a warning about RAM, and no mention of the two things that actually bite: how long a page takes to OCR on the box you own, and what happens when you try to move the whole thing a year later.

I went to the project’s own files rather than to the guides. Everything below about self-hosting Paperless-ngx comes from the compose files, documentation and image manifests that paperless-ngx/paperless-ngx publishes, read on 17 September 2026. The latest stable tag on that date was v3.1.3.

What Happens to a Document After You Drop It In?

It gets read, indexed and left alone. That last part is worth knowing first.

You put a file into a consumption directory, or upload it through the web interface on port 8000. Paperless runs OCR over it if it is a scan or an image, extracts the text, guesses a correspondent and some tags, and makes the contents searchable. The file itself is stored untouched: the project keeps a checksum of every original and runs a scheduled sanity check against them, which is a stronger promise than most document managers make.

What it reads without help: PDF, PNG, JPEG, TIFF, GIF and WebP. Plain text goes in verbatim. Word, Excel, PowerPoint and their LibreOffice equivalents need the two optional containers, and nothing else does.

Alongside the original it usually writes a PDF/A archive version for display and search. By default it makes one for scans and image-based PDFs and skips PDFs that already carry embedded text. That is why a Paperless library is bigger on disk than the pile of files you fed it, and it is a setting rather than a law.

Which of the Four Compose Files Should You Copy?

The one that answers no to both optional questions, unless you know you need otherwise.

Paperless publishes four installation compose files, and the same application is two, three, four or five containers depending on which you download. I counted the services in all four on 17 September 2026 with this site’s own script; the full table is in the post on how many containers a self-hosted app really needs. What matters here is which question moves which number:

What you have Office documents to read? File to copy Containers
A scanner and a few thousand PDFs No docker-compose.sqlite.yml 2
Tens of thousands of documents, or several users No docker-compose.postgres.yml 3
A scanner, plus Word and Excel files Yes docker-compose.sqlite-tika.yml 4
Both of the above Yes docker-compose.postgres-tika.yml 5

The broker in every one of those is not optional and is not the database. It queues document processing behind the web request so uploading twenty scans does not block the interface, and the SQLite file ships with it too. In these files it is Valkey rather than Redis, the fork that followed Redis’ licensing change; the project says any wire-compatible broker works.

Here is the three-container version, trimmed, from the project’s PostgreSQL file:

services:
  broker:
    image: docker.io/valkey/valkey:9-alpine
    restart: unless-stopped
    volumes:
      - redisdata:/data
  db:
    image: docker.io/library/postgres:18
    restart: unless-stopped
    volumes:
      - pgdata:/var/lib/postgresql
    environment:
      POSTGRES_DB: paperless
      POSTGRES_USER: paperless
      POSTGRES_PASSWORD: paperless
  webserver:
    image: ghcr.io/paperless-ngx/paperless-ngx:latest
    restart: unless-stopped
    depends_on: [db, broker]
    ports:
      - "8000:8000"
    volumes:
      - data:/usr/src/paperless/data
      - media:/usr/src/paperless/media
      - ./export:/usr/src/paperless/export
      - ./consume:/usr/src/paperless/consume
    env_file: docker-compose.env

The project recommends PostgreSQL for new installs while the files treat SQLite as the default. Both are supported paths, so this is a real choice rather than a downgrade. If you are new to Compose, the Docker workflow for self-hosting covers what the volume and env_file lines are doing.

Will It Run on a Raspberry Pi?

A 64-bit one will. A 32-bit one has nothing to pull.

I asked the registry which architectures the image publishes rather than repeating what the guides say, and on 17 September 2026 the answer was linux/amd64 and linux/arm64, with no 32-bit ARM entry. The documentation agrees and is blunt about it: for ARMv7 it suggests upgrading to arm64 rather than working around the gap. So the question is not which Pi you own, it is which Raspberry Pi OS you installed. The Raspberry Pi self-hosting guide covers picking the 64-bit image.

The compose file headers still say "amd64, arm and arm64". The published image manifest says amd64 and arm64 only, checked 17 September 2026. Where a comment and a manifest disagree, the manifest is what Docker acts on — you find out at docker compose pull, not at runtime.

On a 64-bit Pi it runs, and the documentation says as much from having tested it on a Pi 3 B. What is slow is OCR, and only OCR: the web interface does its work in your browser and stays responsive while the queue grinds. That is a tolerable shape of slow, because nobody watches a scan process. The project publishes settings for exactly this case:

Setting What it does When to use it
PAPERLESS_OCR_PAGES=1 OCRs only the first page Most filing, where page one identifies the document
PAPERLESS_TASK_WORKERS Defaults to using all cores Lower it to leave the Pi usable during a bulk import
PAPERLESS_ARCHIVE_FILE_GENERATION=never Stops writing the PDF/A copy Tight on disk, and happy viewing originals
PAPERLESS_OCR_CLEAN=none Skips image cleanup before OCR Faster and lighter, slightly worse results
PAPERLESS_WEBSERVER_WORKERS=1 One web worker instead of several Single-user instance on 2 GB or less

The other half of that answer is free: if your scanner can OCR, let it, and Paperless reuses the text rather than redoing the work. The project recommends this ahead of any setting above.

Where Do Your Documents Actually Live?

In four Docker volumes at most, named after your project directory rather than after Paperless.

The .env file shipped beside the compose file sets COMPOSE_PROJECT_NAME=paperless, which turns the bare media and data declarations into volumes called paperless_media and paperless_data on the host. Change that line and your volume names change with it.

The four, per the project’s backup documentation:

  • paperless_media holds the documents themselves, as plain files.
  • paperless_data holds auxiliary data, including the SQLite database if you chose that file.
  • paperless_pgdata exists only if you chose PostgreSQL.
  • paperless_dbdata exists only if you chose MariaDB.

Because the originals are ordinary files, you can drag them out of the media volume and use them elsewhere. The catch is that Paperless names them by internal ID by default, so what you recover that way is your documents with unhelpful filenames. Reaching into a named volume takes a container rather than a cp, which the Docker volume backup guide walks through.

Export or Volume Copy — Which Backup Do You Need?

Both, for different failures, and the difference is whether you are restoring onto the same machine.

A volume copy restores the instance you had. It captures the database along with the documents, so it is bound to the database engine and to a compatible version of Paperless at the other end. That is the right tool for a dead disk and a rebuilt server.

The document exporter is the other one. It writes every document, its thumbnail, and a manifest.json carrying all the metadata — correspondents, tags, document types — into a folder:

docker compose exec -T webserver document_exporter ../export

The -T flag is not decoration: without it the command fails inside a cron job with a TTY error. Point it at a folder that already holds an export and it updates in place, comparing modification time and size, so incremental backups with rsync work.

An export cannot be imported into a different version of Paperless. The project states this plainly: the export contains an exact image of the database, and migrations change the layout between versions. A three-year-old export is not a three-year-old safety net. If the export is your migration plan, export near the moment you move rather than trusting an old archive.

That caveat is the reason to keep both. The exporter gives you documents with real filenames and readable metadata that survive Paperless disappearing entirely; the volume copy gives you the instance back. The backup strategy post covers where those copies go next, and the answer is not the same disk.

What Stops It Starting the First Time?

Two things, and both are in the sample files rather than in your setup.

The first is the secret key. It is required, it has no default value, and Paperless refuses to start without it. The environment file ships with the placeholder PAPERLESS_SECRET_KEY=change-me, which reads like an optional suggestion and is not one. The project documents generating a real one with a single python3 command using the secrets module.

The second is file ownership on the consumption directory. The container has to write into the folder you drop scans into, and the sample environment file carries commented-out USERMAP_UID and USERMAP_GID lines for it. Run id -u and id -g and put those numbers in; if yours are both 1000, the usual first account on a Linux box, it works untouched. There is a rootless alternative that sets user: on the webserver service instead, and the two must not be combined.

Behind a reverse proxy, set PAPERLESS_URL before you go looking for a bug. One value fills in the allowed hosts, CORS origins and CSRF trusted origins together. No trailing slash, and it cannot contain a path. Without it a proxied login fails in a way that looks like a proxy misconfiguration; the reverse proxy guide covers the half that genuinely is one.

One more, if the consumption directory sits on a network share: NFS does not support the filesystem notifications Paperless watches with, so nothing is picked up and nothing errors. The fix is a polling interval instead.

What Paperless-ngx Will Not Do for You

It will not sort out a filing habit you do not have.

Paperless indexes what you give it and guesses tags from what it has seen before. A scanned pile with no naming discipline becomes a searchable scanned pile with no naming discipline. The search is genuinely good, which is the point; it is not the same thing as a system.

It is also not a replacement for a filesystem you already understand. If your documents sit in dated folders you can navigate, Paperless buys you full-text search across their contents and costs you a stack to maintain — the same trade the self-hosted alternatives to SaaS round-up weighs for every app on it.

Two smaller honesties. Duplicates are not rejected by default as of version 3: a matching file is consumed and flagged for review, with a setting to restore the old refusing behaviour. And the AI features people ask about, document chat and similar-document retrieval, are off unless you switch them on and point them at a backend.

✅ Worth running if

  • You have paper arriving and a scanner already
  • You want to search inside documents, not just find them by name
  • You are comfortable that a backup is now two commands rather than one

❌ Skip it if

  • Your documents are born-digital and already well organised
  • You want it to tidy an existing mess for you
  • Your only hardware is a 32-bit Pi, where there is no image to run

Frequently Asked Questions About Self-Hosting Paperless-ngx

How many containers does Paperless-ngx need?

Two, three, four or five, and you choose which by picking one of the four compose files the project publishes. Counted from those files on 17 September 2026: SQLite is broker and webserver, PostgreSQL adds a database, and the two Tika variants add Gotenberg and Apache Tika on top. The Tika pair exist only to read Office documents. If you scan paper and save PDFs, the two-container file is the whole app.

Can a Raspberry Pi run Paperless-ngx?

A 64-bit one, yes. The published image index lists linux/amd64 and linux/arm64 and nothing else, checked 17 September 2026, so a 32-bit Raspberry Pi OS install has no image to pull and the project suggests moving to arm64 rather than working around it. On a 64-bit Pi the web interface is responsive and OCR is the slow part, which is a queue problem rather than a blocker.

Where does Paperless-ngx store my documents?

In Docker volumes, as ordinary files. The originals live in the media volume, auxiliary data and the SQLite database in the data volume, and PostgreSQL in its own volume if you chose that file. Paperless never modifies an original, keeps a checksum of each one and runs a scheduled sanity check against them, so the files you put in are the files you can take out.

Is copying the Docker volumes enough to back up Paperless-ngx?

It restores, but only onto the same setup. A volume copy is an image of the database as well as the documents, so it needs the same database engine and a compatible Paperless version at the other end. The document exporter writes documents, thumbnails and a manifest of all the metadata into a folder instead, and that is the copy you can carry to a new machine.

Why does Paperless-ngx refuse to start?

The commonest reason on a first run is the secret key. It is required, it has no default value, and Paperless will not start without it, so the placeholder in the sample environment file has to be replaced before the first start rather than after. The project documents generating one with a short Python command. The second commonest reason is a consumption directory the container cannot write to.

Does Paperless-ngx send my documents anywhere?

Not unless you turn something on. The tag and correspondent suggestions use a local machine-learning model that sends nothing out. The newer LLM features, which cover document chat and similar-document retrieval, are disabled by default and only send content once you enable them and configure a backend, which can itself be a local one. Checked against the project documentation on 17 September 2026.

Product links on this site are plain links. We earn nothing from them — see our disclosure policy.