Docling Serve Document Conversion API on AWS User Guide
Overview
Docling Serve is the HTTP API service around Docling, an open source toolkit that converts documents into clean, structured content. Point it at a PDF, DOCX, PPTX, HTML or image file and it returns well structured Markdown or JSON in which headings, paragraphs, lists and tables survive the conversion, using machine learning models that understand page layout and reconstruct table structure. Applications POST a document and receive content ready to index, chunk for retrieval augmented generation, feed to a language model, or store. Docling and Docling Serve are Linux Foundation AI & Data projects, originally created at IBM Research, and are released under the MIT licence.
The cloudimg AMI installs Docling Serve into a Python virtual environment at /opt/docling, runs it under uvicorn as an unprivileged docling system account bound to loopback, fronts it with a single nginx gateway on TCP 80 that enforces HTTP Basic authentication on every path, and generates a unique API password on the first boot of every instance. The layout, table structure and OCR models are baked into the image and the service runs in offline mode, so both text based and scanned documents convert without the instance ever reaching out to the internet. Backed by 24/7 cloudimg support.
What is included:
- docling-serve 1.27.0 and the docling conversion engine (docling-slim 2.114.0), both MIT licensed
- PyTorch 2.13 (CPU build) — no GPU is required anywhere
- Baked ML models, all licences verified against the artifacts at build time: document layout analysis (
docling-layout-heron, Apache-2.0), table structure / TableFormer (docling-models, CDLA-Permissive-2.0), and OCR (RapidOCR PP-OCR, Apache-2.0) - nginx as an authenticating reverse proxy, the only network reachable surface
- A built in UI playground at
/ui, an interactive Swagger UI at/swaggerand a ReDoc reference at/docs - A per instance API password generated on first boot into a root only file
- An unauthenticated
/healthzendpoint for load balancer probes

Key facts
| Item | Value |
|---|---|
| Install root | /opt/docling |
| Baked models | /opt/docling/models |
| Credentials file | /root/docling-credentials.txt |
| API user | admin |
| Backend (loopback) | 127.0.0.1:5001 |
| Public API | TCP 80 via nginx |
| UI playground | /ui |
| Swagger UI | /swagger |
| ReDoc API reference | /docs |
| Recommended instance type | m5.large (2 vCPU / 8 GiB) |
Connecting to your instance
An AWS Marketplace listing can offer the same product on several operating systems; each OS variant has its own default SSH login user. Connect as the user for the variant you launched:
| OS variant | Default SSH user |
|---|---|
| Ubuntu 24.04 | ubuntu |
ssh <ssh-user>@<public-ip>
Prerequisites
- An AWS account and either the AWS Management Console or the AWS CLI.
- An EC2 key pair for SSH access.
- A security group that allows inbound TCP 22 (SSH) and TCP 80 (the API) from the addresses you will connect from. Restrict both to your own IP ranges.
- The recommended instance type is m5.large (2 vCPU / 8 GiB). The models load to roughly 2.7 GiB resident; the appliance runs on a 4 GiB instance for evaluation, but m5.large gives headroom for larger documents and concurrent requests. No GPU is needed.
Step 1 — Launch from AWS Marketplace
- In the AWS Marketplace console, find Docling Serve Document Conversion API AMI by cloudimg and choose Continue to Subscribe, then Continue to Configuration and Continue to Launch.
- Choose the software version and your region.
- Select the instance type (m5.large recommended), your VPC and subnet, and a security group that allows inbound TCP 22 and TCP 80 from your own IP ranges only.
- Select your EC2 key pair and launch.
- When the instance is running, note its public IP address (or DNS name).
Step 2 — Launch from the AWS CLI
Replace the AMI id with the one shown on the Marketplace listing for your region, and use your own key pair and security group.
aws ec2 run-instances \
--image-id ami-xxxxxxxxxxxxxxxxx \
--instance-type m5.large \
--key-name my-key \
--security-group-ids sg-xxxxxxxx \
--tag-specifications 'ResourceType=instance,Tags=[{Key=Name,Value=docling-serve}]'
Make sure the security group allows inbound TCP 22 and TCP 80 from your own IP ranges only.
Step 3 — Connect to your instance
ssh ubuntu@<public-ip>
The login banner shows where to find the credentials file, the model provenance and this guide. Use the SSH user for your OS variant from the table above.
Step 4 — Confirm the service is running
systemctl is-active docling-serve.service nginx.service
Expected output:
active
active
The uvicorn backend listens on loopback only and nginx is the single authenticated front end. Confirm the bind and the unauthenticated health probe:
sudo ss -tln | grep -E ':5001|:80 '
curl -s http://127.0.0.1/healthz
Expected output:
LISTEN 0 511 0.0.0.0:80 0.0.0.0:*
LISTEN 0 2048 127.0.0.1:5001 0.0.0.0:*
ok
The backend on 127.0.0.1:5001 is not reachable from outside the instance; every request arrives through nginx on port 80.
Step 5 — Retrieve your API password
Every instance generates its own password on first boot. There is no default login and no shared secret between deployments.
sudo cat /root/docling-credentials.txt
The file is readable only by root (0600) and contains DOCLING_URL, DOCLING_USERNAME and DOCLING_PASSWORD. Store the password in your secret manager and treat it as you would any API key. In the commands below, replace <DOCLING_PASSWORD> with this value.
Step 6 — Confirm authentication is enforced
Every API path requires the credential. An unauthenticated conversion request is refused:
curl -s -o /dev/null -w 'no credential -> HTTP %{http_code}\n' \
-X POST http://127.0.0.1/v1/convert/file \
-F 'files=@/opt/docling/samples/sample.pdf;type=application/pdf' \
-F do_ocr=false -F to_formats=md
Expected output:
no credential -> HTTP 401
With the per instance password the same request succeeds:
curl -s -o /dev/null -w 'per instance password -> HTTP %{http_code}\n' \
-u admin:<DOCLING_PASSWORD> \
-X POST http://127.0.0.1/v1/convert/file \
-F 'files=@/opt/docling/samples/sample.pdf;type=application/pdf' \
-F do_ocr=false -F to_formats=md
Expected output:
per instance password -> HTTP 200
A wrong password is refused with 401 as well, so the credential is genuinely enforced rather than decorative.
Step 7 — Convert a document to Markdown
The image ships a small synthetic sample document at /opt/docling/samples/sample.pdf — a text layer PDF with a heading, a paragraph and a table. Convert it and extract the Markdown from the response. Passing do_ocr=false uses the fast, fully offline text extraction path together with the layout and table models.
curl -s -u admin:<DOCLING_PASSWORD> \
-X POST http://127.0.0.1/v1/convert/file \
-F 'files=@/opt/docling/samples/sample.pdf;type=application/pdf' \
-F do_ocr=false -F to_formats=md \
| python3 -c 'import sys,json; print(json.load(sys.stdin)["document"]["md_content"])'
Expected output:
## CLOUDIMG DOCLING SAMPLE INVOICE
This is a synthetic sample document authored by cloudimg to verify document conversion end to end. Verification marker: DOCLINGPROOF7Q2X.
## Line items
| Item | Quantity | Unit Price |
|---------------|------------|--------------|
| Widget Alpha | 3 | 12.00 |
| Sprocket Beta | 5 | 4.50 |
| Cog Gamma | 2 | 9.75 |
The headings became Markdown headings and the table became a Markdown table — the layout model located the page elements and the TableFormer model reconstructed the table grid. To convert your own document, replace the file path. PDF, DOCX, PPTX, HTML, Markdown, AsciiDoc, CSV and common image formats are accepted.
The response is a JSON object with a document field. Besides md_content it also carries json_content, html_content, text_content and doctags_content, so you can ask for whichever representation suits your pipeline via to_formats (for example -F to_formats=json).
Step 8 — Run OCR on a scanned image (fully offline)
Scanned or image only documents have no text layer, so they need optical character recognition. The RapidOCR models are baked into the image, so OCR runs entirely offline — nothing is sent to any external service. The image ships a synthetic scanned sample at /opt/docling/samples/ocr_sample.png. Convert it with do_ocr=true:
curl -s -u admin:<DOCLING_PASSWORD> \
-X POST http://127.0.0.1/v1/convert/file \
-F 'files=@/opt/docling/samples/ocr_sample.png;type=image/png' \
-F do_ocr=true -F force_ocr=true -F to_formats=md \
| python3 -c 'import sys,json; print(json.load(sys.stdin)["document"]["md_content"])'
Expected output:
## OCRPROOF ZEBRA 4831
synthetic scanned image, no text layer
The recognised text is returned as Markdown. To convert your own scanned document, replace the file path. OCR is more CPU intensive than text extraction, so scanned documents take longer than text layer PDFs of the same length.
Step 9 — Use the built in UI playground and API docs
The image enables the Docling Serve playground at /ui, an interactive Swagger UI at /swagger and a ReDoc reference at /docs. All three are behind the same Basic authentication, so your browser prompts once for the admin credential. In a browser, go to http://<public-ip>/ui and sign in.
Upload a document on the Convert File tab and convert it to see the structured output rendered directly in the page. Below, the sample PDF has been converted and the Markdown tab shows the reconstructed heading, the verification marker and the table.

The /docs page is the ReDoc API reference for the stable v1 API, grouping the health, convert, chunk, tasks, clear and management endpoints.


Step 10 — Call the API from your application
Any HTTP client works. This Python example converts a local PDF and prints the Markdown:
import requests
with open("report.pdf", "rb") as fh:
resp = requests.post(
"http://<public-ip>/v1/convert/file",
auth=("admin", "<DOCLING_PASSWORD>"),
files={"files": ("report.pdf", fh, "application/pdf")},
data={"do_ocr": "false", "to_formats": "md"},
timeout=600,
)
resp.raise_for_status()
print(resp.json()["document"]["md_content"])
For very large documents or batch workloads, Docling Serve also exposes asynchronous conversion endpoints under /v1/convert/source/async with task polling; see /docs for the full contract.
The models and their licences
Document conversion is driven by machine learning models, and each model is a separately licensed artifact. This image bakes only models that permit commercial use and redistribution, and every licence was verified at build time against the shipped model card rather than a documentation badge. The exact models, their sizes and sha256 checksums are recorded on the image:
cat /opt/docling/MODEL-PROVENANCE.txt
| Model | Purpose | Licence |
|---|---|---|
docling-layout-heron |
Document layout analysis (RT-DETRv2) | Apache-2.0 |
docling-models TableFormer |
Table structure reconstruction | CDLA-Permissive-2.0 |
| RapidOCR PP-OCR | Optical character recognition | Apache-2.0 |
None of the shipped models is research only or non commercial, and none is fine tuned from a restricted base. EasyOCR is deliberately not used because its text detector lineage is less clear cut; RapidOCR's PaddleOCR derived models are Apache-2.0 and are the OCR stack shipped. The service runs with HF_HUB_OFFLINE=1, so it always loads these baked models and never reaches out to download anything during a conversion.
Document handling and log hygiene
Documents you submit are the sensitive artifact for this product, so the image is configured to keep them off disk and out of the logs:
- The nginx access log is disabled on every path, and nginx never logs request bodies.
- The service runs at log level
WARNING, so document filenames are not written to the system journal. Document content is never logged at any level. - The synchronous
/v1/convert/fileendpoint returns the result inline and does not persist the submitted document or its output on disk after the response.
You can confirm nothing you submit leaks into the logs by converting a document containing a known marker and then searching /var/log and the journal for it.
Server components
| Component | Role |
|---|---|
docling-serve.service |
The uvicorn API server, bound to 127.0.0.1:5001, running as the docling user |
nginx.service |
Authenticating reverse proxy on TCP 80, the only network reachable surface |
docling-firstboot.service |
One shot unit that generates the per instance password on first boot and proves a real conversion round trip before marking the boot complete |
Filesystem layout
| Path | Contents |
|---|---|
/opt/docling/venv |
Python virtual environment with docling-serve and its dependencies |
/opt/docling/models |
Baked layout, table structure and OCR models |
/opt/docling/samples |
Synthetic sample documents used by the built in self test |
/opt/docling/MODEL-PROVENANCE.txt |
The shipped models with sizes, sha256 and licences |
/var/lib/docling |
Writable scratch and cache directory owned by the docling user |
/root/docling-credentials.txt |
The per instance API password, root only |
/etc/nginx/cloudimg-docling.htpasswd |
The nginx Basic auth password file |
Managing the service
sudo systemctl restart docling-serve.service
sudo systemctl restart nginx.service
sudo journalctl -u docling-serve.service -n 50 --no-pager
Changing the API password
Set a new Basic auth password for the admin user and reload nginx:
sudo sh -c 'printf "admin:%s\n" "$(openssl passwd -apr1 NEW_PASSWORD)" > /etc/nginx/cloudimg-docling.htpasswd'
sudo systemctl reload nginx
Replace NEW_PASSWORD with your chosen password.
Terminating TLS
The image serves the API over HTTP on port 80. For production, terminate TLS in front of the service. Two common approaches:
- AWS Application Load Balancer — put the instance in a target group, terminate TLS on the ALB with an AWS Certificate Manager certificate, and use the unauthenticated
/healthzpath as the target group health check. - Certbot on the instance — point a DNS name at the instance and obtain a certificate directly:
sudo apt-get update && sudo apt-get install -y certbot python3-certbot-nginx
sudo certbot --nginx -d docling.example.com
Certbot obtains a certificate, rewrites the nginx site to listen on 443 and sets up automatic renewal. Restrict inbound access to TCP 443 (and 22) in your security group once TLS is in place.
Troubleshooting
401 Unauthorized— you did not supply the credential, or the password is wrong. Retrieve it withsudo cat /root/docling-credentials.txtand pass it as-u admin:PASSWORD.- The API does not respond — check
systemctl is-active docling-serve.service nginx.service. The backend loads the models at startup, which takes a few seconds after a restart. - A conversion is slow — OCR (
do_ocr=true) is CPU intensive. Use m5.large or larger for heavier workloads and concurrent requests. - Read the logs —
sudo journalctl -u docling-serve.service -n 100 --no-pager.
Security recommendations
- Keep TCP 80 (and 22) restricted to your own IP ranges in the security group.
- Put the service behind TLS as shown above before using it in production.
- Rotate the API password after first login and store it in a secret manager.
- The uvicorn backend is bound to loopback; do not reconfigure it to bind
0.0.0.0, which would bypass the authenticating proxy.
On startup
On the first boot of every instance, docling-firstboot.service generates a unique 24 character API password, writes it to /root/docling-credentials.txt (root only), starts the service, and proves a real conversion round trip before marking the boot complete. No default credential is ever baked into the image. Subsequent boots reuse the generated password.
Support
Every cloudimg deployment is backed by 24/7 support. If you have questions about this image or need help with your deployment, contact the cloudimg support team at support@cloudimg.co.uk.