# Running your own Fulcrum — and why the resolver wants you to Referenced from `src/registrar-config.js` (`REGISTRAR.selfHosted`). ## The problem this solves Public electrum servers listen on **non-standard ports**: 50004 and 62002. On 2026-07-27 all three configured chipnet servers went TCP-closed from one machine at the same instant, while `:443` stayed perfectly reachable. That is the signature of a firewall or VPN policy, not an outage — and it is the normal condition on corporate networks, on some mobile carriers, and behind many consumer VPNs. The consequence is worse than it sounds. Every server in the list shares the same two ports, so **one rule takes down the entire resolver**: no availability search, no registration, no record updates, for that user, everywhere the software runs — website, extension, Theseus, Ariadne. A server on 443 is indistinguishable from ordinary HTTPS traffic and is essentially never blocked. **One server on 443 is worth more than three more on 50004.** ## The second reason: not trusting one server A single electrum server is a trusted third party. It cannot forge a registration — that needs a real CashTokens genesis whose commitment matches the name — but it can **omit** one. Because the protocol rule is *"first valid REG wins"*, a hidden REG makes a taken name look available: the buyer pays, mints a duplicate certificate, and every other resolver rejects it. `ElectrumPool.unionHistory` defends against exactly this by taking the **union** of beacon history across every server that answers, and reporting which servers were short. Union rather than quorum, because omission is the attack: a server showing you *more* history is giving you more truth, and two stale servers must not be able to outvote one honest one. **So running your own server is not a centralisation trade.** Your server is the fast, unblockable path; the public ones stay in the list as cross-checks. The union means your own server cannot quietly hide a registration from you either. ## Configuration ```js // src/registrar-config.js selfHosted: "wss://bns.example.st:443", ``` That is all. The pool connects in parallel, prefers earlier entries, fails over automatically, and unions the history regardless of order. ## Running Fulcrum Fulcrum indexes a full node; you need both. 1. **Bitcoin Cash Node** with the indexes Fulcrum needs: ``` txindex=1 server=1 rpcuser=… rpcpassword=… chipnet=1 # or omit for mainnet ``` 2. **Fulcrum**, pointed at it. The part that matters here is the **WSS port on 443**: ``` bitcoind = 127.0.0.1:8332 rpcuser = … rpcpassword = … ssl = 0.0.0.0:50002 wss = 0.0.0.0:443 # <- the one that survives restrictive networks cert = /etc/letsencrypt/live/bns.example.st/fullchain.pem key = /etc/letsencrypt/live/bns.example.st/privkey.pem ``` 3. **A real certificate.** Browsers will not open a `wss://` connection with a self-signed cert, and the failure is opaque — it surfaces as a generic WebSocket error with no indication that the certificate is the cause. Use Let's Encrypt. 4. **Binding 443 needs privilege.** Either `setcap 'cap_net_bind_service=+ep'` on the Fulcrum binary, or terminate TLS at nginx and proxy to Fulcrum's plain WS port. The nginx route is usually easier because it shares 443 with the rest of the site: ```nginx location /electrum { proxy_pass http://127.0.0.1:50003; proxy_http_version 1.1; proxy_set_header Upgrade $http_upgrade; proxy_set_header Connection "upgrade"; proxy_read_timeout 3600s; # electrum connections are long-lived } ``` Then `selfHosted: "wss://bns.example.st:443/electrum"`. ## Verifying it ```bash # reachable at all? curl -sk -o /dev/null -w "%{http_code}\n" https://bns.example.st:443 # does it speak electrum? cd Argus && node --input-type=module -e " import WebSocket from 'ws'; import { Electrum } from './src/lib/electrum.js'; const el = await new Electrum('wss://bns.example.st:443', WebSocket).connect(); console.log(await el.call('server.version', ['probe','1.4.2'])); console.log('height:', (await el.call('blockchain.headers.subscribe')).height); el.close(); process.exit(0);" ``` The second command is the one that matters — a server can answer HTTPS and still not be a working electrum endpoint. ## Note for the browser The register page can only reach electrum over **WSS**. It cannot open raw TCP, so it can never talk to a P2P node directly, and it cannot use a plain-TCP electrum port. Every entry in the list must be `wss://`. This is also why SPV-grade *verification* (headers + merkle proofs over electrum) is the right target for the web client rather than direct-to-node SPV — see `Decentralized.DNS/DESIGN-trustless-purchase.md`.