コンテンツにスキップ

NextPDF Artisan 向け Chrome レンダラーのセットアップ

ブリッジは chrome-php/chrome を介して、ローカルの Chrome/Chromium プロセスを起動・制御します。このページでは、レンダリングを正常に行うために必要なランタイムのセットアップと、コンテナーおよびサンドボックスに関する判断ポイントを説明します。

BrowserPoolchrome-php/chromeBrowserFactory を構築し(バイナリパスは任意で明示指定できます)、固定されたフラグセットで Chrome を起動します: headless: truekeepAlive: truewindowSize: [1200, 800]sendSyncDefaultTimeout: renderTimeout * 1000、および /integrations/artisan/configuration/ ページに記載されているカスタムフラグです。その後、ブリッジは Chrome DevTools Protocol を介して、起動したプロセスを制御します。リモートデバッグポート経由で別途実行中の Chrome に接続することはないため、公開や認証が必要になるネットワークエンドポイントはありません。Chrome は PHP ワーカーの子プロセスとして実行されます。テスト tests/Unit/Artisan/BrowserPoolTest.php::getBrowserCreatesAndReusesInstanceWithExpectedOptions は、これらの起動オプションを厳密にアサートします。

ワーカーユーザーから実行できる Chrome または Chromium のビルドをインストールします:

Terminal window
# 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

ワーカーユーザーとしてヘッドレスで実行できることを確認します:

Terminal window
chromium --headless --dump-dom about:blank

終了コードが 0 で DOM が空であれば、バイナリと必要な共有ライブラリがそろっていることを意味します。0 以外の終了コードは、ブリッジでは ChromeRenderException として表面化するものと同じ失敗です。まずこの段階で修正してください。

自動検出(chrome-php/chrome のデフォルト)は、バイナリが標準パスにある場合に機能します。本番環境で決定性を確保するには、明示的に固定してください:

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

または配列設定を使用します:

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

コンテナー内では、追加のカーネルケーパビリティがないと、Chrome の OS サンドボックスが root / PID 1 として初期化できないことがよくあります。選択肢は 2 つあります:

  1. サンドボックスを維持する(推奨)。 ワーカーを非 root ユーザーとして実行し、Chrome のサンドボックスに必要なケーパビリティ(一般的には SYS_ADMIN、またはユーザー名前空間の作成を許可する seccomp プロファイル)をコンテナーに付与します。これにより、Chrome のプロセス分離がそのまま維持されます。
  2. サンドボックスを無効化する。 no_sandbox: true を設定します。Chrome は --no-sandbox を付けて起動します。これにより、Chrome のプロセス分離サンドボックスが除去されます。これは単なる形式的なフラグではなく、実質的に封じ込めが弱まります。サンドボックスを有効化できない場合に限って使用し、制約されたコンテナー内で Chrome を非 root ユーザーとして実行し、その配備では入力に対してより高い信頼を前提にするものとして扱ってください。ブリッジのネットワークバリア(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.

ワーカーは root ではなく worker(uid 10001)として実行してください。ブリッジはすでに --disable-dev-shm-usage フラグを適用しており、これによって、追加チューニングのないコンテナーでよく発生する /dev/shm が小さいことによるクラッシュを回避します。

ブリッジはリモートフォントの取得をブロックします(--disable-remote-fonts と CSP)。必要なフォントは OS レイヤーにインストールするか、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/ ページで照合してください。オーケストレーションされた配備では、これを readiness チェックとして組み込んでください。

  • 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/(本番環境での使用)