Перейти к содержимому

Настройка рендерера Chrome для NextPDF Artisan

Мост запускает локальный процесс Chrome/Chromium и управляет им через chrome-php/chrome. Используйте эту страницу, чтобы настроить среду выполнения для корректной отрисовки в формат Portable Document Format (PDF) и принять правильные решения по контейнерам и песочнице.

BrowserPool создаёт chrome-php/chromeBrowserFactory (при необходимости с явным путём к исполняемому файлу) и запускает Chrome с фиксированным набором флагов: headless: true, keepAlive: true, windowSize: [1200, 800], sendSyncDefaultTimeout: renderTimeout * 1000 и пользовательскими флагами, перечисленными на странице /integrations/artisan/configuration/. Затем мост управляет запущенным процессом по протоколу Chrome DevTools Protocol (CDP). Он не подключается к отдельному процессу Chrome через порт удалённой отладки, поэтому не появляется сетевая конечная точка, которую пришлось бы открывать или аутентифицировать. Chrome работает как дочерний процесс рабочего процесса PHP. Тест tests/Unit/Artisan/BrowserPoolTest.php::getBrowserCreatesAndReusesInstanceWithExpectedOptions проверяет именно эти параметры запуска.

Установите сборку Chrome или Chromium, которую сможет запускать пользователь рабочего процесса:

Окно терминала
# 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

Убедитесь, что браузер запускается в headless-режиме от имени пользователя рабочего процесса:

Окно терминала
chromium --headless --dump-dom about:blank

Код завершения 0 с пустой объектной моделью документа (DOM) означает, что исполняемый файл и его разделяемые библиотеки доступны. Ненулевой код завершения — тот же сбой, который мост представляет как ChromeRenderException. Сначала устраните проблему на этом уровне.

Автоматическое обнаружение (поведение по умолчанию в chrome-php/chrome) работает, когда исполняемый файл находится в стандартном пути. Для детерминированного поведения в рабочей среде задайте путь явно:

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

или через конфигурацию в формате массива:

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

Подготовка контейнера и решение о песочнице

Заголовок раздела «Подготовка контейнера и решение о песочнице»

В контейнере песочница операционной системы Chrome часто не может инициализироваться от имени root / с идентификатором процесса (PID) 1 без дополнительных возможностей ядра. Есть два варианта:

  1. Сохраните песочницу (предпочтительно). Запускайте рабочий процесс от имени пользователя без прав root и предоставьте контейнеру возможности, необходимые песочнице Chrome (обычно SYS_ADMIN или профиль seccomp, разрешающий создание пользовательских пространств имён). Так изоляция процессов Chrome остаётся без изменений.
  2. Отключите песочницу. Задайте no_sandbox: true. Chrome запускается с флагом --no-sandbox. Это отключает песочницу изоляции процессов Chrome: уровень изоляции действительно снижается, это не косметический флаг. Используйте этот вариант только там, где песочницу нельзя включить; запускайте Chrome от имени пользователя без прав root внутри ограниченного контейнера и рассматривайте такое развёртывание как требующее более высокого доверия к входным данным. Сетевые барьеры моста — Content Security Policy (CSP) и блокировка CDP — в любом случае остаются в силе, но они не заменяют изоляцию процессов. Это соответствует рекомендациям OWASP ASVS по наименьшим привилегиям и изоляции при отрисовке недоверенного содержимого.

Полное описание границ, включая то, от чего песочница защищает и от чего не защищает, приведено на странице /integrations/artisan/security-and-operations/. Эта страница не утверждает, что отключать песочницу безопасно.

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.

Запускайте рабочий процесс от имени worker (идентификатор пользователя 10001), а не root. Мост уже применяет флаг --disable-dev-shm-usage, который предотвращает сбой из-за малого /dev/shm, часто встречающийся в контейнерах без дополнительной настройки.

Мост блокирует загрузку удалённых шрифтов (--disable-remote-fonts и CSP). Установите нужные шрифты на уровне операционной системы либо встройте их как источники data: с унифицированным идентификатором ресурса (URI) @font-face внутри defaultCss или языка гипертекстовой разметки (HTML). Для вывода на китайском, японском и корейском языках (CJK) в образе должен быть установлен пакет шрифтов CJK, например fonts-noto-cjk.

Используйте эту автономную проверку, чтобы пройти весь путь через мост без основного приложения:

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 подтверждает запуск, отрисовку и импорт. Выброшенное исключение указывает точную причину сбоя. Сопоставьте его со страницей /integrations/artisan/troubleshooting/. Подключите эту проверку как проверку готовности в оркестрируемых развёртываниях.

  • Запускайте Chrome от имени отдельного пользователя без прав root.
  • Установите ограничение памяти на хосте; мост сдерживает рост перезапуском после 100 операций отрисовки, но верхняя граница на хосте всё равно необходима.
  • Сочетайте render_timeout с вышестоящим бюджетом запроса на любом пути, доступном для недоверенных входных данных.
  • Не открывайте порт удалённой отладки Chrome. Мост его не использует, а открытый порт CDP — это канал управления без аутентификации.
СимптомВероятная причинаГде искать
ChromeNotAvailableExceptionchrome-php/chrome не установленУстановка: /integrations/artisan/install/
ChromeRenderException при первой отрисовкеИсполняемый файл отсутствует / песочница не может инициализироватьсяЭта страница; /integrations/artisan/troubleshooting/
Пустой PDFНет видимого блока / сбой ChromeУстранение неполадок: /integrations/artisan/troubleshooting/
Пустые удалённые изображенияСеть заблокирована намеренноБезопасность и эксплуатация: /integrations/artisan/security-and-operations/
Периодический всплеск задержкиПерезапуск после 100 операций отрисовкиЭксплуатация в рабочей среде: /integrations/artisan/production-usage/
  • Установка: /integrations/artisan/install/
  • Настройка: /integrations/artisan/configuration/
  • Безопасность и эксплуатация: /integrations/artisan/security-and-operations/
  • Устранение неполадок: /integrations/artisan/troubleshooting/
  • Эксплуатация в рабочей среде: /integrations/artisan/production-usage/