Lewati ke konten

Penyiapan renderer Chrome untuk NextPDF Artisan

Jembatan ini meluncurkan dan mengendalikan proses Chrome/Chromium lokal melalui chrome-php/chrome. Gunakan halaman ini untuk menyiapkan runtime tersebut agar proses render Portable Document Format (PDF) berjalan dengan baik, serta untuk mengambil keputusan kontainer dan sandbox yang tepat.

BrowserPool membuat sebuah chrome-php/chromeBrowserFactory (opsional dengan jalur biner eksplisit) dan meluncurkan Chrome dengan serangkaian flag tetap: headless: true, keepAlive: true, windowSize: [1200, 800], sendSyncDefaultTimeout: renderTimeout * 1000, serta flag khusus yang tercantum pada halaman /integrations/artisan/configuration/. Jembatan kemudian mengendalikan proses yang diluncurkan tersebut melalui Chrome DevTools Protocol (CDP). Jembatan tidak terhubung ke proses Chrome terpisah melalui porta debugging jarak jauh, sehingga tidak ada endpoint jaringan yang perlu diekspos atau diautentikasi. Chrome berjalan sebagai proses anak dari worker PHP. Tes tests/Unit/Artisan/BrowserPoolTest.php::getBrowserCreatesAndReusesInstanceWithExpectedOptions memverifikasi opsi peluncuran ini secara tepat.

Instal build Chrome atau Chromium yang dapat dijalankan oleh user worker:

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

Pastikan biner tersebut dapat berjalan secara headless sebagai user worker:

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

Exit code 0 dengan Document Object Model (DOM) kosong berarti biner beserta pustaka bersamanya tersedia. Exit code bukan nol adalah kegagalan yang sama yang ditampilkan jembatan sebagai ChromeRenderException. Perbaiki di sini terlebih dahulu.

Deteksi otomatis (perilaku standar chrome-php/chrome) berfungsi ketika biner berada di jalur standar. Agar perilaku produksi deterministik, tetapkan secara eksplisit:

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

atau melalui konfigurasi array:

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

Di dalam kontainer, sandbox Chrome di level sistem operasi sering kali tidak dapat diinisialisasi sebagai root / process identifier (PID) 1 tanpa kapabilitas kernel tambahan. Anda memiliki dua opsi:

  1. Pertahankan sandbox (disarankan). Jalankan worker sebagai user non-root, dan berikan kontainer kapabilitas yang dibutuhkan oleh sandbox Chrome (umumnya SYS_ADMIN, atau profil seccomp yang mengizinkan pembuatan user-namespace). Cara ini menjaga isolasi proses Chrome tetap utuh.
  2. Nonaktifkan sandbox. Setel no_sandbox: true. Chrome diluncurkan dengan --no-sandbox. Ini menghapus sandbox isolasi-proses Chrome: pengurangan nyata pada pengungkungan, bukan sekadar flag kosmetik. Gunakan opsi ini hanya jika sandbox tidak dapat diaktifkan, jalankan Chrome sebagai user non-root di dalam kontainer yang dibatasi, dan perlakukan deployment tersebut sebagai penerapan yang menuntut tingkat kepercayaan lebih tinggi terhadap masukan. Penghalang jaringan jembatan, yaitu Content Security Policy (CSP) dan pemblokiran CDP, tetap berlaku dalam kedua kasus, tetapi keduanya tidak menggantikan isolasi proses. Hal ini selaras dengan panduan hak istimewa terkecil dan isolasi OWASP ASVS untuk merender konten yang tidak tepercaya.

Rincian batasan selengkapnya, termasuk apa yang dilindungi dan tidak dilindungi oleh sandbox, tersedia pada halaman /integrations/artisan/security-and-operations/. Halaman ini tidak mengeklaim bahwa menonaktifkan sandbox itu aman.

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.

Jalankan worker sebagai worker (user ID 10001), bukan root. Jembatan sudah menerapkan flag --disable-dev-shm-usage, yang mencegah crash akibat /dev/shm berukuran kecil—hal yang umum terjadi di kontainer tanpa penyetelan lebih lanjut.

Jembatan memblokir pengambilan fon jarak jauh (--disable-remote-fonts dan CSP). Instal fon yang Anda butuhkan pada lapisan sistem operasi, atau sematkan sebagai sumber Uniform Resource Identifier (URI) data: untuk @font-face di dalam defaultCss atau Hypertext Markup Language (HTML). Keluaran untuk bahasa Tionghoa, Jepang, dan Korea (CJK) memerlukan paket fon CJK (misalnya fonts-noto-cjk) yang terpasang di image.

Gunakan probe mandiri ini untuk menguji alur jembatan secara penuh tanpa aplikasi host:

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 mengonfirmasi peluncuran, render, dan impor. Eksepsi yang dilemparkan menunjukkan kegagalan spesifik. Cocokkan dengan panduan pada halaman /integrations/artisan/troubleshooting/. Jadikan probe ini sebagai pemeriksaan kesiapan (readiness check) pada penerapan yang terorkestrasi.

  • Jalankan Chrome sebagai user non-root khusus.
  • Terapkan batas memori host; jembatan membatasi pertumbuhan dengan restart setiap 100 render, tetapi batas atas di sisi host tetap diperlukan.
  • Selaraskan render_timeout dengan anggaran permintaan di sisi hulu pada setiap jalur yang dapat dijangkau oleh masukan tidak tepercaya.
  • Jangan mengekspos porta debugging jarak jauh Chrome. Jembatan tidak menggunakannya, dan porta CDP yang terbuka merupakan saluran kendali tanpa autentikasi.
GejalaKemungkinan penyebabTempat memeriksa
ChromeNotAvailableExceptionchrome-php/chrome tidak terpasang/integrations/artisan/install/
ChromeRenderException pada render pertamaBiner tidak ada / sandbox tidak dapat diinisialisasiHalaman ini; /integrations/artisan/troubleshooting/
PDF kosongTidak ada kotak yang terlihat / Chrome crash/integrations/artisan/troubleshooting/
Gambar jarak jauh kosongJaringan diblokir secara sengaja/integrations/artisan/security-and-operations/
Lonjakan latensi berkalaRestart setiap 100 render/integrations/artisan/production-usage/
  • /integrations/artisan/install/
  • /integrations/artisan/configuration/
  • /integrations/artisan/security-and-operations/
  • /integrations/artisan/troubleshooting/
  • /integrations/artisan/production-usage/