network_info
Current Monero network state: latest indexed height, difficulty, network hashrate and mempool size.
無需輸入參數。

io.github.nowi333由 GitHub 帳號 nowi333 發布v0.5.2更新於 Nov 5, 2026
Live Monero network metrics: reorgs, orphans, pool centralization and the Haveno order book.
唯讀的 Monero 網路觀測服務:重組、孤塊、礦池集中度、網路指標,以及 Haveno 點對點訂單簿。
Web executable,透過 Streamable HTTP。 遠端服務在工作區中設定後即可從網頁執行環境執行。
把這段提示詞貼上到 Claude Code、Codex、Cursor 等代理程式,或 SourceWeft 對話中。代理程式會讀取該伺服器的安裝指南,先向你展示發布者、端點和登入方式,經你同意後再把它新增到你的客戶端。金鑰不會寫進任何命令。
閱讀 https://sourceweft.com/mcp/io.github.nowi333%2Fmonerometrics/install.md,並按其中說明把這個 MCP 伺服器接入我的客戶端。修改任何設定之前,先告訴我它的發布者、端點和登入方式,等我確認。不要把 API 金鑰寫進命令或我會提交的檔案;問我金鑰應從哪裡取得。把它新增到你客戶端的 mcpServers 設定中。
{
"mcpServers": {
"monerometrics": {
"type": "http",
"url": "https://api.monerometrics.net/mcp"
}
}
}A reorg-aware observatory for the health of the Monero network: public dashboard + API.
[License] [IaC] [Monero] [Kuno]
monerometrics is community-funded. A Kuno campaign funds the next two years: hosting, FCMP++ readiness, free reorg alerts, open data export and a second node.
monerometrics measures and historizes the health of the Monero network: network hashrate,
block time, mempool state, mining-pool distribution and, above all, chain reorganizations
(reorgs) and orphan blocks, which most block explorers surface poorly.
The project was born from the August 2025 Qubic episode, during which a mining pool paying miners in its own token approached a majority of the network hashrate, then withheld blocks and released a longer private chain. On 14 September 2025 that produced an 18-block reorganization at height 3,499,659 that erased about 36 minutes of history, well past the 10 confirmations everyone treated as final: transactions thought settled were suddenly unconfirmed again. The public debate lacked reliable, accessible data to settle it. monerometrics fills that gap with a neutral, verifiable, reorg-aware observatory.
It is open-source and self-funded, with no ads and no tracking. The dashboard and the API are free and open, permanently: there is no paid tier, and there will not be one.
From a diploma project to a community tool. monerometrics V1 was built and defended as a French professional IT-infrastructure project, and it earned the diploma. With that chapter closed, the goal of V2 is to hand the project over to the Monero community.
https://api.monerometrics.net/mcp (Streamable HTTP; in the MCP Registry)6wbhchvavey26lbtscl6w6qg76balycixtsklcggrsslyk4xah6sbbad.onion
(dashboard + API, no Cloudflare, no IP exposure, see Access over Tor)Dashboard, a React SPA in four sections, available in English, French and Spanish, light and dark themes, readable on a phone:
Public API: FastAPI, read-only JSON endpoints grouped by theme, documented via OpenAPI.
Reorg detection: a Python worker reads each block from a synced node, computes the indicators and detects reorganizations by re-checking a rolling window of recent blocks against the node, recording their real depth and the transactions they displaced.
A visitor reaches the dashboard or API through Cloudflare, which terminates TLS and applies its edge protections, then forwards to a hardened edge server (nginx + ModSecurity WAF). The edge serves the static dashboard and reverse-proxies the API to the k3s node, where the application core runs: a Monero node, the indexer, PostgreSQL and the API.
A second, independent path exists: a Tor hidden service running on the edge, which bypasses Cloudflare entirely and serves both the dashboard and the API on a single origin, behind the same WAF.
The dashboard is also published as a Tor v3 hidden service, giving a path to the data that does not depend on Cloudflare and does not expose the visitor's IP address:
/ and reverse-proxies the
API under /api. The SPA detects an .onion host at runtime and switches to that relative path,
so no browser request ever leaves the hidden service for the clearnet. One build serves both..onion
address is the service's public key..onion vhost listens on 127.0.0.1:8080 only, so the
Tor daemon is the sole thing that can reach it. Tor makes outbound connections only.127.0.0.1, so access logging on this vhost would record
nothing useful and is disabled.Onion-Location header.Deployed by the tor Ansible role (config/ansible/roles/tor/).
The platform runs on Hetzner Cloud (Nuremberg) as two Ubuntu 24.04 servers on a private
network, each behind its own firewall. Neither exposes SSH to the internet: administration goes
only over a Tailscale (WireGuard) mesh joined by both servers, and Grafana is reachable over
Tailscale only. Backups are paused: the tooling (Restic, encrypted,
see k8s/monerometrics/BACKUP-PRA.md) stays in the repository,
but no scheduled backup runs today.
Key choices: per-server firewalls, no public SSH anywhere, a WAF on the only public web surface, a zero-trust admin mesh, and a k3s node exposing nothing but the Monero P2P port. A dedicated SSH bastion was dropped in October 2026: Tailscale already gave a zero-trust entry point, so the extra server only added cost. Tailscale's own SSH is disabled; plain OpenSSH with keys runs over the mesh, so access never depends on a browser re-validation. Both hops run HTTP/2 with the WAF active. Everything is Infrastructure-as-Code: Hetzner and Cloudflare resources via Terraform, server configuration and CIS-aligned hardening via Ansible, images published to GHCR. Supervision with Prometheus + Grafana, with alert rules on indexing, node sync, disk and failing workloads. The backup tooling (Restic) is kept but paused.
Secrets. The cluster is provisioned with OpenBao (a free fork of Vault) and the manifests
carry no plaintext credential. OpenBao unseals itself on start (static seal, key held in a
Kubernetes Secret created outside the repository); the workloads can also fall back to a Kubernetes
Secret (postgres-credentials-fallback), so a sealed vault never takes the service down.
Hetzner list prices, monthly cap, including 20 % VAT:
Cloudflare, Let's Encrypt, Tailscale and GitHub Actions are on free tiers.
The volume is the item that moves, and the chain drives it, not indexing. The pruned Monero blockchain takes 106 GB; the entire indexed database, 3.77 M blocks and every time series, takes 3.1 GB, about 540 bytes per block, and grows by roughly 150 MB a year.
Growth is measured from the indexed data rather than estimated. Summing the recorded size of every canonical block gives 186.8 GB for the full chain, so this pruned node keeps a bit over half of Monero. The chain grew 22.18 GB over the last twelve full months, which is 12.35 GB a year on disk, steady across years (17.5 GB in 2022, 18.3 in 2023, 29.1 in 2024, 22.2 in 2025). The volume reached 94 % of 128 GB, so it was taken to 250 GB in October 2026, funded by the community (Kuno milestone 1). That leaves room well beyond the two years promised, which also absorbs the heavier transactions FCMP++ will bring. Removing the SSH bastion the same month paid for most of the difference.
The worker (apps/worker/indexer.py) is the heart of the project. Every
POLL_INTERVAL seconds it asks monerod for its state and, when the node is synced, runs three
passes:
Confirmation-window rescan (reorg detection). It re-fetches the headers of the last
CONFIRMATION_WINDOW blocks (default 60) in one call and compares each hash to the canonical
hash already stored. Any mismatch is a reorganization: the stored block is flagged orphan
(is_canonical = false), the node's block becomes canonical, and a row is written to
reorgs_detected with the real depth and the affected transaction count. This pass is
what makes reorg detection work at all: forward-only indexing never revisits the past, so it
would silently miss every reorg that rewrites already-indexed heights.
The window is also the detection ceiling. A reorganization deeper than CONFIRMATION_WINDOW
rewrites heights the rescan never looks at, so it would be missed entirely rather than reported
with a wrong depth. At 60 blocks the margin is wide, the deepest Monero reorg on record was 18
blocks, but the limit is structural and the counts published here are complete only up to that
depth. Raising it costs one larger header call per poll.
The transaction count is num_txes, which excludes the coinbase, so it counts transactions
users actually broadcast rather than the miner's own output.
Forward indexing. It fetches the blocks above the last indexed height. Close to the tip it pulls full blocks one by one for accurate attribution; far behind (fresh deploy) it switches to a fast header backfill (~1000 blocks per call), enough for the network-health series and fast enough to fill the long windows in under two hours instead of never.
Alternative chains (orphans). Most competing blocks are settled within seconds, long before
the next poll, so the rescan above never sees them: it only catches a block we had already
indexed. The worker therefore also reads the node's own alternative chains
(get_alternate_chains, on an RPC port only the worker can reach) and records every competing
block as an orphan. Before this pass, about one orphan in four was recorded.
Observability. The worker exposes Prometheus metrics on :9100/metrics (indexing lag, reorg
counter, sync state, pool-index size, blocks proven by view key, attribution conflicts) and writes
a heartbeat file consumed by a Kubernetes liveness probe. The heartbeat is written only after a
successful pass, so a loop that keeps failing is restarted and raises the WorkerStalled alert.
Monero is private by design: a coinbase carries no pool name, and stealth addresses mean you cannot look up "who was paid". Attribution has to be established, never assumed.
monerometrics never infers a pool's share from its self-reported hashrate. It only counts
blocks it can tie to a pool by evidence, and records which kind of evidence was used, per
block, in blocks.pool_source.
1. View-key proof, cryptographic (viewkey_proof). Some pools publish their wallet primary
address and secret view key (see blocks.p2pool.observer/proofs).
A view key only reveals incoming transactions; it cannot spend. That is enough to prove ownership
of a coinbase output, with no trust in anyone's API:
If P_expected equals the output key at index i, that output pays the pool's wallet: a
mathematical fact, independent of any pool API, and therefore immune to the reporting lag that
makes fresh blocks look unattributed. Implemented from scratch in
apps/worker/pool_proofs.py (ed25519 point arithmetic, Keccak-256,
Monero base58), about 33 ms per block.
2. Pool block lists, cross-referenced (pool_api). Pools that publish no view key still publish
the blocks they found. Those lists are aggregated every ~2 minutes into an index
{block_hash → pool} and matched by block hash, so the claim is anchored to a real block. The
weakness is latency, not correctness: a pool slow to publish leaves its own recent blocks looking
unknown until it catches up. A re-attribution pass on every cycle fixes those retroactively.
3. Coinbase heuristic, structural (coinbase_heuristic). A coinbase paying many outputs at once
is characteristic of P2Pool, which splits the reward on-chain. Last resort, labelled as a heuristic.
monerometrics_attribution_conflicts_total.pool_api_unproven rather than shown with the same confidence./pools/sources, so
a silently failing source is visible instead of quietly inflating unknown.P2Pool runs three sidechains (main/mini/nano); all three are polled and collapsed into a single
p2pool label, since they are one decentralised network from a centralisation standpoint.
About a fifth of blocks end up unknown (21.9 % over the last 7 days, against 45.8 % proven
cryptographically and the rest claimed by a pool API or inferred), and that number is reported
as-is rather than smoothed over. The reasons are structural:
Every public tracker hits this same ceiling; comparable sites report an even larger unknown share. Shrinking that fifth is the main open work on the project.
A merge-mined block is one where a single proof-of-work claims both a Monero block and a block on
an auxiliary chain. The indexer detects it from the 0x03 tag in the coinbase tx_extra; the share
over a window is published by /chain/provenance
and marked with an M on each block in the fork visualizer.
It is tracked because it is a centralization vector: an auxiliary chain can subsidise miners and pull hashrate toward whichever pool supports it, and concentrated hashrate is what makes a reorganization possible in the first place.
It is not, however, what Qubic did. Qubic ran a "useful proof-of-work" scheme: it paid miners in its own token by converting the mined XMR, at one point roughly three times more lucrative than ordinary mining, taking its share from under 2 % in May 2025 to a claimed majority by August. The subsidy was economic, routed through a pool, not merge mining through the coinbase. Conflating the two would be wrong.
About 60 % of blocks are merge-mined over the last 7 days. That share is not a network-wide drift, it is a per-pool policy: supportxmr, p2pool, c3pool and moneroocean merge-mine every block they find, hashvault most of them, while nanopool, herominers, xmrpool and kryptex merge-mine none. The curve therefore tracks which pool is finding blocks this week as much as any change in practice. The auxiliary chain is not named: the on-chain tag carries only a Merkle root, so identifying it would require querying that chain. We report the count and the root rather than guessing.
PostgreSQL, read-only from the API's point of view. Two tables carry the chain record
(k8s/monerometrics/20-configmap-postgres-init.yaml):
blocks, whose primary key is the block hash, not the height. This is deliberate: it
lets several blocks coexist at the same height (the canonical one plus the orphans left by a
reorg). A partial unique index (UNIQUE (height) WHERE is_canonical) guarantees exactly one
canonical block per height at any instant. pool_source records how the pool was
established for that block, so a consumer can weigh a cryptographic proof differently from a
pool's own claim. reward_xmr is an exact NUMERIC, never a float.reorgs_detected, one row per detected event: fork_point_height, depth,
old_chain_tip_hash, new_chain_tip_hash, affected_tx_count, detected_at.
fork_point_height is the first height that was replaced: the event rewrote heights
fork_point_height to fork_point_height + depth - 1.The orphan/canonical split is what powers the fork visualizer and the /orphans/recent and
/reorgs/stats endpoints.
The rest are time series, created by the worker on first run:
Every one of them is a cache, not a source of truth: the chain tables are re-derivable from any
monerod, and the market tables from haveno.markets. That property is what makes the
high-availability plan below cheap.
Two series are the exception and cannot be rebuilt: mempool snapshots and reorgs. Once transactions are mined, nothing on-chain says how many were pending an hour ago, and a discarded block exists in no explorer. Both start the day this observatory began watching, and are kept rather than pruned for that reason.
The API (apps/api/) is read-only and returns JSON, built with FastAPI, with an
interactive OpenAPI schema at api.monerometrics.net/docs.
Heavy aggregations are cached server-side, and every response carries its own lifetime
(Cache-Control + ETag), so a client that already holds a version gets an empty 304. Every IP
is rate-limited (300 requests/minute; Tor traffic has its own shared bucket). CORS is open for
GET. No key, no account, no tracking.
window accepts 1h, 24h, 7d, 30d, 90d, 1y, 5y unless noted otherwise.
Service
Network
Chain & reorgs
Mining pools
Market
Other
Discovery. Beyond the documented API, the service answers the agent-discovery conventions
crawlers actually ask for: llms.txt, agents.json, agent cards, mcp.json, OpenRPC,
ai-plugin.json, x402, owners.json, and the OAuth protected-resource metadata at both the bare
path and the RFC 9728 form. Requests for endpoints that do not exist get a JSON body listing the
interfaces that do, rather than a bare 404. What the service deliberately does not answer is
/v1/models and its variants: those probes look for an OpenAI-compatible inference API, and
answering them would advertise a capability this project does not have.
The interesting question about a no-KYC exchange is not what Monero costs there, it is what makes it cost more. Grouping every executed trade by payment method answers it, and the answer is not the intuitive one:
USD market, 180 days to 24 August 2026, spot reference Kraken daily close.
The premium tracks reversibility, not privacy. A buyer who pays by PayPal or Cash App can file a chargeback after the Monero has been released, and there is no recourse, so sellers price that risk in at nine to fifteen percent. Rails that cannot be reversed sit near one to three percent. Cash in an envelope, the most private method on the list, is among the cheapest and carries the largest volume of any rail.
The reversible flag is our classification, not a Haveno field. Revolut is left unclassified: a transfer between Revolut accounts is final in principle, but the bank accepts fraud disputes, and its premium sits with the final rails. Methods with a handful of
trades produce a fragile premium, the spot reference is a daily close, and trades before September
2024 fall outside Kraken's window and carry no premium at all. Crypto pairs are excluded:
haveno.markets quotes them inverted.
Reading the premium. ask_premium_pct compares the lowest ask to spot; ask_avg_premium_pct
compares the amount-weighted average of every sell offer. The gap between the two averages is
round_trip_cost_pct, the cost of buying and selling back, and it is the number that survives
contact with reality: around 20 %, against a headline premium near 8 %. It is deliberately built
from amount-weighted averages rather than the best offer on each side, so read it as an upper
bound: the best offer has been backed by as little as 1.49 XMR. A small trade that never leaves
the first price level does better; a trade that walks the book does not.
Scope: fiat markets only. Haveno runs 34 markets, but roughly 95 % of the headline liquidity is
crypto pairs, whose premium is always near zero because a crypto-to-crypto swap is instant and needs
no counterparty. Fiat peer-to-peer involves a real person, chargeback exposure and delay, which is
the only reason a premium exists. Every figure here is XMR_USD unless stated, so it reads far
smaller than the site-wide total, by design. Note that XMR_USD is fiat US dollars: the stablecoin
pairs are listed separately.
What these numbers are not. The series behind /price/spread carry price, amount and offer
count but not the payment method, because the level-1 depth feed does not expose it. The lowest
ask is therefore not the price of buying Monero privately, it is the price of the most competitive
offer, whatever its rail. /haveno/book is the exception: it reads the level-2 feed, so each price
level carries its payment methods. History starts on 24 August 2026, when recording began, because
haveno.markets exposes no historical series and the spread cannot be backfilled.
The same read-only metrics are exposed to AI assistants through a Model Context Protocol server
(apps/mcp/), so any MCP-compatible client can query the Monero network directly, no
account, no API key.
https://api.monerometrics.net/mcpio.github.nowi333/monerometrics in the
MCP Registry.network_info, network_hashrate, network_blocktime, network_mempool,
network_emission, reorgs, reorg_stats, recent_orphans, pool_distribution,
pool_sources, chain_provenance, search_block, get_block, chain_fork_window, price,
haveno_book, haveno_premium, haveno_payment_methods, plus a monerometrics://reference
resource.It is a thin wrapper over the public REST API, deployed alongside it on k3s and routed at /mcp.
The whole platform is reproducible from code. With a Hetzner project, a Cloudflare-managed domain and the required tokens in your environment:
Configuration drift. Server configuration is only changed through Ansible, never by hand. Before and after any change, a dry run must report nothing to change on any host:
common_apt_upgrade=false skips the full package upgrade, so a config-only run never upgrades
production by surprise; security patches come from unattended-upgrades.
Server sizing, datacenter and volume size are Terraform variables (see
infra/environments/poc/terraform.tfvars.example).
No plaintext credential is committed. The cluster ships OpenBao: seed the database credentials
once (secret/postgres/credentials) and every consumer can read them from there. OpenBao unseals itself
on start; if it ever cannot, the workloads read a Kubernetes Secret instead.
The dashboard reads the public API; point it at api.monerometrics.net (see src/api.js).
What runs today is a deliberately lean single-node POC: one k3s node, one unreplicated PostgreSQL, one edge. It is honest, cheap (~35 €/month including VAT) and enough to prove the product, but all three are single points of failure.
One property makes high availability unusually cheap here: every metric is deterministically
derived from the Monero blockchain. The database is a materialized cache, so any replica or whole
region can be re-indexed from its own local monerod. Reads are therefore naturally
active-active, and losing a stack means rebuilding from first principles, not losing data. The two
exceptions are the mempool and reorg series, which are observations rather than derivations.
The plan removes the SPOFs in tiers, each independently fundable, so infrastructure grows with the project's community funding rather than ahead of it:
nbg1 / fsn1 / hel1), with a
synchronous PostgreSQL replica in a second zone for near-zero RPO and an asynchronous copy in a
third. The etcd quorum and edge pool then survive the loss of an entire zone.scripts/load-env.sh) or from OpenBao. Terraform state is kept out of the repo.Questions about the methodology, a number that looks wrong, a pool wanting its view key indexed, or a researcher after a dataset: [email protected]. Bug reports and feature requests are better as GitHub issues, where they stay public and searchable.
monerometrics runs on a modest self-funded infrastructure (no ads, no tracking, no data sold), about 35 € a month including VAT. Donations in XMR go to:
Any other cryptocurrency works too, settled to that address with no account and no KYC, through trocador.app AnonPay.
The same address is published on the dashboard and in
/.well-known/owners.json, so it can be
cross-checked against three independent sources before you send anything.
MIT, see LICENSE.
No advertising. No tracking. No data sold. Just Monero network data, done honestly.
來源:README.md,提交 d3f013b
Current Monero network state: latest indexed height, difficulty, network hashrate and mempool size.
無需輸入參數。
Current Monero (XMR) price: centralized spot plus both sides of the Haveno peer-to-peer book. Returns the best offer and the amount-weighted average on each side, resting depth, offer counts, and round_trip_cost_pct: the cost of buying XMR and selling it straight back, which is far larger than the headline premium.
無需輸入參數。
The live Haveno XMR/USD order book, both sides, priced against centralized spot. Each price level carries its cumulative depth, offer count, payment methods and a reversible flag. `asks` are makers selling XMR, so taking one means buying; `bids` are makers buying, so taking one means selling. Offers are advertisements with differing payment methods rather than a matched book, so nothing executes on its own and the best bid can sit at or above the best ask.
無需輸入參數。
Haveno peer-to-peer quotes against centralized spot over time, both sides. window in 24h,7d,30d,90d,1y. History starts on 24 August 2026, when recording began.
windowExecuted Haveno trades grouped by payment method, with the premium over spot. window in 30d,90d,180d,1y,all. currency in USD,EUR. The premium tracks how reversible and convenient the payment rail is, not privacy: every one of these trades is equally non-KYC. The reversible flag is our own classification, not a Haveno field.
windowcurrencyNetwork hashrate time series. window in 1h,24h,7d,30d,90d,1y,5y.
windowBlock-time variance time series (seconds between blocks). window in 1h,24h,7d,30d,90d,1y,5y.
windowMempool size time series (number of pending transactions). window in 1h,24h,7d,30d,90d,1y,5y.
windowBlock reward / emission time series (XMR per block). window in 1h,24h,7d,30d,90d,1y,5y.
windowDetected Monero chain reorganizations, most recent first, with fork point, depth and affected transactions.
無需輸入參數。
Aggregate reorg statistics over windows: counts, average and maximum depth, affected transactions.
無需輸入參數。
Most recent orphan blocks with their canonical counterpart at the same height, newest first. limit 1..50; window in 24h,48h,7d,30d,90d,180d,1y,all (default all, so the last N orphans are returned however old they are).
limitwindowMining-pool distribution over a window: block share per pool, largest-pool share and the Nakamoto coefficient (minimum pools controlling >50% of blocks). window in 1h,6h,24h,48h,7d.
windowReachability status of each mining-pool API used for block attribution.
無需輸入參數。
How mining-pool attribution was established over a window: share proven by view key, claimed by pool API, inferred from coinbase, or unattributed. window in 1h,6h,24h,48h,7d.
windowFull detail for one block by its 64-character block hash: height, previous hash, size, difficulty, reward, coinbase, transaction list and merge-mining tags.
hash必填Find a block by height (a number) or by 64-character hash, anywhere in the chain down to the genesis block (height 0). Returns the block detail plus whether it is canonical or an orphan.
query必填Look up a transaction by its 64-character hash: whether it is in the mempool or mined, its block, confirmations, whether it is spendable yet, the pool that mined its block, and whether that height was ever contested by a reorg. No amounts, senders or recipients: the protocol encrypts them.
tx_hash必填Canonical chain plus any competing orphan blocks around a height. 'to' is the highest height in the window (defaults to the current tip); lower it to browse older history down to the genesis block. limit 10..500.
tolimit已滿足適用檢查項的 100%
該評分衡量此收錄條目的完整程度,依據註冊中心條目、端點與公開來源計算得出。它不是對伺服器本身的評價,也不表示伺服器安全或目前可用:可連通性是帶日期的檢查結果,評分也不包含安裝量或使用者評價。
flowchart LR User(["Visitor"]) -->|HTTPS| CF["Cloudflare<br/>DNS · WAF · proxy"] CF -->|"HTTP/2 origin pull"| Edge Tor(["Tor visitor"]) -.->|"Tor network"| Onion subgraph HZ["Hetzner Cloud · private network 10.0.0.0/24"] Onion["tor daemon<br/>hidden service v3"] Edge["edge 10.0.0.20<br/>nginx + ModSecurity WAF<br/>static dashboard"] Onion -.->|"127.0.0.1:8080"| Edge subgraph K3S["k3s 10.0.0.30 · no public ingress"] API["FastAPI"] Worker["Python worker<br/>(indexer)"] DB[("PostgreSQL 17")] Node["monerod 0.18<br/>pruned"] end Edge -->|"api. proxy_pass"| API API --> DB Worker --> DB Worker -->|JSON-RPC| Node end Node <-->|"P2P sync"| Monero(["Monero network"]) API -.->|"XMR price (cached)"| Price(["CoinGecko · Kraken<br/>Haveno (RetoSwap)"])6wbhchvavey26lbtscl6w6qg76balycixtsklcggrsslyk4xah6sbbad.onionflowchart TB Admin(["Administrator"]) -->|"SSH over Tailscale"| Mesh Internet(["Internet"]) -->|"80 / 443 via Cloudflare"| Edge subgraph HZ["Hetzner Cloud (nbg1) · 10.0.0.0/24"] Edge["edge 10.0.0.20<br/>firewall: 80/443 from Cloudflare only"] K3s["k3s 10.0.0.30 + data volume<br/>firewall: no inbound (P2P 18080 only)"] Edge -->|"private network"| K3s end Mesh["Tailscale mesh<br/>(admin SSH · kubectl · Grafana)"] Mesh --- Edge Mesh --- K3sflowchart TB Start(["Every POLL_INTERVAL"]) --> Info["GET /get_info"] Info --> Sync{"node synced?"} Sync -->|no| Wait["log progress · sleep"] Sync -->|yes| Rescan["Rescan last N blocks<br/>get_block_headers_range"] Rescan --> Diff{"stored hash<br/>≠ node hash?"} Diff -->|yes| Reorg["mark old → orphan<br/>insert new canonical<br/>record reorg (depth, tx)"] Diff -->|no| Fwd Reorg --> Fwd["Forward index<br/>new blocks (batch)"] Fwd --> Alt["Read alternative chains<br/>record orphans"] Alt --> Metrics["update Prometheus metrics"] Metrics --> StartR = transaction public key, parsed out of the coinbase tx_extra (tag 0x01)derivation = 8 · a · R (a = the pool's secret view key)P_expected = Hs(derivation ‖ varint(i)) · G + B (B = the pool's public spend key)apps/ Application code dashboard/ React + Vite SPA (EN/FR/ES) api/ FastAPI service mcp/ Model Context Protocol server (thin wrapper over the API) worker/ Python indexer (reorg detection) + shared pool moduleinfra/ Terraform, modules (network, server, dns) + environmentsconfig/ Ansible, inventory, playbooks, roles (hardening, nginx, tor, k3s, ...)k8s/ Kubernetes (k3s) manifests + backup/DR runbook (BACKUP-PRA.md)scripts/ Helpers (env loader)source scripts/load-env.sh # tokens from the keychain
cd infra/environments/pocterraform init && terraform apply # servers, private network, firewalls, DNS
cd ../../../config/ansibleansible-playbook site.yml # CIS L1 hardening, nginx+WAF, k3s, Tailscale, tor
kubectl apply -k k8s/monerometrics/ # application workloadsansible-playbook site.yml --check --diff -e common_apt_upgrade=falsecd apps/dashboardnpm installnpm run dev # local dev servernpm run build # production build to dist/flowchart TB CF["Cloudflare · DNS / WAF / proxy"] --> LB["Load balancer"] subgraph R1["Region"] LB --> E1["edge-1<br/>nginx + WAF"] LB --> E2["edge-2<br/>nginx + WAF"] subgraph K3S["k3s HA · etcd quorum"] S1(["server-1"]) --- S2(["server-2"]) --- S3(["server-3"]) end E1 --> K3S E2 --> K3S subgraph PG["PostgreSQL HA"] PGp[("primary")] --> PGr[("replicas")] end K3S -->|writes| PGp K3S -.reads.-> PGr K3S --> N1["monerod-1"] K3S --> N2["monerod-2"] end N1 <--> MN(["Monero P2P network"]) N2 <--> MN R1 -->|"encrypted 3-2-1"| OCI[("off-site backups")]492qrWLgcdd9vUQFeq2mZMUSa2KU7UT3fRpajqNPiQoHNpRUZX1CiGMQeCok2CusfLWXWsZ3KaNL6PkakAxgXyeMRhkM65s