Przejdź do głównej zawartości

Konfiguracja renderera Chrome dla NextPDF Artisan

Most uruchamia lokalny proces Chrome/Chromium i steruje nim za pomocą chrome-php/chrome. Skorzystaj z tej strony, aby skonfigurować to środowisko uruchomieniowe tak, by renderowanie do formatu Portable Document Format (PDF) kończyło się powodzeniem, i podjąć właściwe decyzje dotyczące kontenera oraz piaskownicy.

BrowserPool tworzy obiekt chrome-php/chromeBrowserFactory (opcjonalnie z jawną ścieżką do pliku binarnego) i uruchamia Chrome ze stałym zestawem flag: headless: true, keepAlive: true, windowSize: [1200, 800], sendSyncDefaultTimeout: renderTimeout * 1000 oraz niestandardowych flag wymienionych na stronie /integrations/artisan/configuration/. Następnie most steruje uruchomionym procesem za pośrednictwem protokołu Chrome DevTools Protocol (CDP). Most nie łączy się z oddzielnym procesem Chrome przez zdalny port debugowania, więc nie ma sieciowego punktu końcowego, który trzeba byłoby udostępniać lub uwierzytelniać. Chrome działa jako proces potomny procesu roboczego PHP. Test tests/Unit/Artisan/BrowserPoolTest.php::getBrowserCreatesAndReusesInstanceWithExpectedOptions weryfikuje dokładnie te opcje uruchomieniowe.

Zainstaluj wersję Chrome lub Chromium, którą może uruchomić użytkownik procesu roboczego:

Okno terminala
# Debian / Ubuntu
apt-get install -y chromium
# RHEL / Fedora
dnf install -y chromium
# Alpine (containers)
apk add --no-cache chromium nss freetype harfbuzz ttf-freefont

Sprawdź, czy plik binarny działa w trybie headless jako użytkownik procesu roboczego:

Okno terminala
chromium --headless --dump-dom about:blank

Kod zakończenia 0 i pusty model Document Object Model (DOM) oznaczają, że plik binarny oraz jego biblioteki współdzielone są obecne. Niezerowy kod zakończenia to ta sama awaria, którą most zgłasza jako ChromeRenderException. Najpierw rozwiąż problem na tym poziomie.

Automatyczne wykrywanie (domyślne zachowanie chrome-php/chrome) działa, gdy plik binarny znajduje się w standardowej ścieżce. Aby zachowanie w produkcji było deterministyczne, wskaż go jawnie:

$config = new ChromeRendererConfig(
chromeBinaryPath: '/usr/bin/chromium',
);

albo za pomocą konfiguracji tablicowej:

$config = ChromeRendererConfig::fromArray([
'chrome_binary' => '/usr/bin/chromium',
]);

Przygotowanie kontenera i decyzja dotycząca piaskownicy

Dział zatytułowany „Przygotowanie kontenera i decyzja dotycząca piaskownicy”

W kontenerze piaskownica Chrome oparta na mechanizmach systemu operacyjnego często nie może zainicjować się jako root / proces o identyfikatorze (PID) 1 bez dodatkowych uprawnień jądra. Masz do wyboru dwie ścieżki:

  1. Zachowaj piaskownicę (zalecane). Uruchom proces roboczy jako użytkownik inny niż root i przyznaj kontenerowi uprawnienia, których potrzebuje piaskownica Chrome (zwykle SYS_ADMIN lub profil seccomp zezwalający na tworzenie przestrzeni nazw użytkownika). Dzięki temu izolacja procesów Chrome pozostaje nienaruszona.
  2. Wyłącz piaskownicę. Ustaw no_sandbox: true. Chrome uruchamia się z flagą --no-sandbox. Usuwa to piaskownicę izolującą procesy Chrome: jest to rzeczywiste osłabienie izolacji, a nie kosmetyczna flaga. Stosuj to wyłącznie tam, gdzie piaskownicy nie da się włączyć, uruchamiaj Chrome jako użytkownik inny niż root wewnątrz ograniczonego kontenera i traktuj takie wdrożenie jako wymagające większego zaufania do danych wejściowych. Bariery sieciowe mostu, czyli Content Security Policy (CSP) i blokada CDP, w obu przypadkach pozostają w mocy, ale nie zastępują izolacji procesów. Jest to zgodne ze wskazówkami OWASP ASVS dotyczącymi najmniejszych uprawnień i izolacji przy renderowaniu niezaufanej zawartości.

Pełny opis granic, w tym tego, co piaskownica chroni, a czego nie, znajduje się na stronie /integrations/artisan/security-and-operations/. Niniejsza strona nie twierdzi, że wyłączenie piaskownicy jest bezpieczne.

FROM php:8.4-cli
RUN apt-get update && apt-get install -y --no-install-recommends \
chromium fonts-liberation \
&& rm -rf /var/lib/apt/lists/*
RUN useradd -m -u 10001 worker
USER worker
ENV CHROME_BINARY=/usr/bin/chromium
# Set CHROME_NO_SANDBOX=1 only if the sandbox cannot be enabled in your runtime.

Uruchamiaj proces roboczy jako worker (identyfikator użytkownika 10001), a nie jako root. Most stosuje już flagę --disable-dev-shm-usage, która bez dodatkowego dostrajania zapobiega częstej w kontenerach awarii powodowanej przez mały /dev/shm.

Most blokuje pobieranie zdalnych czcionek (--disable-remote-fonts i CSP). Zainstaluj potrzebne czcionki w systemie operacyjnym lub osadź je jako źródła data: Uniform Resource Identifier (URI) w regule @font-face wewnątrz defaultCss albo w dokumencie Hypertext Markup Language (HTML). Generowanie tekstu chińskiego, japońskiego i koreańskiego (CJK) wymaga zainstalowania w obrazie pakietu czcionek CJK (na przykład fonts-noto-cjk).

Użyj tej samodzielnej sondy, aby przetestować pełną ścieżkę działania mostu bez aplikacji hosta:

chrome-health.php
<?php
declare(strict_types=1);
use NextPDF\Artisan\ChromeHtmlRenderer;
use NextPDF\Artisan\ChromeRendererConfig;
require __DIR__ . '/vendor/autoload.php';
$renderer = new ChromeHtmlRenderer(
ChromeRendererConfig::fromArray([
'chrome_binary' => getenv('CHROME_BINARY') ?: null,
'no_sandbox' => (bool) getenv('CHROME_NO_SANDBOX'),
]),
);
$result = $renderer->render('<p>ok</p>', 200.0, 0.0);
fwrite(STDOUT, strlen($result->getPdfData()) > 0 ? "CHROME_OK\n" : "CHROME_EMPTY\n");
$renderer->close();

CHROME_OK potwierdza uruchomienie, renderowanie i import. Zgłoszony wyjątek wskazuje dokładny rodzaj awarii. Porównaj go z opisami na stronie /integrations/artisan/troubleshooting/. Podłącz tę sondę jako kontrolę gotowości we wdrożeniach z orkiestracją.

  • Uruchamiaj Chrome jako dedykowany użytkownik inny niż root.
  • Zastosuj limit pamięci na hoście; most ogranicza wzrost zużycia poprzez ponowne uruchomienie co 100 renderowań, ale górny limit hosta i tak jest wymagany.
  • Powiąż render_timeout z nadrzędnym budżetem żądania na każdej ścieżce dostępnej dla niezaufanych danych wejściowych.
  • Nie udostępniaj portu zdalnego debugowania Chrome. Most go nie używa, a otwarty port CDP jest nieuwierzytelnionym kanałem sterującym.
ObjawPrawdopodobna przyczynaGdzie szukać
ChromeNotAvailableExceptionchrome-php/chrome nie jest zainstalowany/integrations/artisan/install/
ChromeRenderException przy pierwszym renderowaniuBrak pliku binarnego / piaskownica nie może się zainicjowaćTa strona; /integrations/artisan/troubleshooting/
Pusty plik PDFBrak widocznego pola / awaria Chrome/integrations/artisan/troubleshooting/
Puste obrazy zdalneSieć celowo zablokowana/integrations/artisan/security-and-operations/
Okresowy wzrost opóźnieńPonowne uruchomienie co 100 renderowań/integrations/artisan/production-usage/
  • /integrations/artisan/install/
  • /integrations/artisan/configuration/
  • /integrations/artisan/security-and-operations/
  • /integrations/artisan/troubleshooting/
  • /integrations/artisan/production-usage/