Running a Headless Browser on a VPS: Puppeteer and Playwright Setup 2026
Headless browsers — Chromium running without a display — power web scraping, PDF generation, automated testing, and screenshot services. Getting them to run on a VPS requires more than npm install puppeteer.
Installing Chrome Dependencies on Ubuntu
Puppeteer and Playwright install Chromium automatically but require Linux system dependencies:
# Dependencies for headless Chrome on Ubuntu 22.04
sudo apt install -y \
libnss3 \
libatk-bridge2.0-0 \
libdrm2 \
libxkbcommon0 \
libxcomposite1 \
libxdamage1 \
libxrandr2 \
libgbm1 \
libasound2 \
libpango-1.0-0 \
fonts-liberation \
xdg-utils
Puppeteer: Launch Configuration for VPS
const puppeteer = require('puppeteer');
const browser = await puppeteer.launch({
headless: 'new', // Use new headless mode
args: [
'--no-sandbox', // Required in containers/VPS
'--disable-setuid-sandbox',
'--disable-dev-shm-usage', // Prevents crashes in low-memory environments
'--disable-gpu', // Not needed headless
'--disable-extensions'
]
});
The --no-sandbox flag is required on VPS environments where Chrome's sandbox cannot be used.
Playwright Alternative
Playwright from Microsoft is often preferred for its multi-browser support and better reliability:
npm install playwright
npx playwright install chromium --with-deps # Installs Chromium + all system dependencies
const { chromium } = require('playwright');
const browser = await chromium.launch({ headless: true });
const page = await browser.newPage();
await page.goto('https://example.com');
// Take screenshot
await page.screenshot({ path: 'screenshot.png' });
// Extract text
const text = await page.textContent('h1');
await browser.close();
Memory Management for Long-Running Services
Browser instances use 100–300 MB each. For high-volume services:
// Don't launch a new browser per request — reuse it
let browser;
async function getBrowser() {
if (!browser || !browser.isConnected()) {
browser = await chromium.launch({ headless: true });
}
return browser;
}
// Always close pages (not browser) when done
const page = await (await getBrowser()).newPage();
// ... use page ...
await page.close(); // Returns tab to pool, doesn't close browser
A VPS with 4 GB RAM can handle 4–8 concurrent Playwright contexts comfortably.