Scanner to Paperless Integration
Overview
This guide explains how to set up automatic document ingestion from a scanner directly into Paperless-ngx using the printing NixOS module configured on your laptop (sninful).
Architecture
┌──────────────┐
│ Scanner │
│ (Hardware) │
└──────┬───────┘
│ USB/Network
│
┌──────▼────────────────────────┐
│ NixOS (sninful laptop) │
├───────────────────────────────┤
│ • SANE (scanner drivers) │
│ • scanservjs (web UI) │
│ - Scans documents to PDF │
│ - Provides action menu │
│ • Paperless action (optional) │
│ - User-triggered via UI │
│ • paperless-upload script │
│ - Called by action │
└───────────────┬───────────────┘
│ HTTPS
│ API Token Auth
┌───────────────▼───────────────┐
│ Paperless-ngx (Server) │
│ API: /api/documents/... │
└───────────────────────────────┘
How It Works
- Scanning: Use scanservjs web interface to scan documents
- PDF Generation: scanservjs saves the scanned document as a PDF
- Action Selection: After scanning, choose "Upload to Paperless" from the available actions
- Manual Trigger: The action is user-triggered (you can scan without uploading if desired)
- Auto-Upload: When selected, the paperless-upload script is executed with the PDF file path
- Processing: Paperless receives the document and processes it (OCR, tagging, etc.)
Components
scanservjs
- Web Interface: Access at
http://localhost:8080(when enabled) - Purpose: Provides a user with a customizable action menu
- Custom Actions: Displays "Upload to Paperless" as a post-scan action
Paperless Upload Action
- Type: scanservjs custom action
- Trigger: Manually selected by user after scanning (from action menu)
- Execution: Calls the paperless-upload script with the scanned file
- Flexibility: Can be applied selectively (scan without uploading if desired)
paperless-upload Script
- Location: Available in system PATH when enabled
- Purpose: Uploads PDFs to Paperless API with authentication
- Features: Error handling, logging, timeout protection
- Called By: Paperless Upload action
- Logging: View with
journalctl -u scanservjs -f
Configuration
The configuration is in /nix/hosts/sninful/configuration.nix:
printing = {
enable = true;
scanner = {
enable = true;
paperless = {
enable = false; # Set to true after setting up secrets
url = "https://paperless.snyssen.be";
# Only reference the secret path when enabled
apiTokenPath =
if config.printing.scanner.paperless.enable
then config.sops.secrets."paperless/api-token".path
else "/dev/null";
};
};
};
Test the Setup
- Test scanner access:
bash
scanimage -L
Should show your connected scanner.
-
Test scanservjs:
-
Open http://localhost:8080 in your browser
- Perform a test scan
-
Check the action menu available after the scan completes
-
Test the Paperless Upload Action:
-
After your test scan, you should see "Upload to Paperless" in the action menu
- Click it to upload the scanned document
-
Check scanservjs logs for confirmation:
bash journalctl -u scanservjs -n 20 -
Verify in Paperless:
- Check if the document appears in your inbox
Usage
Scanning and Uploading via Web Interface
- Open http://localhost:8080 in your browser
- Adjust scan settings (resolution, color mode, etc.) as needed
- Click Scan to initiate the scan
- Wait for the scan to complete
- Once complete, you'll see the scanned file with available actions
- Click Upload to Paperless to upload the document
- The document will be sent to your Paperless instance
- Alternatively, click another action or download the file
Scanning Without Uploading
Simply don't select the "Upload to Paperless" action. Your scanned documents will be saved locally and can be processed later.
Manual Upload
You can also manually upload PDFs from the command line:
paperless-upload /path/to/document.pdf
Monitoring
Check scanservjs Service Status
systemctl status scanservjs
View scanservjs Logs (includes action execution)
journalctl -u scanservjs -f
Check Recent Action Logs
journalctl -u scanservjs -n 30
Troubleshooting
Scanner Not Detected
- Check USB connection or network settings
- Verify SANE can see the scanner:
bash
scanimage -L
- Check if drivers are loaded:
bash
lsusb # For USB scanners
Upload Fails
- Check API token:
- Verify the token is correct in secrets.yaml
-
Check token permissions in Paperless
-
Test connectivity:
bash
curl -I https://paperless.snyssen.be
- Manual test upload:
bash
paperless-upload /path/to/test.pdf
- Check service logs:
bash
journalctl -u scanservjs -n 50
Service Won't Start
- Check scanservjs service status:
bash
systemctl status scanservjs
- Verify secrets file exists and is readable (when Paperless integration enabled):
bash
ls -l /run/secrets/paperless/api-token
- Check scanservjs service logs:
bash
journalctl -u scanservjs -n 50
Security Notes
- API Token: Stored encrypted with SOPS and deployed with
owner = "scanservjs",mode = "0400"— readable only by thescanservjsservice user, not world-readable or accessible by other users - Transport: All communication with Paperless uses HTTPS
- File Permissions: Scanner output directory is restricted to scanservjs user
- Token Rotation: Regenerate token periodically in Paperless settings
- Action Execution: Actions run as the scanservjs user with appropriate permissions
Future Enhancements
Potential improvements not yet implemented:
- Physical Scan Button: Support for hardware scan button via
scanbdorinsaned - Notifications: Push notifications via ntfy on successful/failed uploads
- Retry Logic: Automatic retry for failed uploads
- Multiple Targets: Support uploading to multiple Paperless instances
- Document Naming: Auto-naming based on date, tags, or document type
- Email Integration: Optional email notifications on upload status
Related Documentation
Module Options Reference
printing.enable
- Type: boolean
- Default:
true - Description: Enable printing support (CUPS, HP drivers)
printing.scanner.enable
- Type: boolean
- Default:
false - Description: Enable scanner support with scanservjs
printing.scanner.paperless.enable
- Type: boolean
- Default:
falseoptional upload action - Description: Enable automatic upload to Paperless-ngx
printing.scanner.paperless.url
- Type: string
- Example:
"https://paperless.snyssen.be" - Description: Paperless-ngx instance URL (without trailing slash)
printing.scanner.paperless.apiTokenPath
- Type: path
- Description: Path to file containing the Paperless API token (provided by SOPS)