This example demonstrates a local Nutrient Document Engine deployment using Docker Compose, PostgreSQL, MinIO, and Caddy.
This stack is intended for local development and manual testing of large uploads. It includes a README, a setup.sh, a dedicated configuration file, and a sample document for smoke tests.
- A Docker-compatible runtime with
docker composesupport curl
-
Run the automated setup script:
./setup.sh
-
Wait for the script to report that the stack is healthy, then open:
http://localhost:5000/dashboard
Default credentials:
- Username:
admin - Password:
admin
The setup script starts four services:
- PostgreSQL for Document Engine metadata
- MinIO as the local S3-compatible asset store
- Document Engine itself
- Caddy as the reverse proxy in front of Document Engine
The local profile lives in document-engine.env.sh. setup.sh sources that file before calling docker compose, so you can either:
- Edit
document-engine.env.sh - Override individual values in your shell before running
./setup.sh
Example:
export CADDY_HTTP_PORT=5050
export DASHBOARD_PASSWORD=supersecret
./setup.shYou can also choose the Document Engine image tag at invocation time:
./setup.sh
./setup.sh nightlyThe default tag is latest.
The default profile is tuned for multi-GB uploads:
MAX_UPLOAD_SIZE_BYTES=50000000000SERVER_REQUEST_TIMEOUT=900000PSPDFKIT_WORKER_TIMEOUT=900000FILE_UPLOAD_TIMEOUT_MS=900000ASSET_STORAGE_CACHE_SIZE=20000000000
To actually test large documents, you must provide a valid ACTIVATION_KEY. Without one, Document Engine runs with license-imposed trial limits and uploads are capped at 50 MB, even though the local proxy and runtime configuration allow much larger request bodies.
Caddy is configured to:
- Allow request bodies up to
50GB - Proxy
/i/d/.../h/.../page-*tile-rendering requests upstream over HTTP/2 - Keep all other upstream requests on HTTP/1.1 with
response_header_timeout 15m
The dashboard is exposed at plain http://localhost:5000/dashboard. TLS is not needed: Caddy's h2c reverse proxy uses Go's http.Transport, which multiplexes incoming HTTP/1.1 requests onto a single upstream HTTP/2 connection. This gives Document Engine the HTTP/2 stream multiplexing it needs to reuse a single rendering worker across concurrent tile requests.
Once the stack is running, you can use the Document Engine API directly through Caddy.
curl --request POST \
--url http://localhost:5000/api/documents \
--header 'Authorization: Token token=secret' \
--form 'pdf-file-from-multipart=@sample.pdf' \
--form 'instructions={"parts":[{"file":"pdf-file-from-multipart"}],"actions":[],"output":{"type":"pdf","metadata":{"title":"Test Document","author":"API User"}}}'curl --request GET \
--url http://localhost:5000/api/documents \
--header 'Authorization: Token token=secret'Replace DOCUMENT_ID with the actual document ID from the upload response:
curl --request GET \
--url http://localhost:5000/api/documents/DOCUMENT_ID/document_info \
--header 'Authorization: Token token=secret'curl --request GET \
--url http://localhost:5000/api/documents/DOCUMENT_ID/pages/text \
--header 'Authorization: Token token=secret'curl --request GET \
--url http://localhost:5000/api/documents/DOCUMENT_ID/pdf \
--header 'Authorization: Token token=secret' \
--output downloaded-document.pdfStop the stack:
source document-engine.env.sh
docker compose downRemove the stack and local volumes:
source document-engine.env.sh
docker compose down -vNutrient offers support for customers with an active SDK license via Nutrient Support.
Are you evaluating our SDK? That's great, we're happy to help out. To make sure this is fast, please use a work email and have someone from your company fill out our sales form.
This project is licensed under the BSD license. See the LICENSE file for more details.
Please ensure you have signed our CLA so that we can accept your contributions.