A lightweight Stratum proxy that lets multiple miners share a single P2Pool node. Miners connect with a worker name, the proxy aggregates their work under one operator wallet, and p2pool-splitter distributes payouts proportionally based on live hashrate.
Miner 1 ──┐
Miner 2 ──┤──► p2pool-pool :3333 ──► P2Pool node :3334 ──► Monero network
Miner 3 ──┘ │
└──► hashrate.json
│
p2pool-splitter → pays each miner their share
P2Pool requires each miner to mine directly to their own wallet address. That works great when every miner runs their own P2Pool node, but it's impractical for shared setups — small farms, family mining, co-ops. p2pool-pool sits in front of P2Pool and handles the aggregation so individual miners just point at stratum+tcp://yourserver:3333 like any other pool.
Unlike a centralized pool:
- No custody — payouts go directly from the Monero network to the operator wallet via P2Pool, then to miners via p2pool-splitter. p2pool-pool never touches funds.
- Private — all transactions are standard Monero with full RingCT privacy. Miner addresses are never on-chain in plaintext.
- Self-hosted — one Python file, no external dependencies beyond PyYAML.
- Python 3.10+
- PyYAML (
pip install pyyaml) - A running P2Pool node (configured to listen on a Stratum port)
- A running monero-wallet-rpc connected to the operator wallet (for p2pool-splitter)
# 1. Start P2Pool on a non-standard Stratum port (to avoid conflict with us)
p2pool --wallet 48... --stratum 0.0.0.0:3334 ...
# 2. Configure p2pool-pool
cp config.example.yaml config.yaml
nano config.yaml # set operator_wallet and p2pool_port
# 3. Run
python server.py --config config.yaml
# 4. Point your miners at your server
# XMRig example:
# "url": "stratum+tcp://yourserver:3333",
# "user": "rig1", ← worker name, no wallet address needed
# "pass": "x"p2pool-pool writes hashrate.json every 60 seconds (configurable). Pass this to p2pool-splitter instead of a static workers list:
# p2pool-splitter config.yaml
hashrate_file: "/path/to/p2pool-pool/hashrate.json"p2pool-splitter will read the live hashrates and split payouts accordingly.
{
"updated_at": 1710000000,
"window_seconds": 600,
"workers": [
{ "name": "rig1", "hashrate": 4823.5 },
{ "name": "rig2", "hashrate": 2901.1 }
]
}| Key | Default | Description |
|---|---|---|
listen_host |
0.0.0.0 |
Interface to accept miner connections |
listen_port |
3333 |
Stratum port miners connect to |
p2pool_host |
127.0.0.1 |
P2Pool node host |
p2pool_port |
3334 |
P2Pool Stratum port |
operator_wallet |
(required) | Monero wallet address for P2Pool payouts |
hashrate_export_interval |
60 |
Seconds between hashrate.json writes |
hashrate_file |
hashrate.json |
Path to write live hashrate data |
hashrate_window |
600 |
Seconds of share history for hashrate calculation |
start_difficulty |
10000 |
Initial mining difficulty sent to miners |
MIT