GPU-accelerated Bittensor mining on RunPod Docker containers. Optional Shariah-compliant subnet screening (enabled by default). Standalone β no VPS dependency.
graph TB
subgraph RunPod["RunPod Pod (GPU Docker Container)"]
direction TB
START["start.sh<br/>Entrypoint"]
MGR["bt_subnet_manager.py<br/>Interactive Dashboard"]
ANA["subnet_analyzer.py<br/>Profitability + Shariah"]
MON["miner_monitor.py<br/>Performance Snapshots"]
PM2["pm2<br/>Process Manager"]
MINERS["Bittensor Miners<br/>miner-sn4, miner-sn18..."]
end
subgraph Storage["/workspace/ (Network Volume)"]
CONF["mining.conf"]
WAL["wallets/<br/>coldkey + hotkeys"]
DATA["data/<br/>snapshots + reports"]
LOGS["logs/"]
CODE["miners/<br/>sn4/, sn18/..."]
end
subgraph Chain["Bittensor Network (finney)"]
SUB["Subtensor<br/>Chain Data"]
VAL["Validators"]
end
START -->|boot| PM2
START -->|creates| WAL
MGR -->|fetches live data| ANA
MGR -->|collects snapshots| MON
MGR -->|deploys/stops| PM2
ANA -->|queries| SUB
MON -->|queries| SUB
PM2 -->|manages| MINERS
MINERS <-->|axon ports| VAL
MGR -->|reads/writes| DATA
MON -->|reads/writes| DATA
MGR -->|reads| CONF
MGR -->|creates keys| WAL
flowchart LR
A["Deploy Pod"] --> B["SSH In"]
B --> C["Launch Dashboard"]
C --> D{"Choose Action"}
D -->|P| E["Prepare Hotkeys<br/>(free)"]
D -->|D or type number| F["Deploy Subnet<br/>(burns TAO)"]
D -->|W| G["Start 24/7 Watch"]
D -->|O| H["Optimize<br/>(replace worst)"]
E --> C
F --> C
G --> I["Background Monitoring<br/>every 30 min"]
H --> C
I -.->|alerts| C
docker build --platform linux/amd64 -t bt-miner-gpu:latest .
docker tag bt-miner-gpu:latest ghcr.io/helhindi/bt-miner-gpu:latest
docker push ghcr.io/helhindi/bt-miner-gpu:latest| Setting | Value |
|---|---|
| Docker Image | ghcr.io/helhindi/bt-miner-gpu:latest |
| Container Disk | 40 GB |
| Volume Mount | /workspace |
| HTTP Ports | 8888 |
| TCP Ports | 22 70000 70001 70002 70003 70004 |
TCP ports >=70000 are RunPod's "symmetrical" ports β identity-mapped so
Bittensor validators can reach your miner's axon externally. These high
ports are configured in the RunPod template (not via Docker EXPOSE,
which only supports ports β€65535).
Attach a Network Volume (10 GB+). The analyzer auto-selects the cheapest GPU meeting each subnet's VRAM requirement:
| GPU | VRAM | $/hr | $/day | $/month | Subnets |
|---|---|---|---|---|---|
| RTX 3090 | 24 GB | $0.22 | $5.28 | $158 | SN1, SN4, SN6, SN18, SN24, SN25, SN27, SN33, SN47 |
| RTX 4090 | 24 GB | $0.34 | $8.16 | $245 | (alt for 24GB subnets) |
| A40 | 48 GB | $0.39 | $9.36 | $281 | SN12, SN17, SN28 |
| A100 80GB | 80 GB | $1.19 | $28.56 | $857 | SN3, SN9, SN37 |
| H100 80GB | 80 GB | $2.49 | $59.76 | $1,793 | SN56 |
Storage: Network Volume at $0.07/GB/month (included in cost analysis).
ssh root@ssh.runpod.io -i ~/.ssh/id_ed25519
# Launch the interactive dashboard (recommended)
python3 /opt/openclaw/bt_subnet_manager.py
# The dashboard shows:
# - Top 5 GPU + CPU subnets with live profitability data
# - Running miner performance (TAO/day, TAO/hour, rank, incentive)
# - Optimization suggestions (replace underperformers)
# - One-keypress deploy, optimize, or start 24/7 watch mode# Run from repo root β only requires Docker, nothing else installed locally
./scripts/setup-local-wallet.sh
# Creates wallet "pool" at ~/.bittensor/wallets, saves mnemonic securely,
# and writes the SS58 address to mining.conf as BT_LOCAL_WALLET.
# All miner earnings consolidate here via dashboard [K] β [A]./opt/openclaw/scripts/backup-wallets.sh
# Then download: scp <pod>:/workspace/wallet-backup-*.tar.gz ~/| Action | Command |
|---|---|
| Dashboard | python3 /opt/openclaw/bt_subnet_manager.py |
| 24/7 watch | python3 /opt/openclaw/bt_subnet_manager.py --watch |
| Miner status | pm2 list |
| Logs | pm2 logs miner-sn<N> |
| Restart | pm2 restart all |
| Add subnet | /opt/openclaw/scripts/setup-subnet.sh <N> |
| Start miner | /opt/openclaw/scripts/start-miners.sh <N> |
| Analyze subnets | python3 /opt/openclaw/subnet_analyzer.py |
| Analyze (no filter) | python3 /opt/openclaw/subnet_analyzer.py --no-shariah |
| Analyze (custom TAO) | python3 /opt/openclaw/subnet_analyzer.py --tao-price 350 |
| Compare subnet | python3 /opt/openclaw/test_subnet_comparison.py 71 |
| Monitor miners | python3 /opt/openclaw/miner_monitor.py --recommend |
| Edit config | nano /workspace/mining.conf |
| Setup local wallet | ./scripts/setup-local-wallet.sh (run locally, uses Docker) |
| Backup wallets | /opt/openclaw/scripts/backup-wallets.sh |
The bt_subnet_manager.py is the primary interface. One command, one screen:
ββββββββββββββββββββββββββββββββββββββββββββββββββββββββββββββββββ
BT Subnet Manager | 2026-03-16 14:30 UTC | Wallet: min | Data: LIVE
ββββββββββββββββββββββββββββββββββββββββββββββββββββββββββββββββββ
SYS CPU: β°β°β°β°β°β°β±β±β±β±β±β± 42% (8 cores) RAM: β°β°β°β°β°β°β°β±β±β±β±β± 12.3/32 GB IO: R:120MB W:450MB
Load: 3.36 (1m) 2.80 (5m) 2.15 (15m) | 8 cores β green < 8, amber < 16
GPU 0 RTX 3090 CUDA 12.4 Driver 535.129.03 Cost: $0.22/hr ($5.28/day)
VRAM: β°β°β°β°β°β°β°β°β°β°β°β±β±β±β± 18.0/24 GB Util: β°β°β°β°β°β°β°β°β°β°β°β°β°β±β± Temp: 72Β°C Power: β°β°β°β°β°β°β°β°β±β± 280W
RUNNING MINERS (3 active | Total: 0.024510 TAO/day)
βββββββββββββββββββββββββββββββββββββββββββββββββββββ
SN4 Targon online inc:0.00312 rank: 42/180 0.009200t/d [OK]
SN18 Cortex.t online inc:0.00198 rank: 88/200 0.008100t/d [OK]
SN25 Protein online inc:0.00001 rank:190/195 0.007210t/d [REPLACE]
TOP 5 GPU SUBNETS (RunPod)
βββββββββββββββββββββββββββββββββββββββββββββββββββββ
1) SN4 Targon GPU 8.2100t 0.009200t/d ROI: 12d [LIVE]
2) SN18 Cortex.t GPU 6.5000t 0.008100t/d ROI: 15d [LIVE]
...
[D] Deploy [P] Prepare hotkeys [O] Optimize [G] GPU test [K] Wallet [W] Watch [R] Refresh [Q] Quit
or type SN number to quick-deploy
ββββββββββββββββββββββββββββββββββββββββββββββββββββββββββββββββββ
Menu options:
- [D] Deploy β Select subnets by number, auto-creates wallet/hotkey/registers/starts
- [P] Prepare β Batch-create hotkeys for top subnets (free, no TAO burn, ready to deploy instantly)
- [O] Optimize β Review underperformers, swap with better subnets (with cost warnings)
-
[G] GPU test β Full system + GPU diagnostics: CPU, RAM, load averages, VRAM, temperature, power, RunPod cost (
$/hr, $ /day, $/month), CUDA test - [I] Infrastructure β RunPod pod management: launch, start, stop, terminate pods with cost visibility
- [K] Wallet β Wallet operations: balance report, TAO transfers, consolidation, backup, create keys, permissions
- [W] Watch β Start 24/7 background monitoring via pm2
- [R] Refresh β Re-fetch live chain data
-
[J] JSON β Export full report to
/workspace/data/ -
Type a number β Quick-deploy any subnet (e.g., type
4to deploy SN4 immediately)
Hotkey indicators on subnet rows: * = running, K = hotkey ready (can deploy instantly).
Registration burns TAO and newly registered miners need ~3 days to warm up. The manager always shows:
- Registration burn cost per subnet
- ROI including warmup penalty
- Requires typing
yesto confirm any registration - Only suggests replacements after 24h+ of sustained underperformance
flowchart TD
SELECT["User selects subnet<br/>(e.g. SN4)"] --> CK{"Coldkey<br/>exists?"}
CK -->|No| CK_CREATE["btcli wallet create<br/>Mnemonic β wallet_creation.log"]
CK -->|Yes| HK
CK_CREATE --> HK{"Hotkey<br/>hotkey-sn4<br/>exists?"}
HK -->|No| HK_CREATE["btcli wallet new_hotkey<br/>Secret β wallet_creation.log"]
HK -->|Yes| CLONE
HK_CREATE --> CLONE{"Miner code<br/>exists?"}
CLONE -->|No| SETUP["setup-subnet.sh 4<br/>Clone repo + pip install"]
CLONE -->|Yes| REG
SETUP --> REG["btcli subnet register<br/>β Burns TAO"]
REG --> START["start-miners.sh 4<br/>pm2 start miner-sn4"]
START --> PERM["chmod 0700 wallet dirs"]
PERM --> LIVE["Miner live<br/>~3 day warmup"]
All config is centralized through config.py. Priority: environment variable > mining.conf > built-in default.
To add any config key, just add it to mining.conf or set it as an env var β no code changes needed:
# In /workspace/mining.conf:
BT_COLDKEY="min"
BT_NETWORK="finney"
SHARIAH_FILTER="true"
TAO_PRICE_USD="400"
RUNPOD_API_KEY="your-key-here"
MY_CUSTOM_KEY="any-value" # Available as CFG["MY_CUSTOM_KEY"]# Or as environment variables (override mining.conf):
export RUNPOD_API_KEY="your-key-here"
export TAO_PRICE_USD="350"| Key | Default | Purpose |
|---|---|---|
BT_COLDKEY |
min |
Wallet coldkey name |
BT_NETWORK |
finney |
Bittensor network |
SHARIAH_FILTER |
true |
Enable/disable Shariah screening |
TAO_PRICE_USD |
(live fetch) | Override TAO/USD price |
RUNPOD_API_KEY |
(none) | RunPod API key for pod management |
BT_LOCAL_WALLET |
(none) | Destination SS58 address for TAO transfers/consolidation |
BT_DATA_DIR |
/workspace/data |
Data directory |
BT_WALLET_PATH |
/workspace/wallets |
Wallet storage path |
Everything under /workspace/ lives on the Network Volume:
/workspace/
βββ mining.conf # Configuration (never committed)
βββ wallets/ # Coldkey + hotkeys (symlinked to ~/.bittensor/wallets)
βββ miners/ # Cloned subnet repos (sn4/, sn18/, ...)
βββ data/ # Monitor snapshots + manager reports
βββ logs/ # pm2 logs + watch daemon logs
- Coldkey name: configurable via
BT_COLDKEY(default:min) - Hotkey naming:
hotkey-sn{netuid}(e.g.,hotkey-sn4,hotkey-sn18) - Wallet path:
/workspace/wallets/(Network Volume) - Symlink:
~/.bittensor/wallets->/workspace/wallets/ - Permissions: 0700 (owner-only) on all wallet directories
Access via dashboard [K]:
- [B] Balance report β On-chain balance query for all wallets: free TAO, staked TAO, active/idle status. Uses bittensor SDK (fast) with btcli fallback. Non-zero filter option
- [T] Transfer TAO β Transfer from any hotkey to a destination SS58 address. Fee < 0.0003 TAO. Requires
yesconfirmation - [A] Consolidate all β Transfer all non-zero hotkey balances to a single destination. Shows dry-run plan first, then executes after confirmation. Leaves 0.001 TAO dust per hotkey
- [K] Backup β Creates tar.gz archive of all wallets with scp download instructions
- [C] Create coldkey β Idempotent (checks
coldkeypub.txtbefore creating) - [H] Create hotkeys β Batch create for multiple subnets at once
- [S] Secure permissions β Sets 0700 on all wallet directories
- Auto-created on deploy β
[D]Deploy automatically handles wallet setup
Set BT_LOCAL_WALLET in mining.conf to your local/cold wallet SS58 address for one-click consolidation.
Mnemonics and private key output are never displayed on the console. All wallet creation output is written to /workspace/data/wallet_creation.log with 0600 permissions (owner read/write only). Back up this file securely and delete after recording your recovery phrases.
Shariah screening is enabled by default but fully configurable for a wider audience:
# Default: Shariah filter ON β non-compliant excluded, cost comparison shown
python3 /opt/openclaw/subnet_analyzer.py
# Disable filter β all subnets included (flagged but not excluded)
python3 /opt/openclaw/subnet_analyzer.py --no-shariah
# Or set in mining.conf:
SHARIAH_FILTER="false"When the filter is active, subnet_analyzer.py screens all subnets and shows the top 3 excluded subnets for comparison so you can see the opportunity cost:
- SN8 (Taoshi) β leveraged prop trading (maisir + gharar + riba)
- SN11, SN19, SN23 β pending scholarly review (unfiltered content)
28 of 32 cataloged subnets pass screening.
The analyzer shows RunPod running costs and NET daily profit per miner. TAO/USD price is fetched live from CoinGecko on every run (stdlib urllib, no extra deps):
# Full analysis β TAO price auto-fetched from CoinGecko
python3 /opt/openclaw/subnet_analyzer.py --gpu-only
# Override TAO price manually
python3 /opt/openclaw/subnet_analyzer.py --tao-price 350
# Or pin via env var in mining.conf (skips live fetch):
TAO_PRICE_USD="350"Price resolution order: --tao-price CLI flag > TAO_PRICE_USD env var > CoinGecko live API > $400 fallback.
For each GPU subnet the analyzer shows:
- Best GPU β cheapest RunPod GPU meeting the subnet's VRAM requirement
- GPU$/d β daily GPU rental cost
- Stor$/d β daily Network Volume storage cost
- Cost$/d β total daily RunPod cost (GPU + storage)
- NET$/d β daily profit after subtracting RunPod costs (green = profit, red = loss)
Compare any subnet against the top 5 most profitable with full cost analysis:
# Build test container (no GPU needed)
docker build -f Dockerfile.test -t openclaw-test .
# Compare SN71 against top 5 (live chain data)
docker run --rm openclaw-test test_subnet_comparison.py 71
# Disable Shariah filter
docker run --rm openclaw-test test_subnet_comparison.py 71 --no-shariah
# Custom TAO price
docker run --rm -e TAO_PRICE_USD=350 openclaw-test test_subnet_comparison.py 4
# List all live subnets with Shariah status
docker run --rm openclaw-test test_subnet_comparison.py --list
# Create a local pool wallet (no local btcli needed)
./scripts/setup-local-wallet.shThe dashboard [I] Infrastructure menu manages RunPod GPU pods directly via the REST API (stdlib urllib, no extra deps).
# Set API key (get from https://www.runpod.io/console/user/settings)
export RUNPOD_API_KEY="your-api-key"
# Or add to mining.conf:
RUNPOD_API_KEY="your-api-key"| Action | Description |
|---|---|
| List pods | Shows all pods with status, GPU, cost/hr, cost/day |
| Launch pod | Select GPU from pricing table, name pod, attach network volume |
| Start pod | Resume a stopped pod |
| Stop pod | Pause a running pod (preserves state) |
| Terminate pod | Permanently delete a pod (requires "yes terminate" confirmation) |
Total running cost across all pods is shown at the top of the infrastructure view.
The same Python code runs on both VPS (systemd) and RunPod (pm2). Runtime is auto-detected:
| Setting | VPS (systemd) | RunPod (pm2) |
|---|---|---|
| Process mgmt | systemctl start/stop |
pm2 start/delete |
| Base dir | /opt/bittensor |
/workspace |
| Wallet path | /opt/bittensor/wallets |
/workspace/wallets |
| Config | /opt/bittensor/mining.conf |
/workspace/mining.conf |
| GPU monitoring | Graceful skip (no nvidia-smi) | Full GPU stats |
| Watch daemon | systemd timer | pm2 cron |
All paths overridable via env vars: BT_DATA_DIR, BT_WALLET_PATH, BT_MINERS_DIR, BT_LOG_DIR, BT_CONFIG, BT_RUNTIME.
# Pull shared files from openclaw-ansible:
./copy-from-vps-repo.sh /path/to/openclaw-ansibledevβ Default branch. All work merges here via PRs.feature/*β New features branch offdev.bugfix/*β Bug fixes branch offdev.- PRs are the only method to commit changes.
TBD