| .. | ||
| .env.example | ||
| compose.yaml | ||
| README.md | ||
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)
scansis only an inbox. Paperless polls it every 60 s, imports each file, and deletes it from the share afterwards. The documents themselves live in./mediaon the OptiPlex.paperless-exportgets a full export every night: originals, archived PDFs and a manifest with tags, correspondents and so on.document_importercan rebuild a fresh instance from it, so this export is the backup. No extra copy of./dataor./mediais 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)
-
Two shared folders:
scansandpaperless-export. Hide them from "My Network Places", no recycle bin onscans. Every imported file would end up there, and worse: DSM restricts#recycleto admins, so Paperless's recursive watcher crashes on it withPermission denied (os error 13)(hit 2026-10-05). If#recycleexists, delete it in File Station after turning the recycle bin off. -
Two users, each with no other permissions and no app access besides SMB:
scanner: read/write onscansonly. Its password is stored in the Brother scanner.paperless: read/write onscansandpaperless-export.
Gotchas (set up 2026-10-05):
- The
usersgroup 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
usersgroup 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 outscannerandpaperless, who are both inusers.
-
Hyper Backup: add
paperless-exportto 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.scansdoesn'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
scannerpassword would then cross the network in plain text, which is tolerable only because that user can do nothing except write toscans. - 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
scannerlogin 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/Davidandscans/<partner>. Because ofCONSUMER_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.
-
sudo apt install cifs-utils -
Credentials file, readable by root only:
sudo install -m 600 /dev/null /etc/nas-paperless.cred sudoedit /etc/nas-paperless.credContents:
username=paperless password=... -
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 0uid/gid1000 is the container's user (USERMAP_UID); check thatid -uon the OptiPlex is 1000 as well. -
sudo systemctl daemon-reload && sudo systemctl restart remote-fs.target, thenls /mnt/nas/scans(should be empty, no error).
Setup
cp .env.example .env, fill in the secret key.docker compose up -d. Theproxynetwork already exists from the Vaultwarden setup.- Check the mount reaches the container:
docker compose exec webserver ls -la /usr/src/paperless/consume - 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. - Pi-hole Local DNS record:
paperless.home.staffenberger.at→192.168.30.20. - NPM proxy host:
paperless.home.staffenberger.at, schemehttp, forward topaperlessport8000(container name, as with Vaultwarden), Websockets Support on (live status of imports), wildcard certificate, Force SSL, HTTP/2. - 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:
-
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. -
Normal users
davidanddenise, both inHousehold, neither superuser. The admin account is only for administration; otherwise Denise's documents show up in my daily view. -
Subfolders
scans/Davidandscans/Denisein File Station. The printer probably doesn't create folders itself. -
Printer profiles (web interface, Scan to FTP/Network/SharePoint Profile): Profile 2
David→\\192.168.30.10\scans\David, Profile 3Denise→\\192.168.30.10\scans\Denise, both set to Network, otherwise like Profile 1 (paste thescannerlogin into cleared fields, see the Chrome autofill note above). -
Workflows (Settings → Workflows), one per person:
Field Value Trigger Consumption Started Sources Consume Folder Filter path */David/*(or*/Denise/*)Action Assignment → Owner david(ordenise) -
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. -
Test: one scan through each profile, then log in as
davidand asdeniseand 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):
- Stack in the feeder with page 1 first, scan → pages 1, 3, 5.
- Turn the stack over without re-sorting it, scan again → pages 6, 4, 2.
- 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
paperlessand 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
.envmatters../dataand./mediaare covered by the export, and./redisdatais 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
rslavepropagation 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.