A Docker service that automatically interleaves manually duplex-scanned PDFs.
When scanning documents on a scanner without auto-duplex, you scan all front pages first, then flip the stack and scan all back pages. The back pages come out in reverse order. Duplexer automatically interleaves these pages into the correct order.
Input: F1, F2, F3, ..., Fn, Bn, B(n-1), ..., B1 Output: F1, B1, F2, B2, F3, B3, ..., Fn, Bn
- Automatic interleaving of front and back pages
- Continuous directory watching with file stability checks
- Atomic writes - no partial files
- Idempotent - won't reprocess already-completed files
- Handles odd page counts (insert blank page or move to failed)
- Flexible file detection (stability-based or .ready sidecar files)
- Docker-ready with health checks
- Drop your scanned PDFs in
/ingest - Duplexer detects new files and waits for stability (default 5 seconds)
- Pages are interleaved and written to
/completed - Original is archived to
/ingest/archive
Pull and run:
docker run -d \
-v /path/to/scans:/ingest \
-v /path/to/output:/completed \
-e LOG_LEVEL=INFO \
--name duplexer \
ghcr.io/lipkau/duplexer:latestAvailable tags:
latest— Stable release (semver tags only)dev— Development build from mainvX.X.X— Specific versions (e.g.,v1.0.0)vX— Major versions (e.g.,v1)
For Docker Compose examples (including paperless-ngx integration), see docker-compose.examples.md.
Duplexer uses hardcoded paths inside the container. Mount your directories via Docker:
| Path | Purpose | Mount |
|---|---|---|
/ingest |
Input directory for new PDFs | -v /path/to/scans:/ingest |
/completed |
Output directory for processed | -v /path/to/output:/completed |
/ingest/archive |
Successfully processed originals | (auto-created) |
/ingest/failed |
Invalid or failed PDFs | (auto-created) |
| Variable | Default | Description |
|---|---|---|
LOG_LEVEL |
INFO |
Logging: DEBUG, INFO, WARNING, ERROR |
SCAN_GLOB |
*.pdf |
File pattern to watch (e.g., scan_*.pdf, *.PDF) |
FILE_STABILITY_SECONDS |
5.0 |
Seconds file must remain unchanged before processing |
REQUIRE_READY_FILE |
false |
If true, only process PDFs with matching .ready sidecar file |
REVERSE_BACKS |
true |
Back pages are in reverse order (normal for manual duplex) |
INSERT_BLANK_LASTBACK |
false |
Insert blank page for odd counts; false moves to failed |
OUTPUT_SUFFIX |
.duplex |
Suffix for output filenames (e.g., scan.pdf → scan.duplex.pdf) |
docker run -d \
-v /scans:/ingest \
-v /output:/completed \
-e LOG_LEVEL=DEBUG \
-e FILE_STABILITY_SECONDS=10.0 \
-e INSERT_BLANK_LASTBACK=true \
-e OUTPUT_SUFFIX=.interleaved \
--name duplexer \
ghcr.io/lipkau/duplexer:latestSee docker-compose.examples.md for Docker Compose setup with paperless-ngx.