Certainly! This is a well-known issue with Puppeteer/Browsershot when used on Forge (or similar shared hosts) because headless Chrome (used for PDF rendering) can sometimes run out of system resources, or its processes don’t get cleaned up. Your problem of "works after config:cache but crashes after some time" is a clue that it’s environmental, not code logic.
Problem Analysis
- Chrome/Chromium can't start - Error:
Failed to launch the browser process. - Error mentions:
/system.slice/php8.4-fpm.service is not a snap cgroup ... - Works after
php artisan config:cache(possibly temporarily cleans up/stops old processes). - Fails after a while (zombie Chrome processes, lack of permissions, or resource leak).
Solution Steps
1. Ensure chromium's dependencies are installed
On Forge you must install all required dependencies for headless Chrome:
SSH to your server and run:
sudo apt-get update
sudo apt-get install -y \
chromium-browser \
libappindicator3-1 \
libasound2 \
libatk-bridge2.0-0 \
libatk1.0-0 \
libcups2 \
libdbus-1-3 \
libdrm2 \
libgbm1 \
libnspr4 \
libnss3 \
libxcomposite1 \
libxdamage1 \
libxrandr2 \
xdg-utils \
libu2f-udev \
libvulkan1 \
libxss1 \
fonts-liberation \
fonts-unfonts-core
Many Chrome errors on Forge are resolved just by this.
2. Set CHROME_PATH in your .env
Tell Browsershot/Puppeteer exactly where Chromium is located:
Add in your .env:
CHROME_PATH="/usr/bin/chromium-browser"
(In newer Ubuntu it may be /usr/bin/chromium -- check with which chromium-browser or which chromium.)
3. Set up Browsershot to use the correct binary
If not already, specify the binary in your PDF/Browsershot config:
use Spatie\Browsershot\Browsershot;
Browsershot::setChromePath(env('CHROME_PATH') ?: '/usr/bin/chromium-browser');
Or directly within your PDF config if package supports it:
return Pdf::view('PDF.invoice', compact('invoice'))
->format('a4')
->landscape()
->name("{$invoice->invoice_no}-{$invoice->created_at->format('Y-m-d')}.pdf")
->withBrowsershot(
fn ($browsershot) => $browsershot->setChromePath(env('CHROME_PATH', '/usr/bin/chromium-browser'))
)
->download();
4. Add Browsershot/Chrome flags (to prevent resource issues)
Often, Chrome needs extra flags when run in Forge/Laravel shared env. For example:
return Pdf::view('PDF.invoice', compact('invoice'))
->format('a4')
->landscape()
->name("{$invoice->invoice_no}-{$invoice->created_at->format('Y-m-d')}.pdf")
->withBrowsershot(function ($browsershot) {
$browsershot
->setChromePath(env('CHROME_PATH', '/usr/bin/chromium-browser'))
->addChromiumArguments([
'--no-sandbox',
'--disable-setuid-sandbox',
'--disable-dev-shm-usage',
]);
})
->download();
--no-sandboxand--disable-setuid-sandboxare essential on Forge servers!--disable-dev-shm-usagecan help if/dev/shmis too small (typical on Forge).
5. Kill zombie Chromium processes (if leaks persist)
Old Chrome/Chromium processes might accumulate. Consider a (safe) cron job:
# Run every 6 hours
0 */6 * * * pkill -f "(chrome)?(chromium)?(--headless)"
Final Example
Your controller method could look like:
return Pdf::view('PDF.invoice', compact('invoice'))
->format('a4')
->landscape()
->name("{$invoice->invoice_no}-{$invoice->created_at->format('Y-m-d')}.pdf")
->withBrowsershot(function ($browsershot) {
$browsershot
->setChromePath(env('CHROME_PATH', '/usr/bin/chromium-browser'))
->addChromiumArguments([
'--no-sandbox',
'--disable-setuid-sandbox',
'--disable-dev-shm-usage',
]);
})
->download();
Troubleshooting
- Check for running Chrome/Chromium processes:
ps aux | grep chromium - Check PHP logs for related errors.
- Try running a minimal Browsershot test from the command line as
forgeuser.
References
- Spatie Browsershot Docs: Troubleshooting
- Puppeteer troubleshooting
- Laravel Forge troubleshooting PDF/chrome issues
If after all of these you still have issues, provide the output of which chromium-browser and any recent log outputs for help fine-tuning the fix.