Build your image
PDF Server is distributed as a base Docker image. You build your service by layering your templates on top of it.
With Docker
# Dockerfile
ARG PDF_SERVER_IMAGE=registry.gitlab.com/c0va23/pdf-server:latest-chromium
FROM ${PDF_SERVER_IMAGE}
ADD templates templates
ADD compositions compositionsdocker build -t my-pdf-service .
docker run --rm -it -p 9999:9999 my-pdf-serviceThe base image’s entrypoint runs the server, loading templates/ and compositions/ from the working directory. Configure everything else via environment variables (see the CLI & config reference).
With Earthly
# Earthfile
my-image:
FROM registry.gitlab.com/c0va23/pdf-server:latest-chromium
ENV TEMPLATES_RECURSIVE=true
COPY --dir templates compositions .
SAVE IMAGE --push registry.example.com/my-pdf-service:latestChromium vs Firefox
Two base image families are published:
| Image | Browser | Notes |
|---|---|---|
…:latest-chromium | Chromium | Supports both runner and page factory modes |
…:latest-firefox | Firefox | Use --factory-type=runner; ships different BROWSER_ARGS |
Most deployments use Chromium. See Deployment for factory modes and pool tuning.
Nested (recursive) templates
If you organise templates into nested folders, enable recursive loading so names like invoices/eu are discovered:
-e TEMPLATES_RECURSIVE=trueVerify in CI
Fail the build if any template or example cannot render:
pdf-server validate --templates-dir ./templates --compositions-dir ./compositionsRun it
Your service now serves the HTTP API:
curl -X POST -H 'Content-Type: application/json' \
-d '{"number":"A-1"}' \
http://localhost:9999/templates/invoice/render > invoice.pdfPut an authenticating reverse proxy in front of it and apply the hardening checklist before exposing it.