Open source · No third-party services

Bots don't belong on your site.
Bot detection, No JS. No CAPTCHAs.

Thunderhead is a lightweight reverse proxy that silently scores every incoming HTTP request 0–100. Bots get tarpitted or blocked. Humans never notice.

View on GitHub
$ go run ./cmd/thunderhead
request.log
0 requests processed
waiting for requests...
Methodology

Silent observation.
Graduated response.

Thunderhead never interrupts real users. It watches how clients move through your site and builds an intent score from passive signals — no fingerprinting, no cookies, no third-party calls.

Request pipeline

Every request enters the proxy, gets scored, and is dispatched to one of three actions — all within a single hop.

Requestincoming HTTPProxythunderheadScorer0 – 100 scoreAllow< 40Tarpit40 – 74Block≥ 75upstream
Step by step
1
Request arrivesEvery HTTP request hitting your origin is intercepted by Thunderhead's reverse proxy before touching your app.
2
Signals are sampledThe scorer reads five passive signals from the request — no JavaScript, no cookies, no challenges issued.
3
Score is computedEach signal contributes a weighted score. Signals stack additively up to a maximum of 100.
4
Action is dispatchedBelow 40: the request is forwarded silently. 40–74: response is delayed by 5 seconds. 75+: a 403 is returned immediately.
5
Everything is loggedEvery decision is emitted as structured JSON to stdout or a file — ready for your existing observability stack.

Signal weights

Five passive signals are sampled per request. Each contributes an additive score. No single signal is decisive — the combination is what matters.

robots.txt violation+30
Sequential path crawling+25
High request rate+20
Suspicious/missing headers+15
Text-heavy page pattern+10

Score thresholds

The final score determines the action tier. Thresholds are configurable in config.json — tune them for your traffic profile.

40750255075100ALLOW0 – 39Pass to upstreamTARPIT40 – 74Delay 5sBLOCK75 – 100403 ForbiddenINTENT SCORE THRESHOLDS
Observability

Every decision is a log line.

Thunderhead emits structured JSON for every request. Pipe it to your existing stack or just jq.

thunderhead.log
{"action":"block""score":95"path":"/wp-login.php"}
{"action":"allow""score":22"path":"/blog/post-1"}
{"action":"tarpit""score":55"path":"/robots.txt"}
Features

Everything you need.
Nothing you don't.

Thunderhead is deliberately minimal. A single binary, a single config file, and a scoring engine that runs entirely in-process — no sidecars, no databases, no SaaS.

Zero friction

No JS challenges. No CAPTCHAs. No interruptions.

Thunderhead never touches the client. It reads five passive signals from the raw HTTP request — headers, path patterns, request rate — and scores silently in the background.

PASSIVE SIGNALS ONLY
robots.txt checkpassive
Path sequence trackingpassive
Rate window (60s)passive
Header inspectionpassive
Content-type analysispassive
JS challenge
CAPTCHA
Cookies set
Fingerprint
Graduated response

Three tiers of action

Not every suspicious request deserves a hard block. Tarpitting drains bot resources without revealing detection. Tune thresholds to fit your traffic.

NORMAL REQUEST~12ms
TARPITTED REQUEST5000ms
BLOCKED REQUEST403
403 Forbidden
Observability

Structured JSON logs

Every decision emits a log line with IP, path, score, action, and which signals fired. Pipe to Grafana, Loki, or jq.

{
"time":"2024-01-15T14:23:01Z",
"ip":"185.220.101.5",
"path":"/wp-login.php",
"score":95,
"action":"block",
"signals":["robots_violation","high_rate"]
}
Allowlist

IP, CIDR & user-agent bypass

Lock out entire CIDR ranges or allowlist trusted crawlers by user-agent. Googlebot never gets tarpitted.

TypeValue
CIDR10.0.0.0/8
IP203.0.113.5
UAGooglebot/2.1
IP185.220.101.5
UApython-requests/2.31
Configuration

Single config file

One JSON file controls listen address, upstream URL, score thresholds, tarpit delay, and log output. No env vars required.

config.json
1{
2"listen_addr": ":8080",
3"upstream_url": "http://localhost:3000",
4"thresholds": {
5"tarpit": 40,
6"block": 75
7},
8"tarpit": {
9"delay": 5000000000
10},
11"log_file": ""
12}
Roadmap

What's shipping next

Dashboard UI, JS challenge mode, and a Go middleware library are in active development. Core detection is stable and production-ready.

6/8 complete75%
Auto-fetch robots.txt
/thunderhead/status endpoint
IP / CIDR / UA allowlist
Persistent score storage
CIDR range blocking
Dashboard UI
JS challenge mode
Middleware (Go library)
Quickstart

Up and running
in 60 seconds.

Thunderhead sits in front of any HTTP upstream. No code changes to your app required — just install, configure, and run.

1
InstallInstall the binary directly with Go. No external dependencies required.
$ go install github.com/bhavv04/thunderhead/cmd/thunderhead@latest
2
ConfigurePoint Thunderhead at your upstream and tune your scoring thresholds in config.json.
3
RunStart Thunderhead in front of your app. Bots get scored, tarpitted, or blocked.
$ thunderhead -config config.json
thunderhead — install & run