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 connectionsserver 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 serversproxy_http_version 1.1
: Required for WebSocket supportUpgrade
andConnection
headers: Essential for WebSocket connections used by Puppeteer- Extended timeouts: Accommodate long-running browser operations
Starting the Setup
- Create the
nginx.conf
file with the configuration above - Create the
docker-compose.yml
file - 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.