https://github.com/hensing/scan-to-paperless
A secure SMB bridge for hardware scanners to automatically upload documents to Paperless-ngx. Features multi-arch support (x86/ARM), non-root execution, and auto-archiving.
https://github.com/hensing/scan-to-paperless
alpine-linux automation digitization dms docker inotify paperless-ngx raspberry-pi samba scan-to-paperless scanner scansnap self-hosted smb-shares
Last synced: about 1 month ago
JSON representation
A secure SMB bridge for hardware scanners to automatically upload documents to Paperless-ngx. Features multi-arch support (x86/ARM), non-root execution, and auto-archiving.
- Host: GitHub
- URL: https://github.com/hensing/scan-to-paperless
- Owner: hensing
- Created: 2025-12-13T16:47:13.000Z (7 months ago)
- Default Branch: main
- Last Pushed: 2026-03-25T15:40:51.000Z (3 months ago)
- Last Synced: 2026-04-26T02:10:17.356Z (2 months ago)
- Topics: alpine-linux, automation, digitization, dms, docker, inotify, paperless-ngx, raspberry-pi, samba, scan-to-paperless, scanner, scansnap, self-hosted, smb-shares
- Language: Shell
- Homepage:
- Size: 18.6 KB
- Stars: 1
- Watchers: 0
- Forks: 0
- Open Issues: 0
-
Metadata Files:
- Readme: README.md
Awesome Lists containing this project
README
# ๐ Scan to Paperless Bridge
[](https://github.com/hensing/scan-to-paperless/actions/workflows/docker-publish.yml)


**Author:** Dr. Henning Dickten ([@hensing](https://github.com/hensing))
A lightweight, secure, and Dockerized bridge designed for **Raspberry Pi** and generic Linux servers. It provides a Samba (SMB) share for hardware document scanners.
Once a scan is saved to the share, this container detects the completed file, uploads it directly to **Paperless-ngx** via API, and optionally archives or cleans up the local file.
Supports both **single-user** (simple env var config) and **multi-user** mode (one share and API key per person).
---
### ๐ How it works
**Single-user mode**
```mermaid
graph LR
A[๐จ๏ธ Hardware Scanner] -- SMB Port 445 --> B(๐ /data/inbox)
B --> C[๐ณ Container Watcher]
C -- API Token --> D[๐ Paperless-NGX]
C -- Move/Delete --> E(๐ฆ /data/archive)
```
**Multi-user mode**
```mermaid
graph TD
SCAN[๐จ๏ธ Hardware Scanner]
subgraph alice [Alice]
direction TB
AI(๐ alice_scans)
AW[๐ณ Watcher]
AA(๐ฆ archive)
AI --> AW --> AA
end
subgraph bob [Bob]
direction TB
BI(๐ bob_docs)
BW[๐ณ Watcher]
BA(๐ฆ archive)
BI --> BW --> BA
end
PL[๐ Paperless-NGX]
SCAN -- SMB: alice_scans --> AI
SCAN -- SMB: bob_docs --> BI
AW -- Alice's API Key --> PL
BW -- Bob's API Key --> PL
```
## โจ Features
- **๐ Multi-Arch Support:** Optimized for `linux/amd64` and `linux/arm64` (Raspberry Pi).
- **๐ฅ Multi-User Support:** Each user gets their own Samba share, SMB credentials, and Paperless-NGX API key.
- **๐ Secure by Default:** Binds to privileged SMB port 445 but drops privileges to run as a non-root user (configurable `PUID`/`PGID`).
- **๐ Samba Integration:** Built-in SMB server compliant with modern scanners.
- **โก Smart Detection:** Uses `inotify` to detect `close_write` events (prevents processing incomplete files).
- **๐ท๏ธ Auto-Tagging:** Automatically apply tags to uploaded documents โ configurable per user in multi-user mode.
- **๐งน Auto-Cleanup:** Options to archive or delete files after successful upload.
- **๐ก๏ธ SSL Support:** Full support for HTTPS and self-signed certificates.
## ๐ Recommended Workflow
This tool works best as part of a modern document management ecosystem. We highly recommend checking out:
* **[Paperless-ngx Documentation](https://docs.paperless-ngx.com/)**: The official documentation for the backend system.
* **[Paperless-GPT](https://github.com/icereed/paperless-gpt)**: An amazing tool to add AI-powered analysis, tagging, and renaming to your documents after they have been uploaded.
## ๐ Quick Start
### Single-User Mode
#### 1. Configuration
Create your `.env` file based on the example:
```bash
cp .env.example .env
```
**Minimal `.env` example:**
```dotenv
PAPERLESS_URL=https://paperless.local:8000
PAPERLESS_API_KEY=your-super-secret-token
SMB_USER=scanner
SMB_PASSWORD=scan123
PUID=1000
PGID=1000
```
#### 2. Docker Compose
Create a `docker-compose.yml` (or use the one provided):
```yaml
services:
scan-to-paperless:
image: ghcr.io/hensing/scan-to-paperless:latest
container_name: scan-to-paperless
restart: unless-stopped
ports:
- "445:445"
env_file:
- .env
volumes:
- ./data:/data
- ./config:/config:ro
```
Start the container:
```bash
docker compose up -d
```
#### 3. Scanner Setup
Configure your physical scanner (Brother, Canon, HP, etc.) with these settings:
* **Protocol:** SMB / CIFS
* **Server:** IP of your Docker host
* **Port:** 445
* **Share Name:** `scanner` (default)
* **Username:** `scanner` (default)
* **Password:** `scan123` (default)
---
### ๐ฅ Multi-User Mode
Multi-user mode activates automatically when `./config/users.conf` exists. Each user gets an isolated Samba share and uploads to Paperless with their own API key.
#### 1. Create the user config
```bash
mkdir -p config
cp config/users.conf.example config/users.conf
```
Edit `config/users.conf` โ one user per line, colon-separated:
```
# smb_user:smb_password:smb_share:paperless_api_key:paperless_tags(optional)
alice:secretpassword1:alice_scans:paperless-api-token-alice:scanned,alice
bob:secretpassword2:bob_docs:paperless-api-token-bob:scanned,bob
```
#### 2. Set global settings in `.env`
Only `PAPERLESS_URL` and optional processing settings are needed. The `SMB_*` and `PAPERLESS_API_KEY` variables are ignored in multi-user mode.
```dotenv
PAPERLESS_URL=https://paperless.local:8000
PUID=1000
PGID=1000
```
#### 3. Start the container
```bash
docker compose up -d
```
Each user's files land in `/data//inbox` and are archived to `/data//archive`.
> **Upgrading from single-user:** No changes required. Single-user mode is auto-detected when `users.conf` is absent.
---
## โ๏ธ Configuration Reference
### Global Settings (`.env`)
| Variable | Description | Default | Required |
| :--- | :--- | :--- | :---: |
| `PAPERLESS_URL` | Full URL to Paperless-NGX (e.g., `http://192.168.1.5:8000`) | - | โ
|
| `PAPERLESS_VERIFY_SSL` | Verify SSL certificates (`false` for self-signed) | `true` | โ |
| `WHITELIST` | Allowed file extensions | `pdf,jpg,png,bmp` | โ |
| `ARCHIVE` | `true` = Move to archive folder, `false` = Delete after upload | `true` | โ |
| `UPLOAD_TIMEOUT` | Max time (seconds) for API upload | `30` | โ |
| `SCAN_SETTLE_TIME` | Seconds to wait after detection before upload | `5` | โ |
| `PUID` | User ID to run as (matches host user) | `1000` | โ |
| `PGID` | Group ID to run as (matches host group) | `1000` | โ |
### Single-User Settings (`.env`)
Ignored when `config/users.conf` is present.
| Variable | Description | Default |
| :--- | :--- | :--- |
| `PAPERLESS_API_KEY` | API Token from Paperless Settings โ API Tokens | - |
| `PAPERLESS_TAGS` | Comma-separated tags to apply | `""` |
| `SMB_USER` | Username for the scanner to login | `scanner` |
| `SMB_PASSWORD` | Password for the scanner | `scan123` |
| `SMB_SHARE` | Name of the SMB share | `scanner` |
### Multi-User Settings (`config/users.conf`)
| Field | Description | Required |
| :--- | :--- | :---: |
| `smb_user` | Linux/SMB username โ unique, no spaces | โ
|
| `smb_password` | Password for the SMB share | โ
|
| `smb_share` | Share name visible to the scanner | โ
|
| `paperless_api_key` | API Token from Paperless Settings โ API Tokens | โ
|
| `paperless_tags` | Comma-separated tags (optional, can be empty) | โ |
> **Note on Permissions:** This container starts as root to fix volume permissions and bind port 445, then immediately drops privileges to the user specified in `PUID`/`PGID`.
---
## ๐ Directory Structure
**Single-user mode**
```text
/data
โโโ inbox/ <-- Scanner saves files here (monitored)
โโโ archive/ <-- Processed files are moved here (if ARCHIVE=true)
```
**Multi-user mode**
```text
/data
โโโ alice/
โ โโโ inbox/ <-- alice's Samba share (monitored)
โ โโโ archive/ <-- alice's processed files
โโโ bob/
โโโ inbox/ <-- bob's Samba share (monitored)
โโโ archive/ <-- bob's processed files
```
## ๐ ๏ธ Troubleshooting
**๐ "Upload failed" in logs**
* Check if `PAPERLESS_URL` is reachable from inside the container.
* Verify the API key (`PAPERLESS_API_KEY` or the key in `users.conf`).
* If using a self-signed cert, try setting `PAPERLESS_VERIFY_SSL=false`.
* Increase `SCAN_SETTLE_TIME`. Some network scanners report "finished" before the file is fully flushed to disk.
**๐ซ Scanner cannot connect (Network Error)**
* Ensure port **445** is not blocked by a firewall on the host.
* Windows/Mac hosts might use port 445 for their own sharing service. Ensure port 445 is free or use a different external port (note: many scanners hardcode 445).
**๐ File is ignored**
* Check the `WHITELIST` in `.env`.
* The container waits for the `close_write` event. Ensure the scanner finishes writing the file completely.
**๐ฅ Multi-user: user cannot connect**
* Verify the share name in `users.conf` matches what the scanner is configured with.
* Check the container logs for `[INIT] Configured N user(s).` โ if N is 0, the config file has a parsing issue.
* Ensure all four required fields (`smb_user:smb_password:smb_share:paperless_api_key`) are present.
---
## ๐ค How to Contribute
Contributions, improvements, and bug fixes are welcome!
1. Fork the project.
2. Create your feature branch (`git checkout -b feature/AmazingFeature`).
3. Commit your changes (`git commit -m 'Add some AmazingFeature'`).
4. Push to the branch (`git push origin feature/AmazingFeature`).
5. Open a Pull Request.
**Note to Forks:** Please ensure that the original author credit remains intact in the license and documentation when forking or redistributing this project.
## ๐จโ๐ป Development
Build the image locally:
```bash
docker build -t scan-to-paperless .
```
## ๐ License
Distributed under the MIT License. See [LICENSE](LICENSE) for more information.