Every household has the drawer. Tax letters, warranty cards, insurance renewals, and a medical bill from three years ago that may or may not still matter. Finding any single item means flipping through everything, and the one time you need it fast, it has gone missing.
Paperless-ngx fixes that without sending a single page to someone else’s cloud.
It is a free, open-source document management system that runs on your own hardware. You feed it scans or PDFs, it runs optical character recognition on every page, and each word becomes searchable from a browser. Over time it also learns to apply tags, identify senders, and file documents by type. This guide covers installing it with Docker Compose, the settings worth getting right on day one, and the intake and sorting habits that keep the archive useful.

Install Paperless-ngx with Docker Compose
You need a machine that stays on, such as a small home server, a NAS that runs containers, or a spare mini PC. OCR is CPU-hungry, so a couple of cores and a few gigabytes of RAM make large imports far less painful. Install Docker and the Docker Compose plugin first, then pick a directory for the project. The Paperless-ngx team ships an install script that generates the compose file and environment file for you and asks a handful of questions along the way. Run it with bash -c “$(curl –location –silent –show-error https://raw.githubusercontent.com/paperless-ngx/paperless-ngx/main/install-paperless-ngx.sh)” and answer the prompts. As with any script piped into a shell, it is worth opening the URL in a browser and reading it first.
The prompts map to decisions that are annoying to change later, so it pays to know what each one does:
- Port: the web interface defaults to 8000, which is fine unless another service already uses it.
- URL: leave it blank for local use, or enter your full address if the instance sits behind a reverse proxy.
- Time zone: this affects how dates are interpreted on imported documents, so set it correctly.
- OCR language: use a three-letter code such as eng, or combine several with a plus sign, for example eng+deu, if your paperwork mixes languages.
- Database: PostgreSQL is the sensible default for a long-lived archive. SQLite and MariaDB are also supported.
- Tika and Gotenberg: say yes if you want Word files, spreadsheets, and emails parsed alongside PDFs and images.
- Folders: choose where the consume, export, media, and data directories live.
Once the script finishes, move into the project directory and run docker compose pull followed by docker compose up -d. The first start takes a minute while the database initializes and the containers settle. Open the server’s address on port 8000 in a browser and sign in with the admin account you created during setup. If you skipped that step, docker compose run –rm webserver createsuperuser creates one.
Open the generated environment file before you import anything. A few variables deserve attention: PAPERLESS_OCR_LANGUAGE, PAPERLESS_TIME_ZONE, and PAPERLESS_FILENAME_FORMAT, which controls how files are named on disk. Set a long, random PAPERLESS_SECRET_KEY as well. If your consume folder lives on a network share where file-change notifications are unreliable, add PAPERLESS_CONSUMER_POLLING with a value in seconds so the watcher checks on a schedule instead.

Feed it, tag it, find it
Paperless-ngx accepts documents in several ways, and the best one depends on how much paper you handle. The simplest is drag and drop in the web interface. The most useful for ongoing paperwork is the consume folder: point a network scanner’s “scan to folder” function at it, and every sheet that comes off the glass is picked up, OCR’d, and filed automatically. The built-in mail fetcher covers digital paperwork, since it can watch an inbox and import attachments that match rules you define. For scans, 300 dpi is a reasonable balance between legible OCR and file size. Higher resolutions rarely improve recognition on ordinary printed text and fill your disk faster.
Organization rests on four concepts: tags, correspondents, document types, and storage paths. A correspondent is the sender, such as your utility company. A document type is the kind of thing it is, such as an invoice or a contract. Tags cut across both, covering things like “tax-2024” or “to-pay.” Each of these has a matching algorithm. You can use plain keyword rules like “any word” and “exact,” or set it to Auto, which trains a classifier on documents you have already labeled. The classifier is only as good as its teachers, so label your first batch by hand, and use an “inbox” tag on new arrivals so nothing sits unreviewed.
Search is where the effort pays off. The search bar queries the full text of every page, and it also understands field-based queries, so you can narrow results by correspondent, tag, or date instead of scrolling through hits. Backups deserve the same attention as intake. Run docker compose exec webserver document_exporter ../export on a schedule and copy the output somewhere off the machine. If you want to reach the archive from outside your home, avoid exposing port 8000 to the internet. A private mesh such as the one in this Netbird setup guide lets your phone or laptop connect to the server as if it were on your home network.

Before you shred anything
Keep the originals of anything with legal weight, such as birth certificates, property deeds, and passports, because a scan in a database is a convenience and not a substitute. For everything else, run the exporter once, restore the export onto a test machine, and confirm that a search for a document from 2019 returns the right page. Until that works, the shredder stays off.





