English
Documents service
The documents service generates PDFs from Word documents (LibreOffice), redacts PDFs (PDFium), reads scans and photos (Tesseract OCR), and merges and splits PDFs. It is a separate image, ghcr.io/kuznyaoff/loopandroll-documents, shared by every instance of a host: instances call it over HTTP, it keeps nothing.
Without it, Loop & Roll works as before: the document nodes are not offered, and scanned attachments are reported as not read.
Run it
Add the service next to your instances, on a private network they share, and give each instance its address and a token:
yaml
services:
documents:
image: ghcr.io/kuznyaoff/loopandroll-documents:main
restart: unless-stopped
environment:
DOCUMENTS_TOKENS: ${DOCUMENTS_TOKEN}
mem_limit: 2g
read_only: true
tmpfs:
- /tmp:size=1g
networks: [documents]
app:
environment:
DOCUMENTS_URL: http://documents:8080
DOCUMENTS_TOKEN: ${DOCUMENTS_TOKEN}
networks: [default, documents]
networks:
documents:
internal: trueinternal: true is the important line: the service has no outbound access. LibreOffice never fetches an image linked by URL from a template, and nothing a document contains can make the service call anywhere.
Generate a token with openssl rand -hex 32 (32 characters at least).
Variables of the service
| Variable | Default | Meaning |
|---|---|---|
DOCUMENTS_TOKENS | — (required) | The accepted tokens, comma-separated (32 characters at least each). One per instance, or one per host; several allow a rotation without downtime. |
PORT | 8080 | Listening port. |
MAX_CONCURRENCY | 2 | Jobs at the same time. Beyond, a request waits QUEUE_WAIT_SECONDS, then gets 503 busy (the instance retries). |
QUEUE_WAIT_SECONDS | 20 | How long a request waits for a free slot. |
JOB_TIMEOUT_SECONDS | 120 | Time budget of one job; beyond, the job and its processes are killed (504 timeout). |
JOB_MEMORY_MB | 1536 | Address space of one PDF job (PDFium, Tesseract). A document that needs more fails with too_complex. |
MAX_DOCUMENT_MB | 25 | Size of one document. |
MAX_REQUEST_MB | 70 | Size of a request body (base64 included). |
MAX_PAGES | 100 | Pages of a PDF to redact or read. |
MAX_PAGES_STRUCTURAL | 1000 | Pages of a PDF to merge or split. |
MAX_MERGE_DOCUMENTS | 20 | PDFs in one merge. |
RENDER_DPI | 200 | Resolution of redacted pages. |
OCR_LANGUAGES | fra+eng | Tesseract languages (the image ships French and English). |
LOG_LEVEL | info | debug, info, warning, error. |
Budget memory as MAX_CONCURRENCY × JOB_MEMORY_MB plus about 300 MB, and set the container limit accordingly.
Variables of the instance
| Variable | Default | Meaning |
|---|---|---|
DOCUMENTS_URL | — | The service address, for example http://documents:8080. |
DOCUMENTS_TOKEN | — | One of the service tokens (DOCUMENTS_TOKEN_FILE works too). The URL and the token, or neither: one without the other is reported at startup and the service stays off. |
DOCUMENTS_TIMEOUT_SECONDS | 150 | Time budget of one call, on the instance side. Keep it above the service's JOB_TIMEOUT_SECONDS. |
DOCUMENTS_MAX_MB | 25 | Size of a document sent to the service. |
What it keeps, what it logs
Nothing is stored: each job runs in its own process, in a temporary folder deleted at the end, with its own LibreOffice profile. The logs carry one line per request — route, status, error code, calling instance, sizes in bytes, duration — and never a document, a term searched or a file name.
Monitoring
GET /healthzanswers200 {"status":"ok"}without a token; the image has a Docker health check.- On the instance side, an unreachable or busy service makes document steps fail transiently: they are retried (three attempts). Invalid documents (password-protected PDF, malformed template) fail permanently, with a reason.
- A
401from the service means the instance's token is not inDOCUMENTS_TOKENS: the steps fail withdocument.not_configured.
Troubleshooting
| Symptom | Cause |
|---|---|
| The nodes do not appear in the palette | DOCUMENTS_URL or DOCUMENTS_TOKEN is missing on the instance (see the startup warnings). |
document.service_unavailable on every run | The instance cannot reach the service: network, name, port, or the service is down. |
Many 503 busy | Raise MAX_CONCURRENCY (and the memory limit), or add a replica. |
too_complex on a large scan | Raise JOB_MEMORY_MB, or lower RENDER_DPI. |
| Generated PDFs lay out differently from Word | A font of the template is missing: the image ships DejaVu, Liberation, Carlito and Caladea (metric equivalents of Calibri and Cambria). |