site/mirrors/index.html
Local Dev 0b94a60f52 feat(site/mirrors): docs page for BNS p-record reverse-proxy workaround
Cloudflare's Bot Fight Mode fingerprints Electron's TLS ClientHello and
returns HTTP 503 to Theseus regardless of user-agent (verified against
whybitcoincash.com). BNS `p` records proxy through Node's undici fetch
from the main process, which has a different TLS fingerprint and slips
past the check — Theseus renders the upstream under the .bch origin.

New /mirrors/ page explains the mechanism, links the relevant code
(record-picker.js and main.js serveP), and walks through minting a
mirror in Sirius. Ships with an empty featured list; entries populate
as .bch names are minted and added to home-cards.json.

Also adds a short note on /tools/ pointing at the new page so users
hitting a 503 have a discovery path.
2026-10-04 01:47:02 +02:00

194 lines
9.6 KiB
HTML

<!doctype html>
<html lang="en">
<head>
<meta charset="utf-8">
<meta name="viewport" content="width=device-width, initial-scale=1">
<title>Mirrors — Silent Mode</title>
<meta name="description" content="Cloudflare's Bot Fight Mode fingerprints Electron's TLS handshake and blocks Theseus with HTTP 503. BNS `p` records reverse-proxy the request through Node's HTTP stack, bypassing the fingerprint — Theseus renders the page under a .bch name.">
<link rel="stylesheet" href="../shared.css">
<link rel="icon" type="image/svg+xml" href="/favicon.svg">
<style>
.mirror-list{display:grid;gap:10px;margin:1rem 0 1.4rem}
.mirror{
display:grid;grid-template-columns:1fr auto;gap:14px;align-items:center;
background:var(--panel);border:1px solid var(--line);border-radius:12px;
padding:14px 18px;
}
.mirror .row1{font:600 15px/1.35 ui-monospace,monospace;color:var(--acid)}
.mirror .row2{color:var(--mut);font-size:12.5px;margin-top:3px;
font-family:ui-monospace,monospace;word-break:break-all}
.mirror .badge{
font:600 10.5px/1 system-ui;letter-spacing:.18em;text-transform:uppercase;
color:var(--acid);background:rgba(214,255,61,.10);
border:1px solid rgba(214,255,61,.28);padding:5px 9px;border-radius:999px;
white-space:nowrap;
}
.empty-note{
color:var(--mut);font-size:13px;padding:14px 16px;
background:var(--panel2);border:1px dashed var(--line);border-radius:10px;
}
code.k{font-family:ui-monospace,monospace;background:var(--panel2);
padding:1px 6px;border-radius:5px;color:var(--acid)}
.step{display:flex;gap:14px;padding:12px 0}
.step + .step{border-top:1px solid var(--line)}
.step .n{flex:none;width:26px;height:26px;border-radius:999px;
background:rgba(214,255,61,.10);color:var(--acid);
display:grid;place-items:center;font:600 12px/1 system-ui}
.step .b{color:var(--mut);font-size:14px;line-height:1.6}
.step .b b{color:var(--ink)}
</style>
</head>
<body>
<nav class="topnav">
<a class="brand" href="./"><svg class="logo" viewBox="0 0 32 20" aria-hidden="true"><rect class="l1" x="1.5" y="3.5" width="17" height="13" rx="6.5" ry="6.5" fill="none" stroke-width="2.6"/><rect class="l2" x="13.5" y="3.5" width="17" height="13" rx="6.5" ry="6.5" fill="none" stroke-width="2.6"/></svg>Silent <span class="g">Mode</span></a>
<a href="theseus">Theseus</a>
<a href="prometheus">Prometheus</a>
<a href="sirius">Sirius</a>
<a href="hephaestus">Hephaestus</a>
<a href="helios">Helios</a>
<a href="hermes">Hermes</a>
<a href="tools">Tools</a>
</nav>
<header class="hero">
<h1>Reverse-proxy <span class="g">mirrors</span></h1>
<p class="tag">Some sites — including several of the most-cited pages in the Bitcoin
Cash ecosystem — return <b>HTTP 503</b> to Theseus, no matter what user-agent it sends.
A short note on why, and how a <code class="inline">.bch</code> name gets you through.</p>
</header>
<div class="wrap">
<!-- ============ WHAT'S HAPPENING ============ -->
<section>
<h2>Why Theseus 503s on some sites</h2>
<p class="lede">Cloudflare's Bot Fight Mode (and similar WAF rules) fingerprints the
<b>TLS ClientHello</b> — the cipher list, extensions, and JA3/JA4 hash your browser
sends before any HTTP header is negotiated. Chromium's TLS stack, which Theseus is
built on via Electron, ships with a slightly different fingerprint than desktop
Chrome — enough to trigger the bot heuristic. The server replies with a short
503 page and the load fails.</p>
<p class="lede">Stripping <code class="inline">Electron/…</code> from the user-agent
doesn't help: the fingerprint sits below HTTP. Disabling HTTP/2 doesn't help either.
From the site's perspective, Theseus is indistinguishable from a scraper.</p>
</section>
<!-- ============ THE FIX ============ -->
<section>
<h2>What a <code class="inline">p</code> record does</h2>
<p class="lede">A BCDN name can carry a <code class="inline">p</code> record — a
single upstream URL. When Theseus loads a name whose record picker returns
<code class="inline">p</code>, it doesn't hand the request to Chromium's network
stack. It hands it to <b>Node's <code class="inline">fetch()</code></b> from the
main process, which uses a different HTTP client (undici) with a completely
different TLS fingerprint — one Cloudflare doesn't flag. The response body comes
back and gets served under the <code class="inline">.bch</code> origin.</p>
<p class="lede">The address bar stays on the BNS name; the upstream never sees your
IP resolve through Cloudflare's browser-bot rules, only through Theseus's outbound
Node fetch. No captcha, no interstitial, no 503.</p>
<p class="lede">Trade-offs to know: the <code class="inline">p</code> path uses the
upstream's own DNS and public certificate authority (unlike <code class="inline">ip</code>,
which pins to a raw IP + on-chain TLS fingerprint), and Theseus streams the body
through its own process — so the upstream sees Theseus's outbound IP, not yours.
This is a shared proxy in effect, though only for the one request.</p>
</section>
<!-- ============ FEATURED MIRRORS ============ -->
<section>
<h2>Featured mirrors</h2>
<p class="lede">These names are registered on the Bitcoin Cash chain with a
<code class="inline">p</code> record pointing at a Cloudflare-fronted upstream
Theseus can't reach directly. Click any to open it in Theseus (or via
<a href="https://navigate.st/">navigate.st</a> if you don't have the browser
installed yet).</p>
<div class="mirror-list" id="mirror-list">
<!-- Populated at ship time. Keep entries in sync with site/home-cards.json's
"Mirrored" section so the home tiles and this page tell the same story. -->
<div class="empty-note">
<b>No mirrors published yet.</b> The list will fill in as names are minted
through Sirius. Check back, or mint one yourself — instructions below.
</div>
</div>
<p class="lede" style="margin-top:1.2rem">
<b>See a site missing?</b> If a Cloudflare-fronted page you care about is
unreachable from Theseus, either mint a <code class="inline">p</code> record for
it yourself, or open an issue on
<a href="https://code.silentmode.st/silentmode/theseus">the Theseus repo</a> and
we'll add it to the featured list once it's on chain.
</p>
</section>
<!-- ============ DIY ============ -->
<section>
<h2>Mint a mirror yourself</h2>
<p class="lede">Registration costs a few sats of BCH. Theseus 0.3.14+ ships with the
<b>Aegis wallet</b> — the wallet the Sirius UI signs against — so this is a couple
of clicks once your wallet has a small balance.</p>
<div>
<div class="step">
<div class="n">1</div>
<div class="b">Open <a href="https://sirius.x/">sirius.x</a> in Theseus and search
for the label you want. Pick a <code class="k">.bch</code> TLD if the site is
BCH-related; other registered TLDs work too. Mint the name.</div>
</div>
<div class="step">
<div class="n">2</div>
<div class="b">Once minted, open the name's record editor and add:
<br><code class="k">p: "https://the-original-upstream.example/"</code>
<br>The trailing slash matters — anything in the path is used as a prefix
for every request.</div>
</div>
<div class="step">
<div class="n">3</div>
<div class="b">Sign the record change. Wait one confirmation. The record is live
as soon as the next Theseus resolve fetches the beacon.</div>
</div>
<div class="step">
<div class="n">4</div>
<div class="b">Test: type <code class="k">yourname.bch</code> in Theseus's address
bar. If the upstream returns 200, Theseus renders it under your name. Send us
the name and we'll add it to the featured list.</div>
</div>
</div>
<div class="note" style="margin-top:1.4rem">
<b>Be honest about what a mirror is.</b> The upstream is unchanged — the site
operator hasn't consented to being served under your BNS name, and doesn't get
paid for any traffic that lands through the mirror. This is a workaround for a
reachability problem, not a rehosting. If you'd rather leave the mirror to us,
open an issue and we'll consider whether it's canonical enough to include.
</div>
</section>
<!-- ============ TECHNICAL DETAIL ============ -->
<section>
<h2>The relevant code</h2>
<p class="lede">For anyone curious about the exact mechanism:</p>
<ul style="color:var(--mut);font-size:14px;line-height:1.7;padding-left:1.2rem">
<li>Record priority — <code class="inline">pickRecord()</code> in Argus:
<code class="inline">h &gt; s3 &gt; ip &gt; p &gt; u</code> at the apex, and
subdomain inheritance never picks <code class="inline">p</code>. Theseus
carries an inline copy to keep in step.</li>
<li>Theseus proxy pipeline — <a href="https://code.silentmode.st/silentmode/theseus/src/branch/master/main.js"><code class="inline">theseus/main.js</code></a>,
the <code class="inline">serveP</code> closure inside <code class="inline">serveBns()</code>.
Uses <code class="inline">fetch(target, { redirect: "manual" })</code>
from the main process, which is Node's undici — a different TLS stack from
Chromium's, and the reason the fingerprint check doesn't fire.</li>
</ul>
</section>
</div>
<footer>
<div>Silent Mode — a Deviant project.</div>
<div class="fine">Mirrors are provided as-is. The upstream site's terms and privacy
policy still apply — a <code class="inline">.bch</code> name changes only how the
bytes reach you, not who wrote them.</div>
</footer>
</body>
</html>