Author: Carlos Rabelo - contato@carlosrabelo.com.br
Karoo started as a weekend experiment: a lightweight Stratum proxy so a rack of Nerdminers could share a single upstream connection. The idea quickly grew into a production-ready Stratum V1 front-end that keeps upstream pools happy while CPU, GPU, or embedded rigs hammer away behind it. What ships in this repository is exactly that proxy.
- Stratum V1 Protocol Support – full
mining.subscribe,mining.authorize, andmining.submithandling with extranonce management. - Client & Upstream Management – concurrent downstream clients with automatic upstream reconnects and exponential backoff.
- Share Routing – efficient share forwarding plus acceptance/rejection tracking.
- Variable Difficulty (VarDiff) – dynamic, per-client adjustment with configurable target rates and min/max bounds.
- Rate Limiting & Bans – per-IP caps, connection-per-minute throttles, and automatic temporary bans.
- Comprehensive Metrics – HTTP
/statusand/healthzplus counters for shares, clients, and upstream health. - HTTP API – light REST interface for health checks and runtime status.
- Upstream on demand – dials pools only when miners are online and backs off with jittered retries upon failures.
- Protocol aware fan-out – normalises request/response flows while preserving worker identity and minimizing extranonce collisions.
- Share accounting & logs – per-worker latency and cadence reports with aggregate summaries.
- Flexible transport – TCP today with a clear path toward TLS or alternative downstream protocols.
Karoo runs as an intermediary between miners and pools, exposing Stratum downstream while aggregating upstream connections and metrics.
┌─────────────┐ ┌──────────────┐ ┌─────────────┐
│ Miners │────▶│ Karoo │────▶│ Pool │
│ (Clients) │◀────│ Proxy │◀────│ (Upstream) │
└─────────────┘ └──────────────┘ └─────────────┘
│
▼
┌──────────────┐
│ HTTP API │
│ (Metrics) │
└──────────────┘
proxy– connection lifecycle, share routing, and upstream orchestration.routing– message fan-out between miners and upstream.nonce– extranonce allocation and subscription tracking.vardiff– per-client difficulty controller.ratelimit– connection throttling and ban list enforcement.connection– buffered reader/writer helpers for Stratum frames.proxysocks– SOCKS5 proxy support for upstream connections.metrics– counters and gauges exposed over HTTP.stratum– request/response encoding helpers.
- Go 1.25.4+
- Linux or macOS (Windows may work but is not part of CI)
- Clone this repository and copy a config:
cp config/config.example.json config.json. - Build the proxy:
make build(outputsbin/karoo). - Update
config.jsonwith your pool host (upstream.host), worker template (user), and optional VarDiff / rate-limit settings. - Start the proxy:
./bin/karoo -config ./config.json(ormake runwhich does the same after building). - Point your miners to
stratum+tcp://<proxy-host>:3333(or whateverproxy.listenyou configured) and use the worker names that Karoo rewrites upstream. - Hit
curl http://localhost:8080/statusandcurl http://localhost:8080/healthzto confirm miners, shares, and upstream health.
make build # compile to bin/karoo
make run # build + run using ./config.json
make install # install to ~/.local/bin or /usr/local/bingo install github.com/carlosrabelo/karoo/core/cmd/karoo@latestThe installed binary behaves exactly like the one produced by make build.
cd core
go build -o karoo ./cmd/karoo
go test ./...The default configuration listens on :3334 for Stratum clients, connects to the upstream defined in config.json, and exposes HTTP status on :8080. Copy config/config.example.json (or core/config.example.json if you are working inside the Go module) and adjust the fields below to suit your deployment.
{
"proxy": {
"listen": "0.0.0.0:3333",
"client_idle_ms": 300000,
"max_clients": 1000,
"read_buf": 4096,
"write_buf": 4096
},
"upstream": {
"host": "pool.example.com",
"port": 3333,
"user": "your_wallet_address.proxy",
"pass": "x",
"tls": false,
"insecure_skip_verify": false,
"backoff_min_ms": 1000,
"backoff_max_ms": 60000
},
"http": {
"listen": "0.0.0.0:8080",
"pprof": false
},
"vardiff": {
"enabled": true,
"target_seconds": 15,
"min_diff": 1000,
"max_diff": 65536,
"adjust_every_ms": 60000
},
"ratelimit": {
"enabled": true,
"max_connections_per_ip": 100,
"max_connections_per_minute": 60,
"ban_duration_seconds": 300,
"cleanup_interval_seconds": 60
},
"compat": {
"strict_broadcast": false
}
}Key fields:
proxy.listen– downstream Stratum endpoint.upstream.host/port/user/pass– upstream pool credentials or worker template.proxy.client_idle_ms– disconnect idle miners after the configured period.compat.strict_broadcast– whenfalse, forwards unknownmining.*methods unchanged.vardiff.enabled– enables the per-worker difficulty controller.http.listen– HTTP status listener (set empty string to disable).
Karoo supports routing upstream pool connections through a SOCKS5 proxy. This is useful for:
- Routing traffic through VPNs or Tor
- Bypassing network restrictions
- Adding an extra layer of privacy
To enable SOCKS5 proxy support, add the socks_proxy section to your upstream configuration:
{
"upstream": {
"host": "pool.example.com",
"port": 3333,
"user": "your_wallet_address.proxy",
"pass": "x",
"tls": false,
"insecure_skip_verify": false,
"backoff_min_ms": 1000,
"backoff_max_ms": 60000,
"socks_proxy": {
"enabled": true,
"type": "socks5",
"host": "127.0.0.1",
"port": 1080,
"username": "",
"password": ""
}
}
}SOCKS5 proxy configuration fields:
enabled– set totrueto route upstream connections through the proxy.type– must be"socks5"(SOCKS4 is not supported).host– SOCKS5 proxy server hostname or IP address.port– SOCKS5 proxy server port.username– optional username for SOCKS5 authentication (leave empty if not required).password– optional password for SOCKS5 authentication (leave empty if not required).
Important Notes:
- The proxy is only used for upstream pool connections. Downstream miner connections are not proxied.
- TLS connections work transparently through SOCKS5 – the proxy establishes the TCP connection, then Karoo performs the TLS handshake.
- When the proxy is disabled (
enabled: false), connections are made directly to the upstream pool. - Only SOCKS5 is supported. SOCKS4 proxies will be rejected during startup.
GET /healthz– liveness probe that returnsokwhen the process is running.GET /status– JSON payload with upstream connection flags, extranonce info, VarDiff stats, rate-limit counters, and every connected client with accepted/rejected shares. Useful for dashboards and watchdogs.
- Configure your miners to use the Karoo host/port as their Stratum pool.
- Set the worker name to anything meaningful (Karoo keeps the worker suffix and rewrites the upstream user).
- Maintain the same password you configured under
upstream.passunless your pool requires per-worker passwords. - Watch the Karoo logs: every accepted or rejected share is accounted and rolled up in the periodic report.
make dockerbuilds the container image described indeploy/docker.make systemdinstalls the unit file fromdeploy/systemd(requires sudo).deploy/k8scontains namespaced manifests for Kubernetes clusters.
- Guard against connection flooding with
max_connections_per_ip. - Keep reconnect storms in check via
max_connections_per_minute. - Temporary bans (
ban_duration_seconds) discourage repeated abuse.
- Run behind a firewall and restrict downstream access to trusted networks.
- Enable TLS when pools support it; otherwise keep proxy-to-pool traffic isolated.
- Monitor
/statusregularly for rejection spikes and client churn. - Keep binaries updated to pick up bug fixes and security hardening.
Upstream Connection Fails – ensure the pool host/port are reachable, firewall rules permit the egress port, and disable TLS if the upstream does not support it.
Clients Can't Connect – verify proxy.listen is exposed, confirm no other service is bound to the same port, and check perimeter firewalls.
High Rejection Rate – validate VarDiff parameters, confirm miners speak Stratum V1, and look for latency or packet loss between Karoo and the pool.
Rate Limiting Too Aggressive – raise max_connections_per_ip/minute, reduce ban duration, or disable the limiter for trusted networks.
go test ./...
go test -race ./...
go test -cover ./....
├── core/ # Go module (cmd/karoo + internal packages)
├── deploy/ # Docker, Kubernetes, and systemd assets
├── docs/ # Tutorials (EN/PT)
├── scripts/ # Helper scripts
├── config/ # Example configs copied into config.json
└── bin/ # Binaries produced by make build
- Fork the repository.
- Create a feature branch (
git checkout -b feature/amazing-feature). - Write tests alongside code changes.
- Run
go test ./...and ensuremake buildstill succeeds. - Commit with a descriptive message and open a pull request.
- GitHub Issues: https://github.com/carlosrabelo/karoo/issues
- Pull Requests: https://github.com/carlosrabelo/karoo/pulls
- Expand the VarDiff loop into a moving-average controller with bucketed share statistics.
- Add downstream protocol adapters (e.g., WebSockets) and upstream failover lists.
- Ship structured metrics (Prometheus/OpenTelemetry) to complement the existing logs.
- Initial release with Stratum V1 support.
- Variable difficulty controller.
- Rate limiting and HTTP metrics API.
- Comprehensive test coverage scaffold.
Karoo is released under the GNU General Public License, version 2. See LICENSE for the full text.
If Karoo is useful to you, consider supporting development:
- BTC:
bc1qw2raw7urfuu2032uyyx9k5pryan5gu6gmz6exm - DOGE:
DTAkhF6oHiK9HmcsSk3RPZp5XqR2bvCaHK - ETH:
0xdb4d2517C81bE4FE110E223376dD9B23ca3C762E - LTC:
LSQFLPM89gABNEGutwWMFA4ma24qDVwy8m - TRX:
TTznF3FeDCqLmL5gx8GingeahUyLsJJ68A