infra: publish the NEAR node as near.blackbeard.observer

Through the existing nodes role: a Cloudflare CNAME to the site indirection,
a Let's Encrypt cert by DNS-01 on oolon, and a vhost beside the Quantus and
Planck endpoints. The upstream is https://near.internal rather than frankie,
so next week's move to new hardware changes one internal vhost and nothing
here, and frankie's firewall still admits only the hanzalova proxy and bob.

Throttled harder than the Quantus endpoint, because the node is a four-core
stopgap and the swap indexer reads it too (via near.internal, outside these
limits): 5 r/s per client with a burst of 20, 8 connections per client, and a
30 r/s ceiling across all clients so many addresses together cannot starve
it. Only POST / and GET /status, /health pass; bodies over 64 KiB are refused.
Hetzner and OVH hosting networks get the site's 403, and the name has its own
JSON log.

Checked from outside after install: 405 for other methods and paths, 413 for
a 100 KB body, 32 of 40 parallel requests answered 429, and the log carries
the real client address. /health answers 503 because the node is not synced;
that is neard's own answer, passed through.

Closes #29

Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
Claude-Session: https://claude.ai/code/session_015pkwBsR54NRmZyU4QVhvfj
This commit is contained in:
2026-10-03 12:34:35 +03:00
co-authored by Claude Opus 5.5
parent 0de203c819
commit dc68fe3be3
3 changed files with 136 additions and 4 deletions
+10 -4
View File
@@ -55,7 +55,9 @@ SITE_INDIRECTION="${SITE_INDIRECTION:-bl.thgttg.com}"
# The chains the wallet reaches through this proxy, one public name each:
# `<chain>.blackbeard.observer`. Their upstreams live in
# asset/nginx/blackbeard-nodes.conf; each needs a vhost file of the same name.
NODE_CHAINS="${NODE_CHAINS:-quantus planck}"
# `near` is not a wallet chain: it is our NEAR RPC node (blackbeard/observer#29),
# published the same way and throttled harder in its own vhost.
NODE_CHAINS="${NODE_CHAINS:-quantus planck near}"
CERT_EMAIL="${CERT_EMAIL:-ops@blackbeard.observer}"
PUBKEY=""
@@ -464,7 +466,7 @@ print(cn[0]["content"] if cn else "")')
--data "$(python3 -c '
import json, os
print(json.dumps({"type":"CNAME","name":os.environ["NAME"],"content":os.environ["SITE"],
"ttl":1,"proxied":False,"comment":"Quantus-Network/blackbeard.observer (blackbeard/wallet #53)"}))')" \
"ttl":1,"proxied":False,"comment":"blackbeard.observer node endpoint (blackbeard/observer infra-setup --role nodes)"}))')" \
| python3 -c '
import sys, json
d = json.load(sys.stdin)
@@ -539,9 +541,13 @@ REMOTE
for name in "${names[@]}"; do
info "$name answers"
# Each node is asked something its own RPC understands: NEAR has no
# system_chain, and a Substrate node has no status method.
local method=system_chain params='[]'
case "$name" in near.*) method=status params='{}' ;; esac
curl -sS --max-time 15 -H 'content-type: application/json' \
-d '{"jsonrpc":"2.0","id":1,"method":"system_chain","params":[]}' \
"https://${name}" && echo
-d "{\"jsonrpc\":\"2.0\",\"id\":1,\"method\":\"$method\",\"params\":$params}" \
"https://${name}" | head -c 400 && echo
done
}