Skip to main content

Using NGINX with Browserless Docker

When running browserless in production with Docker, you'll often want to use NGINX as a load balancer or reverse proxy. This provides several benefits including SSL termination, load distribution across multiple browserless instances, and improved reliability through health checks and failover.

Why Use NGINX with Browserless?

  • Load Balancing: Distribute traffic across multiple browserless containers
  • SSL Termination: Handle HTTPS certificates at the proxy level
  • Health Checks: Automatically retry failed requests to healthy instances
  • WebSocket Support: Properly handle WebSocket connections for Puppeteer and Playwright
  • High Availability: Prevent single points of failure

Docker Compose Setup

Here's a complete example using Docker Compose with NGINX load balancing two browserless instances:

docker-compose.yml

version: '3'

services:
nginx:
image: nginx
volumes:
- ./nginx.conf:/etc/nginx/conf.d/default.conf:ro
ports:
- "80:80"

browserless_one:
image: ghcr.io/browserless/chromium
environment:
- TOKEN=your-token-here
- CONCURRENT=10

browserless_two:
image: ghcr.io/browserless/chromium
environment:
- TOKEN=your-token-here
- CONCURRENT=10

nginx.conf

upstream browserless {
least_conn;
server browserless_one:3000;
server browserless_two:3000;
}

server {
proxy_next_upstream error timeout http_500 http_503 http_429 non_idempotent;
listen 80;

location / {
proxy_pass http://browserless;
proxy_http_version 1.1;
proxy_set_header Upgrade $http_upgrade;
proxy_set_header Connection 'upgrade';
proxy_set_header Host $host;
proxy_cache_bypass $http_upgrade;

proxy_connect_timeout 900;
proxy_send_timeout 900;
proxy_read_timeout 900;
send_timeout 900;
}
}

Configuration Explanation

Upstream Block

The upstream block defines the backend browserless instances:

  • least_conn: Routes requests to the server with the fewest active connections
  • server browserless_one:3000: References the Docker service name and internal port
  • Multiple servers provide redundancy and load distribution

Server Block

The server block handles incoming requests:

  • proxy_next_upstream: Automatically retries failed requests on other servers
  • proxy_http_version 1.1: Required for WebSocket support
  • Upgrade and Connection headers: Essential for WebSocket connections used by Puppeteer
  • Extended timeouts: Accommodate long-running browser operations

Starting the Setup

  1. Create the nginx.conf file with the configuration above
  2. Create the docker-compose.yml file
  3. Start the services:
docker-compose up

Your browserless instances will be available at http://localhost with automatic load balancing.

Advanced Configuration

Health Checks

You can enable health checks in browserless to make the load balancing more intelligent:

browserless_one:
image: ghcr.io/browserless/chromium
environment:
- TOKEN=your-token-here
- PRE_REQUEST_HEALTH_CHECK=true

browserless_two:
image: ghcr.io/browserless/chromium
environment:
- TOKEN=your-token-here
- PRE_REQUEST_HEALTH_CHECK=true

When enabled, browserless will reject requests when CPU or memory usage is high, causing NGINX to automatically route traffic to healthier instances.

SSL Configuration

For production deployments, you'll want to add SSL support. Here's an example server block with SSL:

server {
listen 443 ssl;
server_name your-domain.com;

ssl_certificate /path/to/your/certificate.pem;
ssl_certificate_key /path/to/your/private-key.pem;

location / {
proxy_pass http://browserless;
proxy_http_version 1.1;
proxy_set_header Upgrade $http_upgrade;
proxy_set_header Connection 'upgrade';
proxy_set_header Host $host;
proxy_set_header X-Real-IP $remote_addr;
proxy_cache_bypass $http_upgrade;

proxy_connect_timeout 900;
proxy_send_timeout 900;
proxy_read_timeout 900;
send_timeout 900;
}
}

Proxy Configuration

When using NGINX in front of browserless, you may need to configure browserless to be aware of the proxy for proper link generation. See the Docker Configuration documentation for details on setting PROXY_HOST, PROXY_PORT, and PROXY_SSL environment variables.

Testing Your Setup

You can test your load-balanced setup by connecting with Puppeteer:

const puppeteer = require('puppeteer');

const browser = await puppeteer.connect({
browserWSEndpoint: 'ws://localhost:80'
});

const page = await browser.newPage();
await page.goto('https://example.com');
const title = await page.title();
console.log(title);

await browser.close();

The requests will be automatically distributed across your browserless instances by NGINX.