# Paperless-ngx Document archive with OCR. Runs on the OptiPlex homeserver (`192.168.30.20`) in `~/paperless`, reachable only as `https://paperless.home.staffenberger.at`, at home or through the WireGuard VPN. ## How the pieces fit ``` Brother scanner (IoT) ──SMB──▶ NAS share `scans` ──SMB mount──▶ Paperless consume │ NAS share `paperless-export` ◀──nightly document_exporter────────────┘ │ └──▶ Hyper Backup to the USB drive (manual, every two weeks) ``` - **`scans`** is only an inbox. Paperless polls it every 60 s, imports each file, and **deletes it from the share** afterwards. The documents themselves live in `./media` on the OptiPlex. - **`paperless-export`** gets a full export every night: originals, archived PDFs and a manifest with tags, correspondents and so on. `document_importer` can rebuild a fresh instance from it, so this export is the backup. No extra copy of `./data` or `./media` is needed. - The database (SQLite) stays on the local disk. A database on a network share is asking for corruption. **Sorting** works through matching rules on tags, correspondents and document types. The default mode, *Auto*, learns from the documents you've already assigned. So at first you assign by hand; after a few dozen documents it starts suggesting assignments. It doesn't sort anything correctly out of the box. ## NAS (DSM) 1. **Two shared folders:** `scans` and `paperless-export`. Hide them from "My Network Places", **no recycle bin on `scans`**. Every imported file would end up there, and worse: DSM restricts `#recycle` to admins, so Paperless's recursive watcher crashes on it with `Permission denied (os error 13)` (hit 2026-10-05). If `#recycle` exists, delete it in File Station after turning the recycle bin off. 2. **Two users**, each with no other permissions and no app access besides SMB: - `scanner`: read/write on `scans` only. Its password is stored in the Brother scanner. - `paperless`: read/write on `scans` and `paperless-export`. Gotchas (set up 2026-10-05): - The `users` group allows almost every application by default, so new users start with full app access. Set **Deny** on everything except **SMB** in each user's Applications tab, and check the Preview column. Don't deny SMB too, or the user can't log in at all. - In the shared folder's permissions (Local groups view), leave the `users` group with **no box ticked**. Its Preview then shows "No Access", which only means "grants nothing". Ticking **No access** would be an explicit deny, which always wins in DSM, and would lock out `scanner` and `paperless`, who are both in `users`. 3. **Hyper Backup:** add `paperless-export` to the existing task's sources. New shared folders are **not** picked up automatically, even though "all shared folders" was selected when the task was created. `scans` doesn't need backing up. ## Scanner (Brother) → NAS The scanner sits on IoT, and IoT Outwards (`IoT → !IoT` deny) blocks it from the NAS. It needs one narrow exception **above IoT Outwards** (in place since 2026-10-05 as "Printer to NAS SMB"): | Policy | Protocol | Source | Destination | |---|---|---|---| | Allow | TCP | IP group: scanner's reserved IP | IP-Port group: `192.168.30.10` port `445` | Groups are under Settings → Profiles → Groups; the rule goes in the Gateway ACL, LAN→LAN. (Check the menu paths in Controller 6.3.) Then in the scanner's web interface (Web Based Management): Scan → Scan to FTP/SFTP/Network/SharePoint → set a profile to **Network**, host `192.168.30.10`, store directory `scans`, user `scanner`, authentication NTLMv2, file type PDF, 300 dpi. Exact menu names depend on the model. The scanner is a **Brother MFC-L3750CDW**. **Working since 2026-10-05** over SMB with DSM's default minimum of SMB2: Profile 1 = Network, `\\192.168.30.10\scans`, NTLMv2, user `scanner`, firmware MAIN `ZJ2606120536` (already the latest). - **No SFTP on this model** (the menu is "Scan to FTP/Network/SharePoint"). If SMB ever breaks, **don't turn SMB1 on in DSM**. Fallback: plain FTP, port 21 + passive range in the ACL. The `scanner` password would then cross the network in plain text, which is tolerable only because that user can do nothing except write to `scans`. - **Chrome autofill on the printer's web interface:** Chrome filled its saved printer login into the profile's username/password fields and then reported a "breached password" on Submit. That was most likely the old default admin password. Paste the `scanner` login from Enpass into cleared fields, and don't let Chrome save the printer's passwords. - Time on the scanner (SNTP) has to be right, or authentication can fail. - Optional: one profile per person, saving into `scans/David` and `scans/`. Because of `CONSUMER_SUBDIRS_AS_TAGS`, the documents then come in tagged with the person's name. ## OptiPlex The shares are mounted on the host with **systemd automount**, not at boot: after a power cut the OptiPlex comes up long before the NAS, and a normal mount would just fail and stay that way. The automount connects on first access and tries again later if the NAS isn't up yet. 1. `sudo apt install cifs-utils` 2. Credentials file, readable by root only: ```bash sudo install -m 600 /dev/null /etc/nas-paperless.cred sudoedit /etc/nas-paperless.cred ``` Contents: ``` username=paperless password=... ``` 3. `sudo mkdir -p /mnt/nas/scans /mnt/nas/paperless-export`, then add to `/etc/fstab`: ``` //192.168.30.10/scans /mnt/nas/scans cifs credentials=/etc/nas-paperless.cred,uid=1000,gid=1000,file_mode=0660,dir_mode=0770,vers=3.0,_netdev,nofail,x-systemd.automount,x-systemd.idle-timeout=0 0 0 //192.168.30.10/paperless-export /mnt/nas/paperless-export cifs credentials=/etc/nas-paperless.cred,uid=1000,gid=1000,file_mode=0660,dir_mode=0770,vers=3.0,_netdev,nofail,x-systemd.automount,x-systemd.idle-timeout=0 0 0 ``` `uid`/`gid` 1000 is the container's user (`USERMAP_UID`); check that `id -u` on the OptiPlex is 1000 as well. 4. `sudo systemctl daemon-reload && sudo systemctl restart remote-fs.target`, then `ls /mnt/nas/scans` (should be empty, no error). ## Setup 1. `cp .env.example .env`, fill in the secret key. 2. `docker compose up -d`. The `proxy` network already exists from the Vaultwarden setup. 3. Check the mount reaches the container: `docker compose exec webserver ls -la /usr/src/paperless/consume` 4. Admin user (the password stays out of the compose file): `docker compose exec webserver createsuperuser`. Later, make a normal user for each person in the web UI. 5. **Pi-hole Local DNS record:** `paperless.home.staffenberger.at` → `192.168.30.20`. 6. **NPM proxy host:** `paperless.home.staffenberger.at`, scheme `http`, forward to `paperless` port `8000` (container name, as with Vaultwarden), **Websockets Support on** (live status of imports), wildcard certificate, Force SSL, HTTP/2. 7. Scan one test page and check it shows up in Paperless within a minute and disappears from `scans`. Steps 1–7 done 2026-10-05. ## Users and separating documents Each person scans with their own profile on the printer. The file lands in their subfolder, and a workflow makes them the owner, so only they see it. Scans from the root folder (profile `NAS`) get no owner and are visible to both of us. ``` Printer profile Folder on the NAS Owner in Paperless NAS scans/ none → shared David scans/David/ david Denise scans/Denise/ denise ``` **Not a security boundary:** the superuser sees everything, and so does anyone with access to the OptiPlex disk or the export on the NAS. It keeps daily use tidy and private between the two of us, nothing more. Steps: 1. **Group `Household`** (Settings → Users & Groups → Groups). Global permissions View/Add/Change/Delete on: Documents, Tags, Correspondents, Document types, Storage paths, Saved views, Custom fields, Notes, Share links, UI settings. **Not**: Users, Groups, Workflows, Mail accounts/rules, App config, Admin. 2. **Normal users `david` and `denise`**, both in `Household`, neither superuser. The admin account is only for administration; otherwise Denise's documents show up in my daily view. 3. **Subfolders** `scans/David` and `scans/Denise` in File Station. The printer probably doesn't create folders itself. 4. **Printer profiles** (web interface, Scan to FTP/Network/SharePoint Profile): Profile 2 `David` → `\\192.168.30.10\scans\David`, Profile 3 `Denise` → `\\192.168.30.10\scans\Denise`, both set to Network, otherwise like Profile 1 (paste the `scanner` login into cleared fields, see the Chrome autofill note above). 5. **Workflows** (Settings → Workflows), one per person: | Field | Value | |---|---| | Trigger | Consumption Started | | Sources | Consume Folder | | Filter path | `*/David/*` (or `*/Denise/*`) | | Action | Assignment → Owner `david` (or `denise`) | 6. **Default permissions:** each user, under Settings → Permissions, sets Default View/Edit to the group `Household`. Otherwise new tags and correspondents belong only to whoever created them, and the other person doesn't see them, even on shared documents. 7. **Test:** one scan through each profile, then log in as `david` and as `denise` and check who sees what. ### Double-sided documents The MFC-L3750CDW's feeder scans **one side only**. Paperless merges two scans into one document (`PAPERLESS_CONSUMER_ENABLE_COLLATE_DOUBLE_SIDED`): 1. Stack in the feeder with page 1 first, scan → pages 1, 3, 5. 2. **Turn the stack over** without re-sorting it, scan again → pages 6, 4, 2. 3. Paperless interleaves them into 1–6. The second scan must arrive **within 30 minutes**, otherwise it counts as a new first half. Needs a `double-sided` subfolder (Paperless doesn't create it): `scans/David/double-sided`, `scans/Denise/double-sided`, and `scans/double-sided` for shared documents. One printer profile each, e.g. `David 2-sided` → `\\192.168.30.10\scans\David\double-sided`. Paperless treats `David/double-sided/` like `David/`. `double-sided` doesn't become a tag. **Still to test:** whether the owner workflow (`*/David/*`) also applies to the merged document. If the two scans get mixed up (a single-sided document scanned into the `double-sided` profile), the next scan gets merged with the wrong one. So use the double-sided profile only for genuinely double-sided documents. The subfolders also become tags (`David`, `Denise`) through `PAPERLESS_CONSUMER_SUBDIRS_AS_TAGS`. That duplicates the owner, but is handy for filtering. Drop the setting if it's in the way. ## Backups Nightly export, as a crontab entry for `david` on the OptiPlex (`crontab -e`): ``` 30 2 * * * cd ~/paperless && docker compose exec -T webserver document_exporter ../export --delete --no-progress-bar >> ~/paperless/export.log 2>&1 ``` `--delete` removes files from the export that no longer exist in Paperless, so the export mirrors the current state. Older versions are in Hyper Backup. Later this moves into Ansible as a systemd timer. - The export is **not encrypted**. It's on the NAS (Servers VLAN, share only readable by `paperless` and admins), and Hyper Backup encrypts it on the USB drive. - **Test a restore** once: a throwaway instance, then `document_importer ../export`. - Off the OptiPlex, only `.env` matters. `./data` and `./media` are covered by the export, and `./redisdata` is disposable. ## Notes - Things to verify on first setup: after rebooting the OptiPlex while the NAS is off, the container should start, and importing should resume on its own once the NAS is back. If the mount doesn't show up inside the container, check the `rslave` propagation in the compose file first. - The image is pinned; check the release notes before bumping. 3.x removed some database settings, which don't matter with SQLite. - Office documents and emails need Tika + Gotenberg as extra containers. Not needed for scans, so add them only if mail import becomes interesting.