Skip to content

9.0.0

Latest

Choose a tag to compare

@gulien gulien released this 05 Nov 18:44
· 9 commits to main since this release

Gotenberg 9 is out 🎉

Important

latest now points to Gotenberg 9. Pin gotenberg/gotenberg:8 until you have upgraded. The upgrade guide maps every Gotenberg 8 route, field, flag, metric and span to its Gotenberg 9 counterpart.

One PDF engine

pdfcpu, QPDF, pdftk and ExifTool are replaced by litho, a PDF engine written in Go for Gotenberg, running in-process.

remediate repairs a PDF until it conforms to one of the eleven PDF/A levels, to PDF/UA-1 or PDF/UA-2, to both together, or to Factur-X, then checks its own result: Gotenberg-Remediation-Residual counts the violations left, Gotenberg-Remediation-Rolled-Back the fixes undone to keep pages, text and images. /forms/pdf/validate runs the same checks on any PDF.

litho also signs and timestamps, redacts from the file rather than from view, infers a structure tree, renders pages as images, fills and flattens forms in the scripts the image's fonts cover, and shrinks a PDF without touching image quality. A stage that would drop the signatures of a signed PDF answers 400, as does text no font can draw.

Stages, in your order

Post-processing is no longer flat fields in a fixed order. A stages list runs as written, on every route that makes a PDF and on /forms/pdf/pipe for PDFs you already have:

[{"op": "merge"}, {"op": "stamp-text", "text": "DRAFT"}, {"op": "remediate", "profile": "PDF/A-2b"}]

26 stages, each also a /forms/pdf/<op> route with form fields, plus six JSON read routes: info, validation, metadata, bookmarks, attachments and form fields. A broken order answers 400 before anything runs.

LibreOffice through lok

unoconverter, Python and the soffice listener are replaced by lok, a long-running LibreOfficeKit process that Gotenberg supervises and restarts after a crash. Macros stay off; --libreoffice-enable-macros runs them.

Fewer dependencies, less CVE surface

Java, Python, unoconverter, pdfcpu, QPDF, pdftk and ExifTool leave the image: fewer packages to patch, and no more CVE reports about tools Gotenberg does not ship. Variants, architectures, user, port and command don't change.

Upgrading

Start from the upgrade guide. /forms/pdfengines routes become /forms/pdf routes, post-processing fields become stages, and a field with a stage twin now starts with native. A removed route answers 404 naming its replacement, a Gotenberg 8 field 400 saying where it went:

Invalid form data: form field 'merge' is unknown to this route; Gotenberg 9 moved it to a stage: add {"op":"merge"} to 'stages'

Custom builds import github.com/gotenberg/gotenberg/v9. The PdfEngine, PdfEngineProvider and MetricsProvider interfaces and the Prometheus module are gone: OTEL_METRICS_EXPORTER=prometheus serves the same.

Everything else

PDF

  • set-form selects several list items, refuses a value a field cannot hold, and lists the PDF's fields when you name a missing one. flatten-form draws a value without appearance over the field's own background and border.
  • Flattened values and text stamps beyond Western European text use an installed font, embedded and subset. Uncovered text answers 400 naming the characters.
  • optimize packs objects into compressed streams, stores identical streams once, recompresses images losslessly and subsets fonts. Every pass runs unless turned off. An encrypted input needs a decrypt or encrypt stage first.
  • merge keeps each file's bookmarks, remapped, and names the result after the first file in alphanumeric order.
  • render draws pages as PNG or JPEG at the resolution you ask.
  • --pdf-max-stream-bytes, --pdf-max-embedded-file-bytes and --pdf-max-image-pixels bound what litho reads. --pdf-allow-list, --pdf-deny-list and their siblings filter the timestamp authorities it calls.

LibreOffice

  • nativePdfa takes PDF/A-1b, PDF/A-2b, PDF/A-3b or PDF/A-4; nativePdfua takes PDF/UA-1. The PDF/A export is no longer redone after the other steps: end the stages with remediate when they may break conformance.
  • initialView, magnification and pageLayout take names such as outline or fitWidth, not numbers. firstPageOnLeft, which LibreOffice ignored, and nativePdfFormats are gone.
  • nativeWatermarkColor takes #rrggbb, nativeWatermarkRotation degrees counter-clockwise, 0 being horizontal. A plain and a tiled watermark together answer 400.
  • CSV files split into columns. .epub is no longer accepted.
  • PDFs are named after their documents, report.docx.pdf, even for a single one. Gotenberg-Output-Filename still overrides.

Chromium

  • paperSize names a format, for LibreOffice too: A3, A4, A5, B4, B5, Letter, Legal or Tabloid.
  • waitForWindowStatus, renamed from waitWindowStatus, now waits as documented. skipNetworkAlmostIdleEvent=false now really waits for networkAlmostIdle.
  • The page sent to the HTML and Markdown routes passes the allow and deny lists, which keep governing what it loads.
  • Print settings Chromium rejects answer 400: a scale out of range, a negative length, a waitDelay longer than the API timeout. A wait that outlasts the request answers 503 naming the field and its value.
  • failOnHttpStatusCodes judges the main page by its frame, not its URL. Screenshot quality goes from 1 to 100.
  • DevTools messages leave the debug logs unless --chromium-debug-protocol is set. URL queries and extra header values stay out too.

API

  • archives unpacks uploaded ZIPs, bounded by --api-archive-max-entries and --api-archive-max-ratio.
  • Errors say what to send: the value sent and the one wanted, a stage option's expected value instead of a Go type, the host that does not resolve. NaN and infinities are refused.
  • Webhook and downloadFrom URLs must be absolute http or https URLs with a host. Gotenberg-Webhook-Events-Url is required with Gotenberg-Webhook-Url and receives errors as webhook.error events: the error URL, method and lists are gone. A failed upload says what the webhook answered, or why it was unreachable.
  • A non-ASCII Gotenberg-Output-Filename is encoded per RFC 6266. Every answer carries the trace header, 404 and 405 included; the version header too, without authentication.
  • The banner is an aligned startup summary, one log record outside a terminal. --api-bind-ip takes IPv6, --api-start-timeout bounds module readiness, /debug reports the lok and litho versions.
  • Debug logs mask form values, extra header values and document passwords.

Telemetry

  • Names follow the OpenTelemetry rules: gotenberg.chromium.requests, gotenberg.<engine>.queue.size, chromium.pdf, webhook.send. A failed request carries error.type; the status attribute and the errors counter are gone.
  • Each webhook and download attempt is an HTTP client span under the whole call's span, with server.address and a url.full stripped of credentials, query and fragment. Outbound URLs lose their query in errors and logs too.
  • The server span stays unset on success and 4xx, and sets Error on 5xx with the status code as error.type. OTEL_PROPAGATORS selects the propagators. Each written document is traced, its editing stages as child spans.

Security

  • The 8.40.0 fixes are in: IANA non-globally-reachable ranges are private for the *_DENY_PRIVATE_IPS checks, Chromium distrusts the compromised eMudhra roots from the first request, and the pinning proxy stays on with --chromium-host-resolver-rules.
  • Pinning proxy tunnels are bound to the server that accepted them. Refused outbound requests are logged with their context, redacted URL and rule.
  • Engine temporary files are collected by exact pattern, Chromium's profile directory is removed after a failed start, and handler panics answer 500 at once.

Removed

  • The deprecated --log-format, --log-enable-gcp-fields, --api-trace-header, --api-disable-health-check-logging, --chromium-incognito, --webhook-error-allow-list and --webhook-error-deny-list flags, and the --pdfengines-* and --prometheus-* ones.
  • UNOCONVERTER_BIN_PATH, replaced by LOK_BIN_PATH, and the pdfcpu, QPDF, pdftk and ExifTool paths.
  • downloadFrom[].embedded, facturxVersion and the merge bookmark options: the guide names their replacements.

Chore

  • Debian 13, Chromium 156 (146 on ppc64le), LibreOffice 26.8 from Debian's backports, Go 1.27, lok v0.0.6, litho v0.0.7.
  • CI runs the integration suite on every push to main and tests the Chromium and LibreOffice variants.
  • The Bruno collection mirrors every route.