Skip to content

Deployment

Everything an operator needs to take TurboOCR from “I want to run this in prod” to “it’s running, monitored, and won’t fall over.” This page covers the supported Docker tags, the required GPU and driver baseline, the TensorRT cache volume, language switching, MPS-based scaling, monitoring endpoints, and a short production checklist.

  • OS — Linux. The container is built on the official NVIDIA TensorRT base image and is verified on Ubuntu 24.04.
  • GPU — NVIDIA Turing or newer (RTX 20-series, GTX 16-series, or anything more recent).
  • Driver — NVIDIA driver 595 or newer, plus the NVIDIA Container Toolkit so --gpus all is honored by Docker.
  • VRAM — roughly ~4 GB for a text-only deployment and ~8 GB for the full pipeline (layout + tables + formulas). Each additional PIPELINE_POOL_SIZE replica adds about another full set.
  • CPU fallback — a CPU-only image exists for development on machines without a GPU, but throughput is much lower (single-digit img/s) and it should not be used in production.

Pre-built images are published to GitHub Container Registry under ghcr.io/aiptimizer/turboocr. Two flavors are produced from docker/Dockerfile.gpu and docker/Dockerfile.cpu in the source repo.

TagPurposeNotes
:latestGPU image, tracks the most recent releaseDrogon HTTP on 8000 (via nginx), gRPC on 50051. Bakes every recognizer, PP-DocLayoutV3, and the table/formula weights. Fine for demos; pin in prod.
:v3.1.0Pinned GPU imageThe current release — use this in production.
turboocr-cpu:v3.1.0CPU fallbackONNX Runtime instead of TensorRT (own image: ghcr.io/aiptimizer/turboocr-cpu). Single-digit img/s — dev/CI only.

The default image runs the full TensorRT pipeline. The first start compiles engines from ONNX (about 90 seconds on an RTX 5090, up to ~1 hour on older GPUs); the named trt-cache volume persists those engines so subsequent restarts are instant.

Terminal window
docker volume create trt-cache
docker run --gpus all -p 8000:8000 -p 50051:50051 \
-v trt-cache:/home/ocr/.cache/turbo-ocr \
ghcr.io/aiptimizer/turboocr:latest

HTTP listens on 8000 (nginx in front of Drogon, for connection buffering) and gRPC on 50051. Both protocols share the same GPU pipeline pool — you can run them simultaneously from the same container.

The CPU image is a drop-in fallback for hosts without an NVIDIA GPU. It uses ONNX Runtime instead of TensorRT, runs on plain ubuntu:24.04, and exposes the same HTTP API.

Terminal window
docker run -p 8000:8000 \
ghcr.io/aiptimizer/turboocr-cpu:v3.1.0

TensorRT engines and language bundles live at /home/ocr/.cache/turbo-ocr inside the container. Mount this path as a named volume — never a host bind-mount.

Terminal window
docker volume create trt-cache
docker run --gpus all -p 8000:8000 -p 50051:50051 \
-v trt-cache:/home/ocr/.cache/turbo-ocr \
ghcr.io/aiptimizer/turboocr:latest

Why a named volume. The image symlinks /app/models/rec into the cache directory so non-default language bundles also live there. Bind-mounting an empty host directory at this path would shadow the baked-in bundles and leave the server with nothing to load. Named volumes auto-populate from the image on first use, which is exactly what you want.

If you delete the volume. The next start will rebuild every TensorRT engine from ONNX (~90 seconds) and re-extract the baked bundles. No data loss — just a slower cold start.

Set the OCR_MODEL environment variable at start time. All models are baked into the image at build time from pinned PaddleOCR releases; there is no runtime download.

Terminal window
docker run --gpus all -p 8000:8000 -p 50051:50051 \
-v trt-cache:/home/ocr/.cache/turbo-ocr \
-e OCR_MODEL=medium \
ghcr.io/aiptimizer/turboocr:latest

The PP-OCRv6 tiers tiny (default) / small / medium cover Latin + Chinese + Japanese and trade accuracy for speed. Other scripts use retained PP-OCRv5 recognizers via the same variable: arabic, eslav (Cyrillic), korean, thai, greek. OCR_LANG still works as a deprecated alias (warns on use). See the Configuration page for the full breakdown.

The repository ships a browser UI — drop in an image or PDF, run OCR, see the layout overlay and reading order, select recognized text, and download a searchable PDF. It runs as a second container that proxies /api/* to the OCR server, so the browser stays same-origin and the server needs no CORS.

From the source repo root:

Terminal window
# GPU
docker compose -f docker-compose.demo.yml up --build
# CPU (dev/CI)
docker compose -f docker-compose.demo.cpu.yml up --build

Then open http://localhost:3000. The demo compose enables TABLE_BACKEND=slanext and FORMULA_BACKEND=ppformulanet_s, so tables and formulas are available end-to-end. The OCR service is still reachable directly on http://localhost:8000 for curl.

The bundled image runs nginx in front of Drogon to buffer slow clients, but nginx cannot rescue a client that opens a fresh TCP connection per request. See the Clients guide for working examples in Python, Java, and C++.

Scrape GET /metrics for Prometheus-compatible metrics. The server exposes per-route request counters, latency histograms, VRAM usage, and pipeline-pool saturation:

turbo_ocr_requests_total{route="/ocr/raw",status="2xx"} 1042
turbo_ocr_request_duration_seconds_bucket{route="/ocr/raw",le="0.025"} 980
turbo_ocr_request_duration_seconds_sum{route="/ocr/raw"} 12.345
turbo_ocr_request_duration_seconds_count{route="/ocr/raw"} 1042
turbo_ocr_gpu_vram_used_bytes 9052815360
turbo_ocr_gpu_vram_total_bytes 33661911040
turbo_ocr_pipeline_pool_size 5
turbo_ocr_pool_exhaustions_total 0
turbo_ocr_request_bytes_total 49493243
turbo_ocr_request_body_avg_bytes 9407
EndpointUse
GET /healthBasic liveness — returns "ok".
GET /health/liveKubernetes liveness probe. Returns 200 once the process is up.
GET /health/readyReadiness probe. Returns 200 only after the GPU pipeline passes a smoke test — gate traffic on this.

For local builds, custom CUDA targets, or air-gapped deployments, see the build instructions in the GitHub repository. The Dockerfiles in docker/ are the canonical reference; the README’s “Building from Source” section lists every dependency and the CMake invocation for both GPU and CPU targets.