Deploy NextPDF Connect
At a glance
Section titled “At a glance”REST and gRPC transports run in RoadRunner worker pools. The package includes three RoadRunner profiles: HTTP only, gRPC only, and a combined profile. The MCP transport runs as a plain subprocess and does not need a supervisor.
Install
Section titled “Install”composer require nextpdf/server./vendor/bin/rr get-binaryConceptual overview
Section titled “Conceptual overview”RoadRunner is the process supervisor. It owns the worker pool, restarts
workers under memory pressure, and routes each request to an available
worker. The PHP package provides the worker entry point:
bin/nextpdf-server for HTTP, and bin/nextpdf-grpc for gRPC. RoadRunner
wraps that entry point with a pool. Each worker handles one request at a
time.
The MCP transport works differently. bin/nextpdf-mcp is a single PHP
process. It speaks JSON-RPC over stdio, and the client starts it directly.
API surface
Section titled “API surface”RoadRunner profiles
Section titled “RoadRunner profiles”| Profile | Transports | Command |
|---|---|---|
.rr.yaml | REST only | rr serve -c .rr.yaml |
.rr.grpc.yaml | gRPC only | rr serve -c .rr.grpc.yaml |
.rr.full.yaml | REST + gRPC | rr serve -c .rr.full.yaml |
The HTTP profile binds the REST listener to 0.0.0.0:8080. It exposes a
status endpoint on :2114 and metrics on :2112. It sizes the worker
pool from NEXTPDF_WORKER_COUNT, which defaults to four. In the shipped
profiles, the supervisor limits each worker to 256 MB.
The combined profile adds the gRPC worker pool on tcp://0.0.0.0:9090.
It sizes that pool from NEXTPDF_GRPC_WORKER_COUNT, which defaults to
two. It also configures gRPC mutual TLS.
Code sample — Quick start
Section titled “Code sample — Quick start”export NEXTPDF_API_KEYS_FILE=/run/secrets/api-keys./vendor/bin/rr serve -c .rr.full.yamlCode sample — Production
Section titled “Code sample — Production”Run a production container with the combined profile, file-based keys, and Redis-backed shared stores:
services: nextpdf-connect: image: ghcr.io/nextpdf-labs/server:latest command: ["rr", "serve", "-c", "/app/.rr.full.yaml"] ports: - "8080:8080" # REST - "9090:9090" # gRPC environment: - NEXTPDF_API_KEYS_FILE=/run/secrets/api-keys - NEXTPDF_WORKER_COUNT=8 - NEXTPDF_GRPC_WORKER_COUNT=4 - NEXTPDF_REDIS_HOST=redis secrets: - api-keys depends_on: redis: condition: service_healthy restart: unless-stopped redis: image: redis:8Edge cases and gotchas
Section titled “Edge cases and gotchas”-
In-memory stores do not span workers. Without Redis, each worker keeps its own rate-limit, idempotency, and document stores. In a multi-worker pool, in-memory stores produce inconsistent rate limiting and can lose documents across workers. For any pool larger than one worker, set
NEXTPDF_REDIS_HOSTand installext-redis. The server automatically falls back to in-memory stores if the Redis connection fails. Verify Redis health; do not assume it. -
The job store is SQLite in WAL mode. Async jobs persist to one SQLite file shared by all HTTP and gRPC workers. Put that file on a volume that all workers can write to. When a worker shuts down, it marks its still-running jobs as failed on a best-effort basis, so those jobs are not left orphaned.
-
bin/nextpdf-pruneis a maintenance entry point. It ships in the repository, not invendor/bin/. Invoke it directly for store pruning tasks. It is not a server transport. -
The image PHP version may not have
ext-redis. The shipped Dockerfile buildsext-redison a best-effort basis. It continues without the extension if no compatible release exists for the base PHP. Confirm that the extension is present in the running image before you rely on Redis-backed stores.
Performance
Section titled “Performance”Set NEXTPDF_WORKER_COUNT for the available CPU and memory. Each worker
is a PHP process limited by the supervisor memory ceiling. For
render-heavy workloads, start with one worker per core, then tune against
the metrics endpoint. Size the gRPC pool independently. It is typically
smaller than the HTTP pool, because gRPC clients are usually fewer and
longer-lived.
Security notes
Section titled “Security notes”gRPC mutual TLS
Section titled “gRPC mutual TLS”The combined profile configures the gRPC transport for mutual Transport Layer Security (TLS): the server presents a certificate, then requires and verifies a client certificate. Supply the server key, server certificate, and client CA as deployment secrets, not baked into the image. Generate and rotate them out of band; do not run the gRPC transport with a plaintext listener on an untrusted network.
REST TLS termination
Section titled “REST TLS termination”The REST profile binds a plaintext HTTP listener. Terminate TLS in front
of it with a reverse proxy, load balancer, or service mesh, and bind the
listener to the internal network only. Forward the client identity through
the Authorization header unchanged; the server performs its own key
validation. The listener does not provide secure transport on its own;
this deployment configuration does.
Secrets
Section titled “Secrets”Mount API keys with NEXTPDF_API_KEYS_FILE pointing to a secret file
instead of using the inline NEXTPDF_API_KEYS variable. The file-based
store hot-reloads on change, so rotation needs no restart. Never bake keys
or TLS private material into the image. See /connect/security-and-operations/.
Conformance
Section titled “Conformance”Deployment mechanics make no normative protocol claims. Authentication and transport-security citations are pinned on /connect/security-and-operations/.
Commercial context
Section titled “Commercial context”Install nextpdf/premium into the image to register the additional Pro
and Enterprise tools inside the same workers. No separate process or port
is involved. You set the packaging boundary at image build time.
See also
Section titled “See also”- /connect/configuration/ — worker count, Redis, and tier ceilings
- /connect/security-and-operations/ — TLS, mutual TLS, secrets, threat model
- /transports/rest/ · /transports/grpc/ — per-transport runtime detail
- /connect/production-usage/ — health probes, scaling, and observability
- /connect/troubleshooting/ — diagnosing worker, store, and auth failures