Architecture
One container, one Go process, a few children.
┌────────────────────────── container ───────────────────────────┐
API / MCP :8080 ─┤ docker-monero (Go) │
metrics :9091 ─┤ ├─ supervises ─▶ monerod ── P2P :18080, restricted RPC :18089 ├─▶ Monero network
│ │ ▲ unrestricted RPC 127.0.0.1:18081 │
│ └─ wallet pool ─▶ monero-wallet-rpc (one per open wallet) │
│ 127.0.0.1:18100+ ──────┘ │
└─────────────────────────── /data ───────────────────────────────┘
tini is PID 1 and reaps children. The Go service is a servicepack application with one service, monero-server, which owns startup and shutdown order.
Packages
| Package | Role |
|---|---|
internal/pkg/services/monero-server | Wires everything and runs the lifecycle. |
internal/pkg/config | DOCKER_MONERO_* parsing and validation. |
internal/pkg/node | monerod supervisor: builds its command line, restarts it with backoff when it crashes, reports when its RPC first answers, stops it with SIGTERM and a deadline. |
internal/pkg/walletpool | One monero-wallet-rpc process per open wallet: port allocation, start and readiness, create/open/restore, save and stop on close, and dropping a process that dies on its own. |
internal/pkg/process | Starts children through psyb0t/commander and forwards their output into the log. Tests swap in a fake launcher. |
internal/pkg/monero/{jsonrpc,daemonrpc,walletrpc} | Typed RPC clients for monerod and monero-wallet-rpc. |
internal/pkg/core/{node,wallets} | The business rules both transports share: validation, sync gating, write switches, and conversion to the API types. |
internal/pkg/http | Generated OpenAPI server (api/) and the handlers and aichteeteapee router (server/). |
internal/pkg/mcp | MCP tools over the same core services. |
internal/pkg/apierrors | Maps errors to a status and a stable code for both transports. |
internal/pkg/metrics | The Prometheus registry. |
Startup
- Parse and validate configuration. A bad value stops here.
- Start monerod. The API starts listening right away;
/readyreports 503 until monerod’s RPC answers, and node and wallet calls answer 503 until then. - Wallets open on request. Nothing is opened automatically at boot.
Shutdown
On SIGTERM, in order:
/readystarts failing and the API listener drains.- Every open wallet is saved and its process stopped.
- monerod gets SIGTERM and up to
DOCKER_MONERO_MONEROD_STOP_TIMEOUTto flush its database. - The metrics listener stops.
If monerod crashes
The supervisor restarts it after 2 seconds, doubling the wait up to a minute for repeated crashes, and resets the backoff after ten minutes of stable running. restarts in GET /v1/node/info and the monero_node_restarts metric count these. If monerod cannot be started at all, the service exits.
If a wallet process dies
The pool drops it and the wallet reads as closed. Open it again.