Cards / paperless-ngx

App card

paperless-ngx

Fit 3/4

Document Management · passed 4 Nov 2026

  • Members only Only people in your organisation get in.
  • Keeps it safe 3 volumes of your data, backed up and checked after a move.
  • Keeps secrets Its passwords are made on your machine, seen by nobody.

Paperless-ngx, scan, index and search your paper documents, behind your Edgible sign-in

Memory
3 GB
Disk
6 GB
Runs on
Intel · ARM

No steward yet · GPL-3.0-onlyEdgible cards 52/53

passed 2026-11-04, Edgible 1.4.29Added 2 November 2026License GPL-3.0-onlyNo stewardApp home page (opens in a new tab)Source on GitHub (opens in a new tab)

Apps

AppWhatWho can reach itPlace
paperless-ngxPaperless-ngx web interface and API, for the people in your organisationorg loginpaperless-ngx

Machine

A place is one serving device. Minimum recommended for each:

PlaceMemoryDiskArchitectureGPU
paperless-ngx3 GB6 GBamd64, arm64none

First start

The first start downloads the app's images: about 941 MB, a few minutes on a typical home connection. That time is the download from the app's registry, not Edgible, and it happens once: later starts and upgrades reuse the images and fetch only what changed.

What it keeps

VolumeWhat it is
paperless-ngx-datarebuilt by the app from the rest, such as a search index
paperless-ngx-mediayours alone: backed up, and checked after a restore or a move
paperless-ngx-consumesafe to lose, such as thumbnails or downloads
paperless-ngx-db-datayours alone: backed up, and checked after a restore or a move
paperless-ngx-secretsyours alone: backed up, and checked after a restore or a move

After a restore or a move, a quick count shows the data arrived, with nothing read but numbers and dates.

What it protects

Self-hosting fit

3 of 4 checks passed. Each is a fact about the app, not an opinion: how they are decided (opens in a new tab).

Needs it answers

Setting it up by hand? Install Edgible from edgible.com (opens in a new tab), then follow the steps below.

Why

Invoices, letters, contracts and statements pile up on paper and in mail attachments, and are hard to find when you need them. Paperless-ngx (opens in a new tab) reads the text of each scan or PDF (OCR), tags and files it, and makes the whole archive searchable, on a machine you own instead of a cloud scanning service.

What

One app, paperless-ngx, on org. A document archive is private, and a person uses it in a browser, so only members of your Edgible organisation reach it, and Paperless's own login still applies after that. The trade-off is that Paperless's phone apps and API clients cannot get past the Edgible sign-in; upload from the web interface, or from a scanner that writes to a folder on the machine. Four services run it: paperless-ngx, paperless-ngx-db, a Postgres, paperless-ngx-redis, a queue, and paperless-ngx-secrets, which makes the passwords and exits. Paperless makes the admin itself at its first start, with a password made on the machine, so there is no setup page to leave open. Inside the app, give each person their own user and set who sees which documents with its permissions and groups; for documents with client, patient or financial data, keep it on org, use those permissions, keep encrypted backups, and follow your profession's retention rules.

Original and archived documents live in the volume paperless-ngx-media, the database in paperless-ngx-db-data; back those two up together. paperless-ngx-data holds the search index, which Paperless rebuilds, and paperless-ngx-consume is a drop folder. Minimum recommended for the place paperless-ngx: 3 GB of memory and 6 GB of disk, on an arm64 or amd64 machine, with no GPU.

The Compose file is docker-compose.yml (opens in a new tab), the settings card.env (opens in a new tab), the card card.yml (opens in a new tab).

How

Five steps. Edit card.env (opens in a new tab) before you start.

1. Fetch

mkdir -p paperless-ngx
curl -fsSL https://github.com/edgible-org/cards/archive/refs/heads/main.tar.gz \
  | tar -xz --strip-components=2 -C paperless-ngx cards-main/paperless-ngx

2. Edit card.env

Set DEVICE to a name edgible device list prints, PAPERLESS_NGX_TIME_ZONE to yours, and PAPERLESS_NGX_OCR_LANGUAGE to the language of your documents. There are no passwords to fill: Start makes them on the machine.

nano paperless-ngx/card.env

3. Check

curl -fsSLo check-env.py https://raw.githubusercontent.com/edgible-org/card-kit/main/check-env.py
python3 check-env.py paperless-ngx

It moves a taken port, as lines to paste. Run it again until it says no conflicts.

4. Start

docker compose --env-file paperless-ngx/card.env -f paperless-ngx/docker-compose.yml pull
docker compose --env-file paperless-ngx/card.env -f paperless-ngx/docker-compose.yml up -d --wait
docker compose --env-file paperless-ngx/card.env -f paperless-ngx/docker-compose.yml ps

The first start downloads the app's images from the registries named in the Compose file, which takes longer for a larger app. pull does that download on its own, so you can see it. The time is the download, not Edgible, and it happens once: later starts and upgrades reuse the images on the machine and fetch only what changed. --wait returns when each service is running, and healthy when it has a healthcheck. The admin is made at this first start, by Paperless, which can take a minute after the services show healthy.

5. Publish

set -euo pipefail
set -a
. paperless-ngx/card.env
set +a
device_id=$(edgible device list --json | jq -er --arg name "$DEVICE" '
  map(select(.name == $name))
  | if length == 1 then .[0].id
    else error("need exactly one device named " + $name + " (" + (map(.status + " " + .id) | join(", ")) + ")")
    end
')
edgible app create existing \
  --non-interactive \
  --name paperless-ngx \
  --port "$PAPERLESS_NGX_PORT" \
  --protocol https \
  --auth-modes org \
  --device-id "$device_id"
edgible app list

Without Edgible: only Publish is Edgible's. The app listens on 127.0.0.1 at the port in card.env, so any reverse proxy or tunnel on the machine, such as Caddy, nginx, Cloudflare Tunnel or Tailscale, can publish it instead, and sign-in is then that tool's to provide. Every other step stays the same.

Verify

paperless-ngx uses org.

curl -sS -o /dev/null -w '%{http_code} %{redirect_url}\n' "https://<paperless-ngx hostname>"

That prints 302 and an edgible.com/application-access/ address, so the org sign-in is in front. That redirects to the Edgible sign-in, so nobody outside your organisation reaches the app. After you sign in to Edgible, sign in to Paperless as PAPERLESS_NGX_ADMIN_USER with the password the card made; see it with docker compose --env-file paperless-ngx/card.env -f paperless-ngx/docker-compose.yml run --rm --no-deps paperless-ngx-secrets show PAPERLESS_NGX_ADMIN_PASSWORD. Change it under your profile after.

The rest of the setup is in the Paperless-ngx docs (opens in a new tab).

Tear down

Four steps, in this order. Step 1 runs wherever edgible is logged in. Steps 2 to 4 run on the machine that runs the containers. Steps 2 and 3 read card.env, so keep it until step 4.

1. Unpublish

edgible app delete paperless-ngx --yes

2. Stop

docker compose --env-file paperless-ngx/card.env -f paperless-ngx/docker-compose.yml down

3. Delete the data

Skip this step to keep the data. The loop copies each volume to a .tgz file in this directory first.

for volume in $(docker volume ls -q --filter label=com.docker.compose.project=paperless-ngx); do
  docker run --rm -v "$volume:/data:ro" -v "$PWD:/backup" alpine tar -czf "/backup/$volume.tgz" -C /data .
done
docker compose --env-file paperless-ngx/card.env -f paperless-ngx/docker-compose.yml down --volumes

4. Remove the card

rm -rf paperless-ngx