Trawl

Trawl

Docker app from kronflux's Repository

Overview

Trawl is a self-hosted web scraping engine and a FlareSolverr / Byparr drop-in replacement. It bypasses JS challenges and captchas — Cloudflare, Turnstile, Interstitial, reCAPTCHA v2, hCaptcha and GeeTest — and returns cookies + user-agent over a FlareSolverr-compatible API on port 8191. Works out of the box with Prowlarr, Jackett, Sonarr, Radarr and the rest of the *arr stack. Powered by a fingerprint-patched Camoufox (Firefox) browser pool with a 4-tier escalation strategy (plain HTTP fetch -> cached browser session -> fresh Cloudflare solve -> residential proxy). Runs standalone out of the box. For faster repeat requests (bypass cookies cached in Redis), point REDIS_URL at a separate Redis container. Note: this image needs a larger shared-memory segment for the browser pool — the template sets --shm-size=1g via Extra Parameters. Do not remove it.



TRAWL

Welcome to TRAWL! 👋

Self-hosted web scraping engine that bypasses any JS challenge & captcha.
Support for: Cloudflare, Turnstile, Interstitial, reCAPTCHA, hCaptcha, GeeTest, Imperva (experimental).
Much faster and more reliable FlareSolverr & Byparr alternative and drop-in replacement for your *arr stack.

Features

  • 2-6x faster - compared to FlareSolverr or Byparr it returns much faster with higher success rate
  • 4-tier execution - plain HTTP fetch → cached browser session → fresh CF solve → residential proxy
  • Native captcha solving - CF Turnstile/Interstitial, reCAPTCHA v2 (free STT), hCaptcha, GeeTest v4 Slide
  • Camoufox Firefox - fingerprint-patched at the C++/Juggler level; indistinguishable from a real browser
  • Session cache - bypass cookies stored in Redis; repeat requests to the same domain return in ~500ms
  • FlareSolverr compatible - works with Prowlarr, Jackett, Sonarr, and the full *arr ecosystem out of the box
  • No external APIs required - reCAPTCHA audio transcription uses Google's free STT endpoint by default

Sponsors

View/Collapse All
nodemaven NodeMaven - The most reliable proxy provider with the Highest Quality IP on the market. Best solution for automation, web scraping, SEO research, and social media management.

Why NodeMaven?
• 99.9% uptime
• Sticky sessions up to 7 days
• IP filtering: all proxies have fraud score <97%
• No KYC required
• Cashback on traffic - burn GB and earn up to 10% back

Special codes for TRAWL users:
• TRAWL35 - 35% off to Mobile and Residential Proxies
• TRAWL40 - 40% off to ISP (Static) Proxies
swiftproxy Swiftproxy - A global residential proxy provider offering 80M+ real residential IPs across 190+ countries and regions. Built for web scraping, browser automation, AI workflows, SEO monitoring, and multi-account management.

Why Swiftproxy?
• Non-expiring residential traffic
• Rotating & sticky sessions
• HTTP, HTTPS & SOCKS5 support
• Country, state & city-level targeting
• 24/7 technical support

Exclusive offer for TRAWL users:
• PROXY90 - Get 10% OFF all proxy plans
• Free Trial Available

Quick start

# Clone and configure
git clone https://github.com/germondai/trawl
cd trawl
cp .env.example .env

# Start scraper + Redis
docker compose up -d

# Verify
curl http://localhost:8191/health

First boot takes 15–30s while the browser pool warms up. Subsequent starts are fast.

API

FlareSolverr-compatible (/v1)

curl -X POST http://localhost:8191/v1 \
  -H 'Content-Type: application/json' \
  -d '{"cmd":"request.get","url":"https://nowsecure.nl","maxTimeout":60000}'

Native API (/scrape)

Returns richer metadata: tier, timings, sessionCached, full cookie list.

curl -X POST http://localhost:8191/scrape \
  -H 'Content-Type: application/json' \
  -d '{"url":"https://nowsecure.nl","maxTimeout":60000}'

Connect Prowlarr / Jackett

Set the FlareSolverr URL to:

http://localhost:8191        # running on the same host
http://trawl:8191            # running via Docker Compose on the same network

MITM forward-proxy mode (fingerprint-bound Cloudflare, e.g. 1337x)

Some sites bind their Cloudflare clearance to the solving browser's full connection fingerprint. The /v1 flow can't help there: Prowlarr keeps only the cookie + user-agent and re-fetches the page with its own HTTP client, which Cloudflare re-challenges — the cookie isn't portable. For those indexers, enable the browser-backed forward proxy and add it to Prowlarr as an HTTP proxy (tag it onto just the affected indexers):

MITM_PROXY_ENABLED=true
MITM_PROXY_PORT=8192
MITM_PROXY_CA_DIR=/data/proxy-ca   # persist the CA (mount a volume)
MITM_PROXY_MAX_TIER=4              # cap escalation (e.g. 3 to stay off residential)

By default the listener binds 0.0.0.0 so clients on a Docker bridge network can reach it; set MITM_PROXY_HOST=127.0.0.1 to restrict it to loopback on a bare-metal host.

  1. Install the proxy's CA into the client's trust store so it accepts the per-host certs: curl http://<trawl-host>:8191/proxy-ca.crt → add to the Prowlarr container's CA store (e.g. a linuxserver /custom-cont-init.d script that copies it to /usr/local/share/ca-certificates/ and runs update-ca-certificates).
  2. Prowlarr → Settings → Indexer Proxies → HTTP, host <trawl-host>, port 8192, give it a tag, and add that tag to the CF-fingerprint-bound indexer.

Every request that indexer makes (search and the .torrent/magnet grab) is then re-issued through the browser pool and returns the exact bytes Cloudflare served the browser.

⚠️ A MITM proxy can impersonate any host to a client that trusts its CA. Only expose it on a private interface (localhost / a private Docker network), never publicly.

Tiers

Request
  │
  ▼
Tier 1: Plain HTTP fetch ────── success ──→ return (< 100ms)
  │ blocked
  ▼
Tier 2: Cached session ─────── success ──→ return (~500ms)
  │ cache miss / expired
  ▼
Tier 3: Fresh CF solve ─────── success ──→ cache + return (4–15s)
  │ IP flagged
  ▼
Tier 4: Residential proxy ──── success ──→ cache + return (15–45s)
  │ failed
  ▼
  error

Docker Compose files

File Description
docker-compose.yml Scraper + Redis (default)
docker-compose.minimal.yml Scraper only, no Redis
docker-compose.prod.yml Production: restart: always, memory limit, healthcheck
docker-compose.full.yml Full stack: scraper + web + docs

Docker images (one GHCR package, two tags)

Image tag Built from Runtime Use case
ghcr.io/germondai/trawl:latest apps/api/Dockerfile Bun 1.3.14 (modern, AVX2) Default — modern Linux amd64/arm64
ghcr.io/germondai/trawl:baseline apps/api/Dockerfile.baseline Bun 1.3.14 baseline (no AVX2) Older CPUs / older kernels (Synology NAS, J4125, Atom-era)

Both tags live on the same ghcr.io/germondai/trawl package — they share the registry but use different Dockerfile sources. Pick whichever tag fits your hardware:

# Modern hardware (most users)
image: ghcr.io/germondai/trawl:latest

# Older CPUs without AVX2 / Synology / older kernels
image: ghcr.io/germondai/trawl:baseline

Synology note: many Synology NAS units (DSM 7.x on J4125 / older hardware) ship kernel 4.4.x, which Bun's modern runtime can't fully handle. Standard Bun requires kernel 5.1+ (5.6+ recommended); the baseline build degrades gracefully down to kernel 3.10. The :baseline tag is published for that case — confirmed working on a Synology DS920+ (Celeron J4125, DSM 7.3.2, kernel 4.4.302): the container starts cleanly, /health reports healthy, and it solves live Cloudflare challenges via /v1 (see #1). Published by independent GitHub Actions workflows (.github/workflows/publish.yml, publish-baseline.yml); tag-triggered releases push matching git tags (e.g. v1.0.01.0.0, 1.0.0-baseline1.0.0-baseline) and manual workflow_dispatch from main updates the rolling tag (latest and baseline respectively).

Releases & versioning

TRAWL follows Semantic Versioning. Pushing a v-prefixed git tag (e.g. v1.0.0) triggers publish.yml, which builds and pushes the matching un-prefixed Docker tag (ghcr.io/germondai/trawl:1.0.0) alongside a major-only tag (:1). :latest always tracks the tip of main; :sha-<shortsha> images are pushed on every main commit regardless of tags. See the Releases page for the full version history and CHANGELOG.md for what changed in each one.

To publish a specific past commit that had a major fix without waiting for the next tip-of-main release, tag that exact SHA and push it — publish.yml builds off the tag ref, not off main's current tip:

git tag -a v1.0.1 <sha> -m "..."
git push origin v1.0.1

Configuration

Variable Default Description
BROWSER_POOL_SIZE 3 Warm Camoufox Firefox instances
BROWSER_ACQUIRE_TIMEOUT_MS 15000 How long acquire() polls for a free browser before HTTP 429 is returned
BROWSER_RECYCLE_AFTER_CONTEXTS 8 Recycle a browser after this many blocked/needs-js outcomes; set 0 to disable
BROWSER_CONTENT_PROCESSES 2 Cap Firefox content processes per browser (dom.ipc.processCount); lowers RAM/CPU
SESSION_TTL_SECONDS 3600 Redis session cache TTL (seconds)
REDIS_URL redis://localhost:6379 Redis connection string
RESIDENTIAL_PROXY_URL Enables Tier 4 proxy escalation
STT_URL Local Whisper endpoint for reCAPTCHA (optional)
PORT 8191 API listen port
MITM_PROXY_ENABLED false Enable the browser-backed MITM forward proxy (see MITM forward-proxy mode)
MITM_PROXY_PORT 8192 Forward-proxy listen port
MITM_PROXY_HOST 0.0.0.0 Bind address; 127.0.0.1 for loopback-only
MITM_PROXY_CA_DIR /data/proxy-ca Where the MITM CA + leaf certs are persisted (mount a volume)
MITM_PROXY_MAX_TIER 4 Cap escalation used by the proxy (e.g. 3 to stay off residential)
MITM_PROXY_DEBUG false Log one line per proxied request (errors are always logged)

Stack

Built on a modern, fast-by-default stack: Bun + Elysia for the API, Redis for caching, Camoufox (hardened Firefox) for browser automation, and Nuxt for the web UI — no legacy Node/Express baggage.

Layer Technology
Runtime Bun
API Elysia
Browser Camoufox Firefox (via camoufox-js)
Session cache Redis 8.8
Landing page Nuxt 4
Documentation VitePress

License

AGPL-3.0


Made with ❤️ by @germondai

Install Trawl on Unraid in a few clicks.

Find Trawl in Community Apps on your Unraid server, review the template, and click Install. Unraid handles the Docker app or plugin setup from the published template.

Open the Apps tab on your Unraid server Search Community Apps for Trawl Review the template variables and paths Click Install

Requirements

Internet access is required. Allow roughly 1 GB of RAM headroom per browser in the pool (see Browser Pool Size).

Categories

Related apps

Explore more like this

Explore all

Details

Repository
ghcr.io/germondai/trawl:latest
Last Updated2026-07-25
First Seen2026-07-23

Runtime arguments

Network
bridge
Shell
sh
Privileged
false
Extra Params
--shm-size=1g

Template configuration

API PortPorttcp

FlareSolverr-compatible API port. Point Prowlarr/Jackett at http://[UNRAID-IP]:8191/v1.

Target
8191
Default
8191
Value
8191
Browser Pool SizeVariable

Number of concurrent browsers kept warm. Higher = more parallel throughput but more RAM (~1 GB each). Use 1 on low-memory systems.

Target
BROWSER_POOL_SIZE
Default
3
Value
3
AppdataPathrw

Persistent state. Holds the MITM proxy CA (/data/proxy-ca) so it survives container recreation.

Target
/data
Default
/mnt/user/appdata/trawl
Redis URLVariable

Optional. Point at a separate Redis container (e.g. redis://REDIS-IP:6379) to cache bypass cookies for ~500ms repeat requests. Leave empty to run standalone with an in-memory cache.

Target
REDIS_URL
Time ZoneVariable

Timezone used in log timestamps, e.g. America/Edmonton.

Target
TZ
Default
UTC
Value
UTC
Proxy URLVariable

Optional upstream proxy for the Tier 3 browser solve, e.g. http://user:pass@host:port.

Target
PROXY_URL
Residential Proxy URLVariable

Optional residential proxy used for the Tier 4 (last-resort) escalation.

Target
RESIDENTIAL_PROXY_URL
Enable MITM ProxyVariable

Optional browser-backed HTTPS forward proxy. When true, also publish the MITM Proxy Port below. Only expose it to trusted clients — it can impersonate any host to a client that trusts its CA.

Target
MITM_PROXY_ENABLED
Default
false
Value
false
MITM Proxy PortPorttcp

Host port for the MITM forward proxy. Only needed when Enable MITM Proxy is true.

Target
8192
Default
8192
Value
8192
MITM Proxy HostVariable

Bind address for the MITM proxy inside the container. Keep 0.0.0.0 so it is reachable through the published port.

Target
MITM_PROXY_HOST
Default
0.0.0.0
Value
0.0.0.0
MITM Max TierVariable

Cap the escalation tier the MITM proxy uses (e.g. 3 to keep it off residential Tier 4). Empty = up to 4.

Target
MITM_PROXY_MAX_TIER
MITM DebugVariable

Log one line per proxied request (noisy). Errors are always logged.

Target
MITM_PROXY_DEBUG
Default
false
Value
false
STT URLVariable

Optional local Whisper server for reCAPTCHA audio solving (fully air-gapped), e.g. http://whisper:8080/inference. Empty = Google's free STT endpoint.

Target
STT_URL
STT API KeyVariable

Optional API key for the local Whisper STT server, if it requires one.

Target
STT_API_KEY