public node endpoints: one name per chain on oolon, throttled, routed to bob #53

Closed
opened 2026-09-15 13:00:55 +00:00 by grenade · 1 comment
Owner

Parent: #3. The infrastructure half of #20's decision (see the correction there dated 2026-09-15).

Scope

  • DNS: quantus.blackbeard.observer and planck.blackbeard.observer (per architecture/public-dns.md), pointing at oolon.
  • nginx on oolon: one vhost per chain name, Let's Encrypt via the existing external-TLS pattern (architecture/external-tls.md), and one upstream per chain in conf.d/ so adding a server is one line:
    • quantus_node: bob's node over the mesh (the only node we run). The two public mainnet archive nodes the observer already uses as fallbacks may join as backup servers.
    • planck_node: a1-planck.quantus.cat and a2-planck.quantus.cat, the official Quantus endpoints. We run no testnet node. This is a TLS upstream, so proxy_pass https://, proxy_ssl_server_name on, and proxy_ssl_name per server so SNI is right.
    • Proxy both HTTP JSON-RPC POST / and the WebSocket upgrade on the same name, with proxy_read_timeout long enough for subscriptions and a health check that removes a dead upstream server.
  • Throttling: limit_req_zone keyed on client address for HTTP RPC, limit_conn_zone for concurrent WebSockets per client (limit_req only sees the upgrade handshake), sane bursts, and a 429/503 the wallet reads as "throttled, back off" rather than "node down". Record the chosen numbers in the vhost comments. Throttling on the Planck name also protects Quantus's public nodes from us.
  • bob: the node's RPC listens on loopback for the observer today. Expose it to oolon over the mesh only (firewalld service scoped to the mesh source, architecture/internal-tls.md if the hop is encrypted), --rpc-methods safe, --rpc-cors for the public name, --rpc-max-connections sized for the throttle.
  • Where it lives: oolon's vhosts and bob's node service are deployed from blackbeard/observer's workflow today. Put the vhost, upstream and firewalld files in that repo's asset/ and deploy job, and link the commit here, unless a wallet-owned deploy is preferred (say why on this issue if so).

Why Planck at all

Planck is in the wallet only to prove the multi-chain UX end to end, until a real post-quantum mainnet that is not Quantus exists. Heisenberg is not needed; if Planck is ever retired, the same pattern proxies whichever testnet Quantus keeps.

Acceptance

websocat wss://quantus.blackbeard.observer answers system_chain with Quantus; planck.blackbeard.observer answers Planck. Taking one Planck upstream out of DNS or having it time out does not break the name. Hammering either name from one address gets throttled while a second address is unaffected. The certificate renews unattended. The wallet's profile for each chain lists only that name.

Depends on

Nothing in the wallet code; #20 consumes the result.

Parent: #3. The infrastructure half of #20's decision (see the correction there dated 2026-09-15). ## Scope - **DNS**: `quantus.blackbeard.observer` and `planck.blackbeard.observer` (per `architecture/public-dns.md`), pointing at oolon. - **nginx on oolon**: one vhost per chain name, Let's Encrypt via the existing external-TLS pattern (`architecture/external-tls.md`), and one `upstream` per chain in `conf.d/` so adding a server is one line: - `quantus_node`: bob's node over the mesh (the only node we run). The two public mainnet archive nodes the observer already uses as fallbacks may join as `backup` servers. - `planck_node`: `a1-planck.quantus.cat` and `a2-planck.quantus.cat`, the official Quantus endpoints. We run no testnet node. This is a TLS upstream, so `proxy_pass https://`, `proxy_ssl_server_name on`, and `proxy_ssl_name` per server so SNI is right. - Proxy both HTTP JSON-RPC `POST /` and the WebSocket upgrade on the same name, with `proxy_read_timeout` long enough for subscriptions and a health check that removes a dead upstream server. - **Throttling**: `limit_req_zone` keyed on client address for HTTP RPC, `limit_conn_zone` for concurrent WebSockets per client (`limit_req` only sees the upgrade handshake), sane bursts, and a `429`/`503` the wallet reads as "throttled, back off" rather than "node down". Record the chosen numbers in the vhost comments. Throttling on the Planck name also protects Quantus's public nodes from us. - **bob**: the node's RPC listens on loopback for the observer today. Expose it to oolon over the mesh only (firewalld service scoped to the mesh source, `architecture/internal-tls.md` if the hop is encrypted), `--rpc-methods safe`, `--rpc-cors` for the public name, `--rpc-max-connections` sized for the throttle. - **Where it lives**: oolon's vhosts and bob's node service are deployed from `blackbeard/observer`'s workflow today. Put the vhost, upstream and firewalld files in that repo's `asset/` and deploy job, and link the commit here, unless a wallet-owned deploy is preferred (say why on this issue if so). ## Why Planck at all Planck is in the wallet only to prove the multi-chain UX end to end, until a real post-quantum mainnet that is not Quantus exists. Heisenberg is not needed; if Planck is ever retired, the same pattern proxies whichever testnet Quantus keeps. ## Acceptance `websocat wss://quantus.blackbeard.observer` answers `system_chain` with `Quantus`; `planck.blackbeard.observer` answers `Planck`. Taking one Planck upstream out of DNS or having it time out does not break the name. Hammering either name from one address gets throttled while a second address is unaffected. The certificate renews unattended. The wallet's profile for each chain lists only that name. ## Depends on Nothing in the wallet code; #20 consumes the result.
grenade added the child label 2026-09-15 13:01:05 +00:00
Author
Owner

Done, 2026-09-16. The files live where the issue asked:

  • Quantus-Network/blackbeard.observer 54db950: asset/nginx/blackbeard-nodes.conf (upstreams quantus_node → bob:9944 over the mesh, planck_node → a1/a2-planck.quantus.cat:443 with max_fails=3 fail_timeout=30s; limit_req_zone node_rpc 20r/s, limit_conn_zone node_conn), asset/nginx/quantus.blackbeard.observer.conf and planck.blackbeard.observer.conf (LE cert, TLS 1.2+1.3, limit_req burst=40 nodelay, limit_conn 16, 429 on both, 3600 s socket timeouts, 1 MiB bodies; the Planck one is proxy_pass https with proxy_ssl_server_name on, proxy_ssl_name a1-planck.quantus.cat, verification against the system CA bundle, since both hosts sit behind one *.quantus.cat certificate), and a nodes role in script/infra-setup.sh that creates the CNAME to bl.thgttg.com, issues the certificate, installs the vhosts and enables them only after nginx -t passes.
  • lair/quantus 404c65a: bob's matrix entry gains rpc_extra_sources: "oolon.kosherinata.internal", resolved on the node into a /32 rich rule for quantus-node-rpc beside the site-subnet rule. Applied by hand on bob with the same command, then codified.

Acceptance, as run:

check result
system_chain over HTTPS Quantus and Planck
system_chain over WSS both answer; chain_subscribeNewHeads on the quantus name delivered a head
throttling 120 requests from one address, 40 in parallel: 19×200, 101×429; five from bob at the same time all 200
certificates both to 2026-12-15, certbot-renew.timer enabled and active on oolon, host-wide reload hook present
wallet profiles list only wss://quantus.blackbeard.observer / wss://planck.blackbeard.observer; the ignored planck_accepts_the_signature… test passes against the public name

Two notes. nginx open source has no active health checks, so "taking one Planck upstream out of DNS" is covered by passive max_fails/fail_timeout (a failing server is skipped for 30 s) rather than tested by pulling a record; and a resolver that looked the quantus name up before the record existed caches the miss for a while, which is what the script's own final curl hit.

Done, 2026-09-16. The files live where the issue asked: - **Quantus-Network/blackbeard.observer** `54db950`: `asset/nginx/blackbeard-nodes.conf` (upstreams `quantus_node` → bob:9944 over the mesh, `planck_node` → a1/a2-planck.quantus.cat:443 with `max_fails=3 fail_timeout=30s`; `limit_req_zone node_rpc 20r/s`, `limit_conn_zone node_conn`), `asset/nginx/quantus.blackbeard.observer.conf` and `planck.blackbeard.observer.conf` (LE cert, TLS 1.2+1.3, `limit_req burst=40 nodelay`, `limit_conn 16`, 429 on both, 3600 s socket timeouts, 1 MiB bodies; the Planck one is `proxy_pass https` with `proxy_ssl_server_name on`, `proxy_ssl_name a1-planck.quantus.cat`, verification against the system CA bundle, since both hosts sit behind one `*.quantus.cat` certificate), and a `nodes` role in `script/infra-setup.sh` that creates the CNAME to `bl.thgttg.com`, issues the certificate, installs the vhosts and enables them only after `nginx -t` passes. - **lair/quantus** `404c65a`: bob's matrix entry gains `rpc_extra_sources: "oolon.kosherinata.internal"`, resolved on the node into a `/32` rich rule for `quantus-node-rpc` beside the site-subnet rule. Applied by hand on bob with the same command, then codified. Acceptance, as run: | check | result | |---|---| | `system_chain` over HTTPS | `Quantus` and `Planck` | | `system_chain` over WSS | both answer; `chain_subscribeNewHeads` on the quantus name delivered a head | | throttling | 120 requests from one address, 40 in parallel: 19×200, 101×429; five from bob at the same time all 200 | | certificates | both to 2026-12-15, `certbot-renew.timer` enabled and active on oolon, host-wide reload hook present | | wallet profiles | list only `wss://quantus.blackbeard.observer` / `wss://planck.blackbeard.observer`; the ignored `planck_accepts_the_signature…` test passes against the public name | Two notes. nginx open source has no active health checks, so "taking one Planck upstream out of DNS" is covered by passive `max_fails`/`fail_timeout` (a failing server is skipped for 30 s) rather than tested by pulling a record; and a resolver that looked the quantus name up before the record existed caches the miss for a while, which is what the script's own final curl hit.
Sign in to join this conversation.
1 Participants
Notifications
Due Date
No due date set.
Dependencies

No dependencies set.

Reference: blackbeard/wallet#53