feat(infra): our NEAR nodes public by shard, s<id>.near.blackbeard.observer
near.blackbeard.observer reaches only frankie, and a NEAR node refuses any account on a shard it does not track. The wallet's NEAR Intents account (blackbeard/wallet#71) needs reads on every shard its route touches, so each shard one of our nodes tracks now has its own name on oolon: s4/s8 to gargravarr, s7/s13 to frankie, s10/s12 to quadbrat. One vhost and one certificate lineage cover them all, the shard-to-node map sits in blackbeard-nodes.conf with a request ceiling per node, and infra-setup.sh --role nodes provisions them (NEAR_SHARDS). Already applied: DNS, the certificate (to 2027-01-07) and the vhost, all answering status. Every name answers for an account on its shard except s13. That needs a node for wrap.near: adding it to frankie's tracked accounts stalled the node, as CLAUDE.md now records, and was reverted. Refs blackbeard/wallet#73 Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com> Claude-Session: https://claude.ai/code/session_01NUx7SPonBnB3ofU4mH41WT
This commit is contained in:
+34
-11
@@ -58,6 +58,12 @@ SITE_INDIRECTION="${SITE_INDIRECTION:-bl.thgttg.com}"
|
||||
# `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}"
|
||||
# The NEAR shards our nodes track, published as `s<id>.near.blackbeard.observer`
|
||||
# (blackbeard/wallet#73): one vhost (near-shards.blackbeard.observer.conf), one
|
||||
# certificate lineage naming them all, and the shard-to-node map in
|
||||
# blackbeard-nodes.conf. All three change together when NEAR reshards.
|
||||
NEAR_SHARDS="${NEAR_SHARDS:-4 7 8 10 12 13}"
|
||||
NEAR_SHARDS_LINEAGE="near-shards.${PUBLIC_NAME}"
|
||||
CERT_EMAIL="${CERT_EMAIL:-ops@blackbeard.observer}"
|
||||
|
||||
PUBKEY=""
|
||||
@@ -475,24 +481,29 @@ sys.exit(0 if d["success"] else 1)'
|
||||
REMOTE
|
||||
}
|
||||
|
||||
# node_cert LINEAGE [NAME...]: one certificate lineage for the names given, or
|
||||
# for LINEAGE alone. --expand lets a lineage gain a name (a new shard) in place.
|
||||
node_cert() {
|
||||
local name="$1"
|
||||
local lineage="$1"; shift
|
||||
local names="${*:-$lineage}"
|
||||
# Same recipe as role_cert; the deploy hook and timer are host-wide and
|
||||
# already handled there.
|
||||
ssh "$EDGE_HOST" "NAME='$name' CERT_EMAIL='$CERT_EMAIL' bash -euo pipefail" <<'REMOTE'
|
||||
if sudo test -d "/etc/letsencrypt/live/${NAME}"; then
|
||||
echo "certificate lineage ${NAME} already exists"
|
||||
ssh "$EDGE_HOST" "LINEAGE='$lineage' NAMES='$names' CERT_EMAIL='$CERT_EMAIL' bash -euo pipefail" <<'REMOTE'
|
||||
if sudo test -d "/etc/letsencrypt/live/${LINEAGE}"; then
|
||||
echo "certificate lineage ${LINEAGE} already exists"
|
||||
fi
|
||||
domains=()
|
||||
for n in $NAMES; do domains+=(-d "$n"); done
|
||||
sudo certbot certonly \
|
||||
-m "$CERT_EMAIL" --agree-tos --no-eff-email --noninteractive \
|
||||
--cert-name "$NAME" \
|
||||
--cert-name "$LINEAGE" \
|
||||
--key-type ecdsa \
|
||||
--dns-cloudflare \
|
||||
--dns-cloudflare-credentials /root/.certbot-internal \
|
||||
--dns-cloudflare-propagation-seconds 60 \
|
||||
--keep-until-expiring \
|
||||
-d "$NAME"
|
||||
sudo test -f "/etc/letsencrypt/live/${NAME}/fullchain.pem" \
|
||||
--keep-until-expiring --expand \
|
||||
"${domains[@]}"
|
||||
sudo test -f "/etc/letsencrypt/live/${LINEAGE}/fullchain.pem" \
|
||||
|| { echo "certbot reported success but no fullchain.pem exists" >&2; exit 1; }
|
||||
REMOTE
|
||||
}
|
||||
@@ -513,14 +524,26 @@ role_nodes() {
|
||||
node_cert "$name"
|
||||
done
|
||||
|
||||
local shard shard_names=()
|
||||
for shard in $NEAR_SHARDS; do shard_names+=("s${shard}.near.${PUBLIC_NAME}"); done
|
||||
[ -f "$REPO_ROOT/asset/nginx/${NEAR_SHARDS_LINEAGE}.conf" ] \
|
||||
|| { echo "no vhost asset/nginx/${NEAR_SHARDS_LINEAGE}.conf" >&2; return 1; }
|
||||
for name in "${shard_names[@]}"; do
|
||||
info "$EDGE_HOST: public DNS for $name"
|
||||
node_dns "$name"
|
||||
done
|
||||
info "$EDGE_HOST: Let's Encrypt certificate $NEAR_SHARDS_LINEAGE for ${shard_names[*]}"
|
||||
node_cert "$NEAR_SHARDS_LINEAGE" "${shard_names[@]}"
|
||||
|
||||
info "$EDGE_HOST: node upstreams, throttle zones and vhosts"
|
||||
rsync -a --rsync-path 'sudo rsync' \
|
||||
"$REPO_ROOT/asset/nginx/blackbeard-nodes.conf" \
|
||||
"$EDGE_HOST:/etc/nginx/conf.d/blackbeard-nodes.conf"
|
||||
local files=()
|
||||
for name in "${names[@]}"; do files+=("$REPO_ROOT/asset/nginx/${name}.conf"); done
|
||||
files+=("$REPO_ROOT/asset/nginx/${NEAR_SHARDS_LINEAGE}.conf")
|
||||
rsync -a --rsync-path 'sudo rsync' "${files[@]}" "$EDGE_HOST:/etc/nginx/sites-available/"
|
||||
ssh "$EDGE_HOST" "NAMES='${names[*]}' bash -euo pipefail" <<'REMOTE'
|
||||
ssh "$EDGE_HOST" "NAMES='${names[*]} ${NEAR_SHARDS_LINEAGE}' bash -euo pipefail" <<'REMOTE'
|
||||
# Enable, test, and only then reload. A vhost that fails the test is
|
||||
# disabled again before leaving, so a typo here never blocks the next
|
||||
# reload of every other site on this proxy.
|
||||
@@ -539,12 +562,12 @@ role_nodes() {
|
||||
INNER
|
||||
REMOTE
|
||||
|
||||
for name in "${names[@]}"; do
|
||||
for name in "${names[@]}" "${shard_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
|
||||
case "$name" in near.*|s*.near.*) method=status params='{}' ;; esac
|
||||
curl -sS --max-time 15 -H 'content-type: application/json' \
|
||||
-d "{\"jsonrpc\":\"2.0\",\"id\":1,\"method\":\"$method\",\"params\":$params}" \
|
||||
"https://${name}" | head -c 400 && echo
|
||||
|
||||
Reference in New Issue
Block a user