Production runbook
Operational procedures, monitoring, recovery and key rotation; not a readiness certification.
This manual targets 0.1.0-beta.3. Read the source and availability policy before installing. Historical reports retain their original scope.
This runbook applies to the v0.1 Arbitrum One + native USDC profile. A green
unit-test suite is not a substitute for completing the live gate in
docs/MAINNET-GATE.md.
Trust boundaries and network policy
- Keep port
8787bound to loopback. Put an authenticated TLS reverse proxy in front only when remote merchant access is required. Do not trust forwarded client-IP headers inside PPOps; enforce a second rate limit at that proxy. - Permit outbound traffic only to the configured independent Arbitrum RPC origins, production PPOI origin, package/image registries used during a separate build phase, and the configured webhook origin. The running container does not need registry access.
- Use RPC providers under different administrative control. Two URLs at the same origin are rejected. PPOps requires both providers to agree; three providers tolerate one failed or inconsistent source.
- Mount the shareable viewing key, RAILGUN database key, merchant signer, API
token and webhook HMAC key read-only from a secret manager or mode-
0600files. The merchant signer is an identity key, not a RAILGUN spending key. - Use encrypted disks and encrypted snapshots. SQLite contains the private mapping from merchant references to payment history.
Before starting
- Pin an immutable PPOps container digest and retain its CycloneDX SBOM from CI. Review all lockfile and RAILGUN SDK changes before upgrading.
- Validate the config with
ppops config-validate, then runppops preflight. The latter verifies actual RPC chain ID, quorum and finalized-tag support plus PPOI JSON-RPC health without opening wallet secrets. Arbitrum mainnet refuses confirmation-count finality, non-native USDC, fewer than two RPC origins, and the documented test PPOI host. The Wallet SDK currently documentshttps://ppoi.fdi.networkas a public community aggregator; using it creates an external availability/trust dependency. Evaluate that dependency or operate an independent compatible node before broad production use. - Restore a backup into an isolated directory and run the restore checks.
- Verify the merchant signer through the merchant’s independent identity channel. Do not teach customers to trust the signer displayed by checkout alone.
- Keep at least 4 GiB RAM, 2 CPU cores and sufficient persistent storage for the RAILGUN LevelDB and SQLite WAL. The Compose profile enforces these process limits.
Health and alerts
GET /v1/liveproves only that HTTP is alive.GET /v1/readyreturns503until a full RAILGUN/PPOI scan succeeds and whenever the last success becomes stale. Use it for orchestration health.GET /v1/metricsrequires the bearer token and returns metadata-free Prometheus metrics.
Page an operator when any of these conditions holds:
ppops_ready == 0for 15 minutes;ppops_scan_consecutive_failures >= 2;time() - ppops_last_scan_timestamp_seconds > 900;ppops_outbox_dead_lettered > 0;ppops_outbox_pendinggrows for three scan intervals;- RPC height disagreement appears in
scan.failedlogs; - disk usage exceeds 75%, process RSS approaches the 4 GiB limit, or the container restarts.
Logs intentionally omit invoice identifiers, references, viewing material and provider URLs. Preserve that property in log shipping.
Safe shutdown
- Before planned maintenance, check
/v1/readyand wait untilscanInProgressisfalse. The RAILGUN Wallet SDK scan cannot be cancelled. - On
SIGTERM, PPOps stops accepting HTTP traffic and scheduling new scans, then drains any active scan before closing LevelDB, SQLite and the runtime lock. Do not impose a conventional 30-second kill window; the Compose profile grants 30 minutes because an initial or recovery scan can be long. - PPOps pauses the Wallet SDK listener poller and owns one explicit scan schedule. Do not add a second poller or another SDK process against the same LevelDB; the SDK’s historical refresh and deferred wallet event are different completion models, and mixing them previously caused stalls and delayed TXID work after shutdown.
- A forced kill during a scan is an abnormal recovery event. Restart with the same state, wait for a complete successful scan and verify readiness before fulfilling payments or taking a backup.
- Backup and restore commands remain offline operations and refuse an active runtime lock. Never copy live LevelDB files as a substitute for the documented backup flow.
Webhook recovery and key rotation
The repository’s pilot:webhook-receiver is loopback-only evidence tooling. Do
not deploy it as the merchant’s production fulfillment backend.
mainnet-gate-replay is likewise controlled-pilot tooling: it deliberately
resends the already delivered confirmation to prove durable receiver dedupe. Do
not use it as a routine production replay mechanism.
- Every delivery includes
ppops-event-id,ppops-timestamp,ppops-key-id, andppops-signature. Receivers must reject old timestamps and deduplicate event IDs before applying business state. - Investigate the receiver before replaying. Then call
POST /v1/outbox/{eventId}/replay; only a dead-lettered event can be reset. - To rotate the HMAC key, configure the receiver to accept both old and new key
IDs, atomically replace the secret file and
webhook.keyId, restart PPOps, verify a new delivery, then remove the old receiver key. - Rotate the API token by atomically replacing its file and restarting PPOps. Update clients before removing the old instance; v0.1 intentionally does not expose secret-rotation endpoints.
Backup and incident response
- Back up SQLite, the encrypted RAILGUN LevelDB, wallet-state file and their
corresponding secrets. A database without the
reference -> invoicemapping cannot reconstruct merchant reconciliation from chain data alone. - On suspected viewing-key exposure, stop the instance, preserve logs and snapshots, create a new receiver wallet outside PPOps, and treat the old receiver’s complete private payment history as disclosed. Funds are not directly spendable with the viewing key.
- On suspected merchant-signer or API-token exposure, rotate the affected key, publish the new expected signer through the independent merchant identity channel, and invalidate outstanding descriptors if signer trust changed.
- On RPC/PPOI disagreement, do not manually mark intents paid. PPOps fails closed; restore provider agreement and rescan.