Search code examples
phpnode.jsapachepuppeteer

PHP / Apache / Node / Puppeteer - Error: Failed to launch the browser process


Node.js v20.11.1
PHP 7.4.33
chrome/linux-124.0.6367.91

Edit/TLDR: After more research, when I run via the command line, chrome is putting files in my home directory under .config/google-chrome-for-testing/ . I guess Chrome must be trying to find that dir when run by Apache. Looking into it now.

I have files index.js and puppeteerrc.cjs in the same directory. I am trying to make a PDF of a page at a given URL. puppeteerrc.cjs specifies the cache directory. The contents of both files are below.

This command works if I run it from within that directory

node index.js 'https://www.stackoverflow.com' output.pdf

However, in PHP, this does not:

 $cmd = "cd '/path/to/script' && node 'index.js' 'https://www.stackoverflow.com' /path/to/output.pdf 2>&1";
 exec($cmd, $out, $error_code);

I'm not sure what's different between the command line and Apache. I ran chrome_crashpad_handler --help, but I'm not sure what to do with that information.

When I set the executablePath config in index.js I get the same result, it runs from cmd line, not from Apache:

  const browser = await puppeteer.launch({
                executablePath:'/opt/npm/.cache/puppeteer/chrome/linux-124.0.6367.91/chrome-linux64/chrome'
          });

I've also tried all of the following configs and it outputs the same error:

args: ['--no-sandbox', "--disabled-setupid-sandbox"],
ignoreDefaultArgs: ['--disable-extensions'] ,
userDataDir: "/path/to/a/dir",
headless:true

Note that previously, when it couldn't find the chrome executable, I got a different error, now that I am past that error, it still doesn't work. So I know it can find the executable now. Also, I ran is_executable() on the chrome file and PHP running under Apache returns true.

I did notice that there is a ".config/google-chrome-for-testing/Crash Reports" directory in my home directory. Now I'm guessing that maybe it's looking for one of those directories when apache is running it.

Output when node command run from PHP

opt/npm/lib/node_modules/puppeteer/node_modules/@puppeteer/browsers/lib/cjs/launch.js:310
                reject(new Error([
                       ^

Error: Failed to launch the browser process!
chrome_crashpad_handler: --database is required
Try 'chrome_crashpad_handler --help' for more information.


TROUBLESHOOTING: https://pptr.dev/troubleshooting

    at Interface.onClose (/opt/npm/lib/node_modules/puppeteer/node_modules/@puppeteer/browsers/lib/cjs/launch.js:310:24)
    at Interface.emit (node:events:530:35)
    at Interface.close (node:internal/readline/interface:527:10)
    at Socket.onend (node:internal/readline/interface:253:10)
    at Socket.emit (node:events:530:35)
    at endReadableNT (node:internal/streams/readable:1696:12)
    at process.processTicksAndRejections (node:internal/process/task_queues:82:21)

Node.js v20.11.1

index.js

/**
 * Create a PDF file from a URL.  First  command line
 * argument (besidedes JS file) is URL, second one 
 * is output file.
 * Usage:   node  index.js <URL> <OUTPUT_FILE_NAME>
 */




const node_path = "/opt/npm/lib/node_modules";
module.paths.unshift(node_path);



const puppeteer = require('puppeteer');

(async () => {

  // Create a browser instance
  const browser = await puppeteer.launch();

  // Create a new page
  const page = await browser.newPage();

  // Website URL to export as pdf
  const website_url = process.argv[2];

  // output path
  const output_path = process.argv[3];

  // Open URL in current page
  await page.goto(website_url, { waitUntil: 'networkidle0' }); 

  //use the print CSS
  await page.emulateMediaType('print');

  // Downlaod the PDF
  const pdf = await page.pdf({
    path: output_path,
    margin: { top: '.39in', right: '.39in', bottom: '.39in', left: '.39in' },
    printBackground: true,
    format: 'Letter',
  });

  // Close the browser instance
  await browser.close();
})();

.puppeteerrc.cjs

/**
 * @type {import("puppeteer").Configuration}
 */
module.exports = {
  // Changes the cache location for Puppeteer.
  cacheDirectory: '/opt/npm/.cache/puppeteer'
};

Solution

  • Chrome needs a .config directory to write to, which it expects in the user's home directory. In the .config dir, it will put a google-chrome-for-testing/ directory. So, I created a config directory, for example '/my/web/app/dir/.config' Chmoded it to 775, Changed the directory group to apache.

    Then, I changed the HOME environment variable before I run the node command.

     $cmd = "HOME='/my/web/app/dir/' && export HOME && cd '/path/to/script' && node 'index.js' 'https://www.stackoverflow.com' /path/to/output.pdf 2>&1";
     exec($cmd, $out, $error_code);