Zum Inhalt springen
getnextpdf.com

NextPDF serverlos ausführen

Die native, prozessinterne NextPDF-Core-Engine ist ein nahezu idealer serverloser Workload. Sie ist reines PHP, das innerhalb Ihres Prozesses läuftcomposer require nextpdf/core, ein Dokument bauen, die Bytes holen. Es gibt keine externe Binärdatei, die gestartet werden muss, keinen Headless-Browser, keinen Daemon, der am Leben gehalten werden muss, und keinen Socket zu einem Sidecar-Dienst. Eine Funktion, die ein PDF baut, startet kalt, führt Ihr PHP aus, gibt die Bytes zurück und beendet sich. Das bildet sauber auf AWS Lambda (über die Bref-Laufzeit), Google Cloud Run und AWS App Runner ab.

Diese Seite behandelt das Deployen dieser nativen Engine auf diese drei Laufzeiten und den kleinen Satz echter Constraints, den sie auferlegen:

  • Das Laufzeit-Dateisystem ist nicht dauerhaft: Lambda garantiert nur ein beschreibbares /tmp, während Container-Laufzeiten (Cloud Run, App Runner) ein ephemeres, container-gebundenes Dateisystem haben — in beiden Fällen müssen Schriften innerhalb des Deployment-Pakets oder -Images reisen und in PHP registriert werden (die Engine liest keine Schriftpfad-Umgebungsvariable);
  • Cold Starts zahlen für das Autoloading und jegliches Schrift-Warmup, also wärmen Sie die FontRegistry einmal pro Container, nicht pro Aufruf;
  • Paketgröße, Speicher und Timeout müssen auf den Build dimensioniert werden, nicht auf eine triviale Anfrage.

Diese Seite ist nur für die native Engine. Die Chrome-Bridge (writeHtmlChrome über das empfohlene Paket nextpdf/artisan) ist eine andere, schwerere Geschichte: Sie startet ein Headless-Chromium über symfony/process, das ein gewöhnliches Lambda-Zip oder ein schlanker Container nicht enthält. Chromium auf Lambda auszuführen bedeutet einen eigenen Layer mit dem Browser und seinen Shared Libraries, weit größere Pakete und viel längere Cold Starts — hier außerhalb des Geltungsbereichs. Die nackte Engine braucht nichts davon.

Bestätigen Sie vor dem Start, dass diese Teile vorhanden sind:

  • Ihre Anwendung hat eine eingecheckte composer.json und composer.lock, mit nextpdf/core als Abhängigkeit.
  • Sie verfügen über die Schriftdateien, die Sie einbetten möchten, und Sie sind berechtigt, sie einzubetten.
  • Sie verfügen über die Toolchain für Ihr Ziel — die Bref-CLI und das serverless-Framework für Lambda oder einen Container-Build für Cloud Run / App Runner.

Direkt aus dem Paket gelesen, erfordert nextpdf/core php: >=8.4 <9.0 und einen kleinen Satz von PHP-Erweiterungen — ext-mbstring, ext-intl, ext-gd, ext-openssl, ext-zlib und ext-curl. Die Standard-Bref-PHP-Layer bündeln jede einzelne davon. Die offiziellen php:8.4-Container-Images liefern openssl, curl und zlib ab Werk, aber mbstring, gd und intl sind nicht gebündelt — sie erfordern das Installieren von System-Abhängigkeiten und das Aktivieren der Erweiterungen mit docker-php-ext-install (siehe die Docker-Deployment-Anleitung). Auf Bref gibt es nichts Exotisches zu kompilieren; auf dem Container-Pfad aktivieren Sie diese drei Erweiterungen im Image-Build für die nackte Engine.

Was die Eignung sauber macht, ist das, was die Engine nicht tut:

  • Kein Subprozess für den Core-Pfad. Ein Dokument zu bauen und getPdfData() aufzurufen ist von Anfang bis Ende prozessinternes PHP. Die symfony/process-Abhängigkeit existiert für die optionale Chrome-Bridge, nicht für das native Rendern — die native PDF-Erzeugung startet nie einen Prozess.
  • Kein persistenter Zustand. Jeder Aufruf baut ein frisches Dokument und gibt Bytes zurück. Nichts muss zwischen Anfragen überleben außer dem warmen Container, den Sie für das Schrift-Warmup (unten) ausnutzen, sich für die Korrektheit aber nie darauf verlassen.
  • Kein beschreibbares Arbeitsverzeichnis nötig. Die Engine baut das PDF im Speicher und gibt es als Zeichenkette zurück; sie berührt die Festplatte nur, wenn Sie save() aufrufen. Auf serverlos tun Sie das nicht — Sie geben die Bytes zurück —, sodass das Fehlen eines dauerhaften Dateisystems den Build-Pfad nie trifft.

Der eine harte Constraint: kein dauerhaftes, beschreibbares Dateisystem

Abschnitt betitelt „Der eine harte Constraint: kein dauerhaftes, beschreibbares Dateisystem“

Das Deployment-Dateisystem ist nicht dauerhaft, aber das Modell unterscheidet sich je nach Laufzeit. AWS Lambda garantiert nur ein beschreibbares /tmp (512 MB standardmäßig, konfigurierbar bis 10 GB); der Rest des Funktions-Dateisystems ist schreibgeschützt. Container-Laufzeiten (Cloud Run, App Runner) haben ein ephemeres, container-gebundenes beschreibbares Dateisystem statt eines reinen /tmp-Modells — aber alles, was dort geschrieben wird, geht verloren, wenn der Container recycelt wird, sodass es Arbeitsspeicher (Scratch) ist, kein Speicher. In jedem Fall bevorzugen Sie /tmp oder ein konfiguriertes Volume zum Zwischenlagern und verlassen sich nie auf Schreibvorgänge in den Anwendungs-Image-Pfad als dauerhaften Speicher. Daraus folgen zwei Konsequenzen.

Rufen Sie save() nie in der Erwartung einer dauerhaften Ausgabe auf. NextPDF\Core\Document stellt sowohl save(string $path): void als auch getPdfData(): string bereit. Auf serverlos verwenden Sie getPdfData() und geben die Bytes zurück oder laden sie hoch — behandeln Sie einen Schreibvorgang in das Anwendungsverzeichnis nicht als persistenten Speicher. Wenn Sie eine Datei zwischenlagern müssen (zum Beispiel für einen Multipart-Upload zu Objektspeicher), schreiben Sie unter /tmp (oder ein konfiguriertes Volume) und räumen auf, wobei Sie sich daran erinnern, dass dieser Scratch-Bereich auf einem warmen Container über Aufrufe hinweg bestehen bleibt und auf sein Größenlimit angerechnet wird.

use NextPDF\Core\Document;
// Right for serverless: get the bytes, return or upload them.
$pdf = $document->getPdfData(); // string of PDF bytes, built in memory
// Avoid on serverless: save() writes to disk. On Lambda the application
// directory is read-only; on Cloud Run / App Runner it is writable but
// ephemeral (lost on container recycle). Neither is durable storage.
// $document->save('/var/task/out.pdf'); // not durable — return the bytes instead

Installieren Sie keine OS-Schriften zur Laufzeit und verlassen Sie sich nicht auf die automatische Schrifterkennung; bündeln Sie Ihre Schriftdateien für die Produktion. Auf Lambda blockiert das schreibgeschützte Dateisystem apt-get install fonts-* rundheraus; auf einer Container-Laufzeit landet jede Laufzeit-Installation auf einem ephemeren Dateisystem und geht beim nächsten Recycle verloren. Und es würde ohnehin nicht helfen, denn die native Engine liest keine OS-/fontconfig-Schriften — sie löst Schriften nur aus Dateien auf, die Sie registrieren. Für die Produktion müssen die Schriftdateien daher innerhalb des Deployment-Artefakts ausgeliefert werden. Wenn Sie Schriftdateien bewusst nach /tmp oder in ein konfiguriertes Volume holen, müssen Sie sie explizit bei der Schrift-Registry registrieren und die zusätzlichen Cold-Start- und Zuverlässigkeitskosten in Kauf nehmen — es ist kein empfohlenes Produktionsmuster.

Schriften im Paket oder Image bündeln und registrieren

Abschnitt betitelt „Schriften im Paket oder Image bündeln und registrieren“

Die native Engine löst Schriften aus Schriftdateien über die NextPDF\Typography\FontRegistry auf, nicht aus fontconfig oder OS-installierten Schriften. Auf serverlos ist das nicht verhandelbar: Es gibt nach dem Deploy kein persistentes Dateisystem, auf das man Schriften legen könnte, sodass sie innerhalb des Pakets (eines Lambda-Zips oder -Layers) oder innerhalb des Images (Cloud Run / App Runner) ausgeliefert werden.

Bündeln Sie Ihre .ttf- / .otf- / .ttc-Dateien unter einem Verzeichnis in Ihrem Projekt — resources/fonts/ ist die Konvention —, sodass sie im Artefakt enthalten sind. Registrieren Sie dann dieses Verzeichnis in PHP. Die Engine liest keine Schriftpfad-Umgebungsvariable: NEXTPDF_FONTS_PATH ist der Standardwert des fonts_path-Konfigurationsschlüssels des Pakets nextpdf/laravel (env('NEXTPDF_FONTS_PATH', resource_path('fonts'))) und wird nur von dieser Framework-Integration verbraucht, nicht von nextpdf/core. Eine nackte Funktion muss die Registry mit dem gebündelten Verzeichnis konstruieren:

use NextPDF\Typography\FontRegistry;
use NextPDF\Core\DocumentFactory;
use NextPDF\Graphics\ImageRegistry;
// Register the directory the deployment artifact bundled the fonts into.
// On Lambda/Bref the code root is /var/task; adjust for your runtime.
$registry = new FontRegistry(__DIR__ . '/resources/fonts');
// (equivalently, $registry->addFontDirectory(__DIR__ . '/resources/fonts');)
$factory = new DocumentFactory($registry, new ImageRegistry(maxCacheBytes: 0));
$document = $factory->create();

Das ist die gesamte serverlose Angelegenheit für Schriften. Die Dateibenennungsregeln, die vollständige Registry-API und die Handhabung des nicht-dauerhaften Dateisystems liegen auf der dedizierten Seite — duplizieren Sie sie nicht hier. Lesen Sie Schriften für die native Engine in der Produktion bereitstellen für das vollständige Muster und registrieren Sie dasselbe Verzeichnis, das Sie gebündelt haben. Die Docker-Deployment-Anleitung behandelt das äquivalente image-seitige Bündeln für den Cloud-Run- / App-Runner-Fall.

Cold Starts: die FontRegistry einmal pro Container wärmen

Abschnitt betitelt „Cold Starts: die FontRegistry einmal pro Container wärmen“

Ein Cold Start zahlt für das PHP-Bootstrap, Composers optimierten Autoloader und jegliches Schrift-Parsing, das der erste Build auslöst. Das Bootstrap können Sie nicht vermeiden, aber Sie können die Schriftarbeit aus dem heißen Pfad herausnehmen und über warme Aufrufe hinweg wiederverwenden.

Konstruieren Sie die FontRegistry und DocumentFactory einmal, außerhalb des Handlers, sodass sie für die Lebensdauer des Containers existieren und bei jedem warmen Aufruf wiederverwendet werden. Rufen Sie optional warmup() mit den Schriftdateien auf, von denen Sie wissen, dass Sie sie verwenden werden, sodass sie während der Initialisierung geparst werden statt beim ersten Rendern, und sperren Sie dann die Registry mit lock(), sodass ihr geparster Zustand eingefroren ist und keine Mutation pro Aufruf eine Race-Bedingung erzeugen kann:

use NextPDF\Typography\FontRegistry;
use NextPDF\Core\DocumentFactory;
use NextPDF\Graphics\ImageRegistry;
// Container-scoped, built once at cold start (module scope, not per request).
$fontsDir = __DIR__ . '/resources/fonts';
$registry = new FontRegistry($fontsDir);
// Parse the fonts you will actually use now, so the first render does not.
$registry->warmup([
$fontsDir . '/liberation/LiberationSans-Regular.ttf',
$fontsDir . '/liberation/LiberationSans-Bold.ttf',
]);
// Freeze the parsed state for the life of the warm container.
$registry->lock();
$factory = new DocumentFactory($registry, new ImageRegistry(maxCacheBytes: 0));
// Each invocation: fresh document from the shared, warm factory.
$handler = static function (array $event) use ($factory): string {
$document = $factory->create();
$document->addPage();
$document->cell(0, 10, 'Hello from serverless', newLine: true);
return $document->getPdfData();
};

Rufen Sie warmup() vor lock() auf — die Registry ist eingefroren, sobald sie gesperrt ist, sodass ein Warmup danach einen Konfigurationsfehler auslöst. Behandeln Sie eine Schrift, die beim Warmup nicht geladen werden kann, als Deploy-Zeit-Fehler, nicht als Laufzeitdetail: Validieren Sie, dass jeder Schriftpfad, den Sie zu wärmen beabsichtigen, beim Start tatsächlich existiert und geparst werden kann, und lassen Sie das Deploy (oder Ihren Health-Check) scheitern, wenn einer das nicht tut, statt einen vertippten Pfad später als fehlende Glyphen auftauchen zu lassen. Halten Sie die Warmup-Liste auf die Schriften beschränkt, die ein typischer Aufruf braucht; eine große Familie zu wärmen, die Sie selten verwenden, verlängert nur jeden Cold Start.

Bref stellt die PHP-Laufzeit für Lambda als veröffentlichten Layer und als serverless.yml-Plugin bereit. Die php-84-Laufzeit liefert bereits die Erweiterungen, die nextpdf/core braucht, sodass Sie Ihren Code und Ihre Schriften deployen und eine Funktion auf einen Handler zeigen lassen. Eine minimale serverless.yml:

service: nextpdf-serverless
provider:
name: aws
region: us-east-1
runtime: provided.al2023
plugins:
- ./vendor/bref/bref
functions:
generate:
handler: handler.php
description: Generate a PDF with the native NextPDF engine
runtime: php-84
memorySize: 1024 # size to the build; see "Sizing" below
timeout: 30 # seconds; raise for large documents
# The Lambda filesystem is read-only except /tmp. Fonts ship in the
# package under resources/fonts and are registered in the handler.

Der Handler baut das Dokument mit der warmen, container-gebundenen Factory und gibt die Bytes zurück. Für eine HTTP-API geben Sie sie base64-codiert mit dem application/pdf-Content-Type zurück, sodass API Gateway den Body als binär behandelt; für einen Invoke- oder Queue-Trigger laden Sie die Bytes in Objektspeicher hoch und geben den Key zurück:

handler.php (outline)
<?php
declare(strict_types=1);
require __DIR__ . '/vendor/autoload.php';
use NextPDF\Core\DocumentFactory;
use NextPDF\Graphics\ImageRegistry;
use NextPDF\Typography\FontRegistry;
// --- Cold-start: built once per container, reused across warm invocations. ---
$fontsDir = __DIR__ . '/resources/fonts';
$registry = new FontRegistry($fontsDir);
$registry->warmup([$fontsDir . '/liberation/LiberationSans-Regular.ttf']);
$registry->lock();
$factory = new DocumentFactory($registry, new ImageRegistry(maxCacheBytes: 0));
// --- Per-invocation handler. ---
return static function (array $event) use ($factory): array {
$document = $factory->create();
$document->addPage();
$document->cell(0, 10, 'Invoice', newLine: true);
// getPdfData() materializes the whole PDF in memory and returns it.
$bytes = $document->getPdfData();
return [
'statusCode' => 200,
'isBase64Encoded' => true,
'headers' => ['Content-Type' => 'application/pdf'],
'body' => base64_encode($bytes),
];
};

Verifizieren Sie, dass das Paket eine gesunde Umgebung enthält, bevor Sie Traffic darauf leiten. nextpdf/core liefert eine CLI aus, die unter vendor/bin/nextpdf installiert wird und deren doctor-Befehl genau über die Erweiterungen berichtet, die die Engine braucht. Führen Sie ihn einmal gegen dasselbe Laufzeit-Image oder denselben Layer aus, um zu bestätigen, dass PHP 8.4 und jede erforderliche Erweiterung vorhanden ist.

Cloud Run und App Runner führen einen Container aus statt einer gezippten Funktion, sodass der Build das Docker-Image aus Eine NextPDF-Anwendung containerisieren ist, kein Bref-Paket. Die Constraints der nativen Engine sind identisch: Schriften in das Image bündeln, das gebündelte Verzeichnis in PHP registrieren, unprivilegiert laufen und das Dateisystem als nicht-dauerhaft behandeln. Anders als Lambdas reines /tmp-Modell hat ein Cloud-Run- / App-Runner-Container ein ephemeres, container-gebundenes beschreibbares Dateisystem — aber es wird bei jedem Recycle zurückgesetzt, also verwenden Sie /tmp (ein tmpfs auf Cloud Run) oder ein konfiguriertes Volume für Scratch und verlassen sich nie auf Schreibvorgänge in den Anwendungs-Image-Pfad als dauerhaften Speicher.

Die Unterschiede zu Lambda sind betrieblich, nicht strukturell:

  • Der Container kann über Anfragen hinweg warm bleiben unter einer Concurrency-Einstellung, sodass sich das oben gezeigte Warmup der container-gebundenen FontRegistry/DocumentFactory über viele Anfragen auszahlt, nicht nur über den nächsten Aufruf.
  • Sie bedienen über HTTP (eine FPM- oder eingebaute PHP-Server-SAPI) statt eines Invoke-Events, sodass Sie die Bytes über die Antwort Ihres Frameworks zurückgeben. Für ein großes Dokument geben Sie sie als gestreamte Antwort zurück — siehe Ein großes generiertes PDF als HTTP-Antwort streamen.
  • Das Anfrage-Timeout und der Speicher werden am Dienst gesetzt (Cloud-Run-Dienst-Timeout / -Speicher; App-Runner-Instanzkonfiguration) statt pro Funktion.

Alles andere — der Erweiterungssatz, die Schriftregistrierung, der getPdfData()-Ausgabeaufruf — ist derselbe Code wie der Lambda-Handler.

  • Paket- und Image-Größe. Das Artefakt trägt vendor/ (nur Produktion — installieren mit --no-dev) und Ihre gebündelten Schriften. Schriften dominieren: Eine vollständige CJK-Familie umfasst zig Megabyte. Liefern Sie nur die Schriften aus, die Sie tatsächlich rendern, um das Lambda-Paket unter seinen Limits und das Image klein zu halten, was auch die Cold Starts verkürzt. Die gebündelte Liberation-Familie (resources/fonts/liberation/) ist klein und deckt die metrikkompatible Helvetica-Ersetzung ab.
  • Speicher. getPdfData() baut das gesamte Dokument im Speicher und gibt es als eine Zeichenkette zurück, sodass der Speicher-Peak ungefähr der Größe eines fertigen PDFs plus dem Arbeitsbereich des Builds entspricht. Dimensionieren Sie den Funktions-/Container-Speicher auf das größte Dokument, das Sie erzeugen, nicht auf einen Durchschnitt. Auf Lambda skaliert der Speicher auch die CPU, sodass mehr Speicher oft einen schnelleren Build und einen günstigeren Lauf bedeutet, trotz der höheren Rate pro Millisekunde — messen Sie beides. Ein Dokument von wenigen Seiten ist bei 512–1024 MB komfortabel; bildlastige oder mehrseitige Dokumente brauchen mehr.
  • Timeout. Der Build, nicht die Übertragung, dominiert das Anfragebudget. Setzen Sie das Funktions-Timeout mit Spielraum über die Worst-Case-Build-Zeit. Wenn ein Dokument groß genug ist, um ein Timeout zu riskieren, verschieben Sie die Erzeugung auf einen asynchronen Trigger (ein queue-gestütztes Lambda oder einen Cloud-Run-Job), der das Ergebnis in Objektspeicher schreibt, statt eine synchrone Anfrage zu blockieren.
  • /tmp-Größe. Wenn Sie irgendetwas unter /tmp zwischenlagern, berücksichtigen Sie sein Größenlimit und erinnern sich daran, dass es über warme Aufrufe hinweg bestehen bleibt — räumen Sie auf, sonst füllt ein langlebiger Container es allmählich.
  • Kein dauerhaftes save() in das App-Verzeichnis. Das Deployment-Dateisystem ist nicht dauerhaft — Lambdas App-Verzeichnis ist schreibgeschützt (nur /tmp akzeptiert Schreibvorgänge), und ein Cloud-Run- / App-Runner-Container-Dateisystem ist beschreibbar, aber ephemer. Verwenden Sie getPdfData() und geben/laden Sie die Bytes zurück bzw. hoch; lagern Sie unter /tmp oder einem konfigurierten Volume zwischen, wenn Sie müssen.
  • Verlassen Sie sich nicht auf die automatische Schrifterkennung. Installieren Sie keine OS-Schriften zur Laufzeit und verlassen Sie sich nicht auf die automatische Schrifterkennung; bündeln Sie Ihre Schriftdateien für die Produktion. Die native Engine liest keine OS-/fontconfig-Schriften — sie löst nur Dateien auf, die Sie registrieren. Wenn Sie Schriftdateien bewusst nach /tmp oder in ein konfiguriertes Volume holen, müssen Sie sie explizit bei der Schrift-Registry registrieren und die zusätzlichen Cold-Start- und Zuverlässigkeitskosten in Kauf nehmen. Bündeln und registrieren Sie die Dateien. Siehe die oben verlinkte Schriftenseite.
  • NEXTPDF_FONTS_PATH bewirkt nichts für die nackte Engine. Es ist der Konfigurationsstandard des Pakets nextpdf/laravel, keine Variable, die nextpdf/core liest. Ein nackter Bref-Handler, der nur diese Variable setzt, registriert keine Schriften und rendert Tofu.
  • Die Chrome-Bridge passt nicht in eine gewöhnliche Funktion. writeHtmlChrome braucht ein Headless-Chromium und den symfony/process-Subprozess-Pfad. Chromium auf Lambda zu bringen erfordert einen eigenen Layer mit dem Browser und seinen Bibliotheken, weit größere Pakete und lange Cold Starts. Die native Engine und writeHtml brauchen nichts davon — bevorzugen Sie sie auf serverlos.
  • Die Cold-Start-Kosten sind Autoload plus Schrift-Parsing. Verwenden Sie --optimize-autoloader bei der Produktionsinstallation und wärmen Sie die Registry einmal pro Container. Wärmen Sie keine Schriften, die Sie selten verwenden.
  • API Gateway braucht Binärbehandlung. Geben Sie isBase64Encoded: true mit Content-Type: application/pdf zurück und konfigurieren Sie die API so, dass sie application/pdf als binären Media-Type behandelt, sonst empfängt der Client beschädigte Bytes.
  • Premium und ionCube sind eine schwerere Artefakt-Angelegenheit. ionCube-codierte NextPDF-Pro- / Enterprise-Builds benötigen den ionCube-Loader, abgestimmt auf den exakten PHP-Build in der Laufzeit, den ein Standard-Bref-Layer nicht enthält. Das ist für ein Core-Serverless-Deploy außerhalb des Geltungsbereichs.
  • Liefern Sie keine Dev-Abhängigkeiten aus. Installieren Sie mit --no-dev, sodass die Test- und Analysewerkzeuge nie in das Funktionspaket oder Image gelangen.
  • Validieren Sie Eingaben vor dem Bauen. Ein PDF-Build, der von einer Anfrage-Eingabe gesteuert wird, ist ein Vektor für Speichererschöpfung; weisen Sie Eingaben außerhalb des Bereichs oder von übergroßer Größe an der Grenze zurück, bevor irgendeine Build-Arbeit läuft, und beschränken Sie die Concurrency, sodass hoher Traffic den Speicher-Peak nicht zu einem Out-of-Memory-Fehler vervielfacht.
  • Halten Sie Schriften und Lizenzen aus öffentlichen Artefakten heraus. Bündeln Sie nur Schriften, die Sie einbetten dürfen, und backen Sie niemals eine Premium-Lizenzdatei in ein öffentlich gepushtes Image oder Layer ein — liefern Sie sie stattdessen zur Laufzeit über einen Umgebungswert oder einen Secret-Manager.
  • Least Privilege. Geben Sie der Funktion/dem Dienst nur die IAM-Berechtigungen, die sie/er braucht (zum Beispiel Schreibzugriff auf den einen Ausgabe-Bucket), und führen Sie den Container unprivilegiert aus, wie die Docker-Anleitung zeigt.

Diese Anleitung erhebt keinen normativen Standardanspruch. Die Plattformfakten werden direkt aus dem Paket nextpdf/core gelesen: der php: >=8.4 <9.0-Constraint und die erforderlichen Erweiterungen ext-mbstring, ext-intl, ext-gd, ext-openssl, ext-zlib und ext-curl. Der Standard-Bref-PHP-8.4-Laufzeit-Layer bündelt alle sechs; das offizielle php:8.4-Image liefert openssl, curl und zlib, aber mbstring, gd und intl müssen im Image-Build mit docker-php-ext-install installiert und aktiviert werden (siehe die Docker-Seite). Der Ausgabeaufruf ist die echte Core-Oberfläche NextPDF\Core\Document::getPdfData(): string (sein Festplatten-Pendant ist save(string $path): void). Schriften werden über NextPDF\Typography\FontRegistry registriert — sein Verzeichnis-Konstruktorargument / addFontDirectory(), mit warmup(array $fontFiles) und lock() für das Cold-Start-Muster —, verdrahtet über NextPDF\Core\DocumentFactory::create(). NEXTPDF_FONTS_PATH ist der fonts_path-Konfigurationsschlüssel des Pakets nextpdf/laravel (env('NEXTPDF_FONTS_PATH', resource_path('fonts'))), keine Variable, die nextpdf/core liest. Der nextpdf-CLI-doctor-Befehl ist als "bin": ["bin/nextpdf"] im Paket deklariert und in einer konsumierenden App unter vendor/bin/nextpdf installiert. Die Bref-Laufzeitnamen und das Verhalten von AWS Lambda / Cloud Run / App Runner sind die dokumentierten Features dieser Anbieter.