Deployment
docray ships as one container image containing the server, the worker CLI, and the pinned PDFium build. The same image runs everywhere.
Docker
docker build -t docray .
docker run -d --rm -p 41619:41619 \
-e DOCRAY_WORKERS=2 \
docray
The image runs as a non-root user with the data directory at /data; mount
a volume there if you want job results to survive restarts.
The runtime stage is distroless
(gcr.io/distroless/cc-debian13): it contains the two docray binaries, the
PDFium shared library, glibc/libstdc++, CA certificates and tzdata — no shell,
package manager, curl, perl or openssl. docker exec ... sh does not work in
this image, and health checks cannot shell out to curl. Use the built-in
probe instead:
docray-server --healthcheck # exit 0 when GET /healthz on DOCRAY_PORT returns 200, else 1
The image declares a Docker HEALTHCHECK with this command; ECS task
definitions must use the exec form ("CMD", not "CMD-SHELL") as in the
example below.
AWS ECS Fargate
A validated task-definition example lives at
deploy/ecs-task-def.example.json:
1 vCPU / 5 GB memory with 2 workers (see the
sizing guidance), a container health
check via docray-server --healthcheck, and CloudWatch logging. Before
registering it:
- push the image to ECR and fill in the image URI,
- create the CloudWatch log group (
/ecs/docray), - set an
executionRoleArnthat can pull from ECR and write logs.
What to know operationally
- Job state is instance-local (SQLite + files under
DOCRAY_DATA_DIR). One instance is the supported topology; horizontal scaling would require an external job store. - On restart, jobs that were mid-flight are automatically re-queued.
- With telemetry disabled (the default), the server needs no outbound network — only the playground’s browser assets (pdf.js, fonts) load from CDNs, client-side. Enabling the OTLP exporter requires outbound access to the configured collector.
- Responses are not compressed at the HTTP layer yet; if you front docray
with a reverse proxy, enabling gzip/brotli there shrinks
char-level responses dramatically.
OpenTelemetry
For production, send metrics to an OpenTelemetry Collector rather than configuring a vendor SDK in the docray container:
OTEL_METRICS_EXPORTER=otlp
OTEL_EXPORTER_OTLP_ENDPOINT=http://otel-collector:4318
OTEL_SERVICE_NAME=docray-server
OTEL_RESOURCE_ATTRIBUTES=deployment.environment.name=production
The collector can fan metrics out to CloudWatch, Prometheus, Grafana,
Datadog, Honeycomb, New Relic, or multiple destinations. Set
DOCRAY_TELEMETRY_LOGS=json when the deployment also wants per-request
structured events in its existing log pipeline.