Files
trawl/apps/docs/getting-started/configuration.md
T

197 lines
7.7 KiB
Markdown
Raw Blame History

This file contains ambiguous Unicode characters
This file contains Unicode characters that might be confused with other characters. If you think that this is intentional, you can safely ignore this warning. Use the Escape button to reveal them.
---
title: Configuration
description: All environment variables for TRAWL, with defaults and examples.
---
# Configuration
All configuration is via environment variables. Copy `.env.example` to `.env` and edit before starting.
## Redis
### `REDIS_URL`
**Default:** `redis://localhost:6379`
Standard Redis connection URL — TRAWL's cache backend is Redis 8.8. When running inside Docker Compose use the service name:
```ini
REDIS_URL=redis://redis:6379
```
With authentication:
```ini
REDIS_URL=redis://:yourpassword@redis:6379
```
With a specific database index:
```ini
REDIS_URL=redis://redis:6379/1
```
## Browser Pool
### `BROWSER_POOL_SIZE`
**Default:** `3`
Number of Camoufox Firefox instances to keep warm. Each instance uses ~350–500 MB RAM under load. Start conservative and raise if you need higher concurrency.
```ini
BROWSER_POOL_SIZE=1 # minimal (1 GB host RAM)
BROWSER_POOL_SIZE=3 # default — good for most self-hosted setups
BROWSER_POOL_SIZE=8 # high-throughput (6+ GB host RAM)
```
> **Note:** The API container sets `shm_size: 1gb` by default. If you raise `BROWSER_POOL_SIZE` above 5, also raise `shm_size` in your `docker-compose.yml` to at least `2gb`.
### `BROWSER_ACQUIRE_TIMEOUT_MS`
**Default:** `15000` (15 seconds)
How long `BrowserPool.acquire()` will poll for a free browser before rejecting with `PoolExhaustedError`. With `BROWSER_POOL_SIZE=3` and a typical Cloudflare challenge taking 5–8s per request, the 15s default lets a full burst of 10 concurrent requests drain without any 429s.
Lower it for fail-fast client feedback (Prowlarr will see 429s sooner and retry on its own). Raise it for very heavy upstream targets or when you've bumped `BROWSER_POOL_SIZE` higher.
```ini
BROWSER_ACQUIRE_TIMEOUT_MS=5000 # fail fast — 429s after 5s
BROWSER_ACQUIRE_TIMEOUT_MS=15000 # default — absorbs a full burst on pool=3
BROWSER_ACQUIRE_TIMEOUT_MS=30000 # tolerate longer queueing on slow targets
```
When the timeout fires, both `/v1` and `/scrape` return **HTTP 429** with the FlareSolverr v2 error envelope (not a 500).
### `BROWSER_RECYCLE_AFTER_CONTEXTS`
**Default:** `8`
How many `blocked` / `needs-js` outcomes a pooled browser can produce before TRAWL restarts the full browser process. The recycle counter only increments when Tier 3 or Tier 4 reports the upstream actively rejected the browser's profile — successful solves preserve cookies, `cf_clearance`, and warm fingerprint state. This avoids the HTTP-429 storm that occurred when the pool preemptively recycled mid-flight (issue #17).
```ini
BROWSER_RECYCLE_AFTER_CONTEXTS=8 # default - recycle after 8 blocked/needs-js outcomes
BROWSER_RECYCLE_AFTER_CONTEXTS=0 # disable browser recycling entirely
```
### `BROWSER_CONTENT_PROCESSES`
**Default:** `2`
Caps Firefox content processes per pooled browser via the `dom.ipc.processCount` Firefox pref. Firefox's default of 8 lets thread count climb when Tier 3 / Tier 4 churn disposable contexts (see #13). The cap bounds the leak at the source without paying the recycle cost. Raise if specific targets fail with empty content (rare).
```ini
BROWSER_CONTENT_PROCESSES=2 # default - conservative cap, lowest RAM/CPU
BROWSER_CONTENT_PROCESSES=4 # raise if CF/Imperva challenges stall
```
## Session Cache
### `SESSION_TTL_SECONDS`
**Default:** `3600` (1 hour)
How long Cloudflare cookies are cached in Redis per domain. After this TTL the next request to the domain triggers a fresh challenge solve (Tier 3) and refreshes the cache.
Cloudflare's `cf_clearance` cookie typically has a 30-minute expiry. Setting `SESSION_TTL_SECONDS` below 1800 wastes cache hits; setting it above 7200 risks replaying expired cookies (TRAWL handles this gracefully by invalidating the cache and falling back to Tier 3).
```ini
SESSION_TTL_SECONDS=3600 # default — safe for most sites
SESSION_TTL_SECONDS=1800 # more conservative
```
## Proxies
### `PROXY_URL`
**Default:** _(empty — no proxy)_
Datacenter proxy pool used for Tier 3 (fresh challenge solve). Format: `protocol://user:pass@host:port`, or a **comma-separated list** for multiple proxies:
```ini
PROXY_URL=http://user:pass@dc-proxy.example.com:8080
PROXY_URL=http://user:pass@dc1.example.com:8080,http://user:pass@dc2.example.com:8080
```
Leave empty to run Tier 3 without a proxy (your server's real IP is used).
### `RESIDENTIAL_PROXY_URL`
**Default:** _(empty — Tier 4 disabled)_
Residential proxy pool used for Tier 4 (when the datacenter IP is flagged). Same format as `PROXY_URL` — single URL or comma-separated list. Tier 4 is completely skipped if this variable is not set and no per-request `proxy` override is supplied.
```ini
RESIDENTIAL_PROXY_URL=http://user:pass@residential.example.com:8080
```
### `PROXY_LIST_FILE` / `RESIDENTIAL_PROXY_LIST_FILE`
**Default:** _(empty)_
Alternative to cramming a large proxy list into `PROXY_URL`/`RESIDENTIAL_PROXY_URL` — path to a file with one proxy URL per line (`#` comments allowed). Merged with the corresponding `*_URL` env var if both are set.
```ini
PROXY_LIST_FILE=/etc/trawl/datacenter-proxies.txt
RESIDENTIAL_PROXY_LIST_FILE=/etc/trawl/residential-proxies.txt
```
### Rotation and failure handling
When more than one proxy is configured, TRAWL picks proxies **sticky-per-domain** — repeat requests to the same hostname keep reusing the same proxy (helps avoid re-triggering challenges), while different domains spread round-robin across the pool. If a tier attempt comes back `"blocked"` using a pool-sourced proxy, that proxy is put in a 5-minute cooldown and the request retries once with the next available proxy before falling through (Tier 3 → Tier 4, or Tier 4 failing outright) — bounded to 2 attempts per tier so a long list can't blow the request's `maxTimeout`.
### Per-request override
Both `POST /scrape` and `POST /v1` accept an optional `proxy` field in the request body — when present, it's used directly for that request's Tier 3/4 attempts instead of the configured pool (and isn't retried against other pool proxies on failure, since it's caller-supplied):
```json
{ "url": "https://example.com", "proxy": "http://user:pass@my-proxy.example.com:8080" }
```
Note: `proxy` on `/v1` is a TRAWL-specific extension — it is not part of the real FlareSolverr v2 contract, so other FlareSolverr-compatible clients simply won't send it.
## Ports
### `PORT`
**Default:** `8191`
Host port the Docker port mapping forwards to TRAWL's internal listener. Defaults to `8191` — the same port FlareSolverr and Byparr use, so you can swap TRAWL in without changing any *arr app settings. The container itself always listens on `8191` internally; `PORT` only changes the **host-side** port (e.g. `"${PORT:-8191}:8191"` in every compose file).
To run TRAWL alongside FlareSolverr (or any other service that already binds `8191` on the host), set `PORT` in your shell or `.env` to any free port **before** running `docker compose up`:
```bash
PORT=9191 docker compose up -d
# TRAWL reachable at http://localhost:9191, while port 8191 stays free for FlareSolverr.
```
### `PORT_WEB`
**Default:** `3000`
Port the Nuxt landing page listens on.
---
## Full `.env.example`
```ini
# ── Redis ─────────────────────────────────────
REDIS_URL=redis://localhost:6379
# ── Browser pool ──────────────────────────────
BROWSER_POOL_SIZE=3
BROWSER_ACQUIRE_TIMEOUT_MS=15000
SESSION_TTL_SECONDS=3600
# ── Proxies (optional, comma-separated lists) ─
PROXY_URL=
RESIDENTIAL_PROXY_URL=
PROXY_LIST_FILE=
RESIDENTIAL_PROXY_LIST_FILE=
# ── Ports ─────────────────────────────────────
PORT=8191
PORT_WEB=3000
```