Commit Graph
34 Commits
Author SHA1 Message Date
satoshi 6b6e0ed102 Include ckpool volume in backup and restore
The backup only covered /root/.kamado (DB, config, TLS certs) but
missed /root/.ckpool which holds miner/worker state, pool status,
and ckpool logs. Without it a restore would lose all per-user and
per-worker statistics.
2026-05-23 13:13:32 +03:00
satoshi 6994b39dc9 Move ZMQ setting to top level and make advanced fields optional
ZMQ block notifications are important enough to be visible without
expanding Advanced. Advanced fields no longer show a required asterisk
since they all have sane defaults and the entrypoint already falls back
to them via yq.
2026-05-23 03:13:50 +03:00
satoshi 83938e4aea Rename config labels for TLS mode and block explorer fields 2026-05-19 03:09:38 +03:00
satoshi 57ec696e3f Add multiarch build setup and build documentation
- Add `make setup` target to register qemu and create a multiplatform
  buildx builder for universal (x86_64 + aarch64) packages
- Use named builder with --progress=plain to avoid flickering output
- Conditionally depend on arch-specific Docker tars so single-arch
  builds don't require the other image
- Document prerequisites, build targets, and overrides in README
2026-05-19 03:01:46 +03:00
satoshi a068afc8c1 Supervise ckpool with restart loop and bitcoind readiness check
Replaces the one-shot ckpool launch with a supervised loop that waits
for bitcoind to be reachable before each start. When the API kills
ckpool (bitcoind down), the loop waits for recovery and restarts it
automatically — dashboard stays up the whole time.
2026-05-19 01:30:44 +03:00
satoshi 75024a41c6 Enable ckpool LOG_INFO loglevel for share statistics
Sets CKPOOL_LOGLEVEL=6 so ckpool emits per-share Accepted/Rejected
client log lines needed by the stats and difficulty distribution
features.
2026-05-18 21:13:20 +03:00
satoshi cb01a16af8 Add reset-latency StartOS action
Calls POST /api/admin/reset-latency to zero the block-update latency
counters. Available while the service is running, no warning needed.
2026-05-11 02:18:48 +03:00
satoshi c925dceecc Refactor health checks to use effects.fetch and util helpers 2026-05-10 17:24:52 +03:00
satoshi c71309844b Add Pool Status action, rename from Stratum Smoke Test
Adds a comprehensive status action showing pool health, connected
miners, block history with chain tags, and debug memory-vs-DB
comparison. Removes the clear-network-orphans action (now handled
automatically by the reconcile loop). Updates manifest description
to accurately reflect capabilities.
2026-05-10 17:24:39 +03:00
satoshi 683a9a0b6b Expose granular health indicators to StartOS
Add three new named health checks to the manifest alongside the existing
web check, each implemented as a fetch+parse of /api/health:

  ckpool      — is the stratum server alive? (miners can connect)
  bitcoin     — is Bitcoin Core RPC reachable? (blocks can be submitted)
  submit-gap  — have all block submissions been confirmed by bitcoind?

The web check retains its current role: calling /api/health which returns
503 when any critical subsystem is down, so StartOS marks the overall
service as degraded. The three new checks give operators a drill-down
view of which subsystem is the problem.

Each check returns "starting" for the first 20 s after launch so normal
boot sequencing does not trigger false alarms.
2026-04-28 23:07:16 +03:00
satoshi f03f2b1bc3 Remove Block Broadcast Fallback config
Companion to KamadoPool's df5e65d. The fallback submitter has been
scrapped — primary bitcoind remains the sole submission target, with
upstream's indefinite-retry behavior preserved. Drops the
block-broadcast-fallback union from advanced config and the
BACKUP_RPC_URLS / PENDING_BLOCKS_DIR / PENDING_BLOCKS_GRACE exports
from docker_entrypoint.
2026-04-28 02:07:33 +03:00
satoshi 00c882a8d2 Lower fallback grace default from 30s to 3s
ckpool patch 0004 now bounds generator_submitblock's wait for a live
primary to ~3s rather than spinning indefinitely, and calls submit
before writing the pending-block hex to disk so the happy path adds
zero latency. The right default is small: a fallback should kick in
while the work is still relevant for the current chain tip.

Range widened to [1, 600] so impatient operators can crank further
down. Description updated to reflect the new architecture.
2026-04-27 21:53:53 +03:00
satoshi 1b67479a4d Expose Block Broadcast Fallback config + plumb env through
New advanced.block-broadcast-fallback union:
  * enabled (default: false)
  * grace-seconds (default: 30, range 10-600)
  * backup-rpcs: list of full bitcoind RPC URLs, with inline
    credentials supported (https://user:pass@host:port/). Up to 10.

docker_entrypoint reads the list with yq, joins with newlines, and
exports BACKUP_RPC_URLS plus PENDING_BLOCKS_DIR=<logdir>/pending-blocks
and PENDING_BLOCKS_GRACE so kamado-api's blocksubmit watcher activates.
If the user enables the fallback but provides no URLs, we log a
warning and disable rather than spam pending-block warnings.

The companion ckpool patch (KamadoPool repo, 0004-dump-pending-block-
for-fallback) writes raw block hex to PENDING_BLOCKS_DIR before each
submit attempt and unlinks on success. The watcher only fires if
ckpool's primary submit fails AND the operator configured backup RPCs.
2026-04-27 21:26:50 +03:00
satoshi 4be06d347c Add Block Explorer config, log TLS handshakes at notice level
Two related polish items:

1. Optional custom block explorer. New union under Advanced config
   ("Block Explorer") defaulting to "mempool.space". Picking
   "Custom URL" reveals a single text field where the user can
   point Kamado at their own mempool instance — useful for users
   running mempool as a sibling StartOS service or on the same LAN.
   The entrypoint reads .advanced.mempool-explorer.{type,url} and
   exports MEMPOOL_BASE_URL when type=custom; otherwise leaves it
   empty and the UI keeps its mempool.space defaults.

2. stunnel debug level 4 (warning) was hiding successful TLS
   handshakes — only failures showed up in the service logs, which
   made it hard to confirm "yes, my miner did connect over TLS"
   without going looking at netstat. Bump to level 5 (notice) so
   each successful handshake produces an "accepted connection from
   <ip>" / "connected from <ip>" line. Errors stay visible at level
   3, so the only thing this changes is making the happy path
   observable.
2026-04-26 23:11:07 +03:00
satoshi d9ad1036f5 Bind a second loopback-only stratum socket for TLS detection
ckpool exposes the serverurl[] index a client connected on as
client.server in its runtime JSON. By binding a second
loopback-only stratum socket and pointing stunnel at it, every TLS
miner arrives with server == 1 and the dashboard can render a
TLS pill cleanly — no source-IP heuristics.

Add TLS_INTERNAL_PORT=3437 to the entrypoint, render it into the
ckpool.conf.template's serverurl array (in the matching commit on
the KamadoPool repo), and update the stunnel config so TLS traffic
forwards to 127.0.0.1:${TLS_INTERNAL_PORT} instead of the public
plaintext port. Even when TLS is disabled the second bind is
harmless — nothing connects to it.
2026-04-26 18:41:41 +03:00
satoshi f6430d0cee Properties: expose full stratum TLS cert PEM for miners with custom-CA
AxeOS / Bitaxe firmware verifies the stratum TLS cert against
Espressif's bundled Mozilla CA store. A self-signed cert never
matches anything in that bundle, so the handshake fails with
mbedtls_ssl_handshake -0x3000 (fatal alert) and the miner shows
"Failed to verify certificate". The firmware does, however, expose
a "Stratum SSL Cert" field where a custom CA / trusted root can be
pasted — that's the supported way to use TLS with a self-signed
pool cert.

Read tls/stratum.crt from the main volume and surface the full PEM
(BEGIN/END markers included) as a copyable property. Update the
TLS port and fingerprint descriptions to point users at the new
field with a clear "paste this into your miner's TLS settings"
explanation, instead of the previous wording that implied
disabling cert verification was the only path.
2026-04-26 18:03:52 +03:00
satoshi d9f17ff181 TLS: cover mDNS / LAN / Tor hostnames via wildcard SAN entries
Miner firmware typically verifies the TLS server cert against the
hostname it was pointed at. Bitaxe (AxeOS) uses mbedtls and the
logs showed mbedtls_ssl_handshake returning -0x2700
(MBEDTLS_ERR_X509_CERT_VERIFY_FAILED) when connecting to
obese-admirer.local:3338 — our cert's SAN only had
kamado-pool.embassy / kamado-pool / localhost / 127.0.0.1, none of
which match an arbitrary mDNS host.

Add leftmost-label wildcards for the TLDs miners typically reach
the pool through:
  *.local      (mDNS / Bonjour, e.g. obese-admirer.local)
  *.embassy    (StartOS inter-service hostnames)
  *.onion      (Tor hidden services)
  *.home.arpa  (RFC 8375 home network namespace)
  *.lan        (common consumer router default)
  *.internal   (some corporate / LAN setups)

OpenSSL's own X509_check_host refuses these 2-label wildcards as a
public-suffix safeguard, but mbedtls accepts them (its wildcard
check is RFC 2818 verbatim — just requires *.X where X is any
non-empty label), so miners using mbedtls-based stacks (ESP-IDF,
most embedded firmwares) will now match.

Bump TLS_CERT_VERSION to 4 so existing installs self-regenerate.
2026-04-24 01:33:06 +03:00
satoshi f47699d7b0 Harden TLS cert generation with a version marker and openssl config
The previous fix relied on inspecting the existing cert for a
subjectAltName extension to decide whether to regenerate. That
works but is brittle — it depends on openssl text output format
and on the assumption that SAN is the only thing that could go
wrong. If a future client rejects us for some *other* missing
extension, we'd be stuck on a bad cert again.

Switch to an explicit cert version marker (TLS_CERT_VERSION). Any
time we change the cert shape, we bump the version; the startup
check regenerates whenever the marker file is absent or out of
date. Upgrades self-heal on next boot with no introspection.

Write the full extension set via an openssl config file instead of
-addext flags. -addext is subtly different across openssl versions
(in some builds the extension lands in the CSR rather than the
cert). The config-file path is the documented, portable way to pin
basicConstraints, keyUsage, extendedKeyUsage, subjectKeyIdentifier,
and subjectAltName together.

Also log the resulting extensions at startup so operators can
verify cert sanity from the service logs without exec'ing into the
container, and pin a modern TLS floor in stunnel.conf (no SSL3,
no TLSv1, no TLSv1.1).
2026-04-24 00:45:29 +03:00
satoshi 1fccebef01 Stratum TLS cert: add subjectAltName, auto-regen on upgrade
Old cert was /CN=kamado-pool-stratum with no SAN extension. Strict
TLS clients (Go, Rust, mbedtls, most modern miner firmwares) treat
missing SAN as a hard validation failure and send TLS alert 42
(bad_certificate), which is exactly what we saw in the stunnel
logs: "SSL_accept: ... error:0A000412: ... sslv3 alert bad
certificate".

Generate the cert with subjectAltName covering kamado-pool.embassy,
localhost, and 127.0.0.1, and an explicit
extendedKeyUsage=serverAuth. Swap the combined PEM so the cert
comes before the key (convention). Upgrades auto-heal: if an
existing cert lacks SAN, the entrypoint regenerates it on next
start — the fingerprint changes and the user needs to re-pin on
their miner, but the previous cert couldn't complete a handshake
anyway so there's nothing to lose.

Also make stunnel's intent explicit with verify=0 so anyone reading
the config knows we're doing opportunistic TLS, not client-cert
auth; miner auth is the stratum layer's job.
2026-04-23 02:12:44 +03:00
satoshi dc33bb7694 Wire ckpool to real ZMQ endpoint and enable blockpoll
With BITCOIN_NOTIFY=true, ckpool's generator_getbest short-circuits
to GETBEST_NOTIFY (generator.c:902) and the blockupdate loop sleeps
5s doing nothing (stratifier.c:4695). It then expects ZMQ to push
new-tip events — but our ZMQ_BLOCK was empty and ckpool defaults to
tcp://127.0.0.1:28332 (ckpool.c:1795), which has nothing listening
inside this container. Net effect: ckpool was blind to tip changes,
so miners kept hashing the stale work until the next 30s
update_interval finally pulled a new template. Observed was a
16-second gap between bitcoind's UpdateTip log line and ckpool's
subsequent CreateNewBlock call — that's pure wasted hashrate.

Fix both paths:
- BITCOIN_NOTIFY=false so the blockpoll thread actually polls
  getbestblockhash every BLOCKPOLL_MS (100ms).
- ZMQ_BLOCK=tcp://${BITCOIN_RPC_HOST}:28332 so the zmqnotify thread
  subscribes to bitcoind's real hashblock publisher. Whichever path
  sees the new tip first triggers update_base(); both are safe to
  run concurrently.
- Drop the sed line that was stripping zmqblock from the rendered
  conf — we now want it in there.
2026-04-23 01:10:31 +03:00
satoshi 04a8e2d4dc Move ckpool logs and kamado-api DB to persisted volumes
The default LOGDIR and DB_PATH both pointed at ephemeral container
paths, so a service restart wiped the pool's users/workers state,
its block history, and kamado-api's hashrate chart.

- LOGDIR: /var/log/ckpool -> /root/.ckpool/logs (ckpool volume).
  Persists pool/pool.status, users/, workers/, and daily logs.
- DB_PATH: default /var/lib/kamado/kamado.db
  -> /root/.kamado/data/kamado.db (main volume).
  Persists blocks, hashrate_samples, and the kv table that holds
  cumulative pool work.

CKPOOL_LOGFILE follows LOGDIR so kamado-api's log-tailer keeps
picking up ckpool's block-solve lines.
2026-04-22 21:07:36 +03:00
satoshi bfc9553bb9 Properties screen: expose stratum ports, TLS fingerprint, worker format
Entrypoint persists the generated TLS cert fingerprint so the
properties script can read it from the main volume. The screen
shows the active network, plaintext and TLS stratum ports, the
SHA-256 fingerprint for miner pinning, and the worker username
format (BTC address plus optional worker label).
2026-04-14 18:16:41 +03:00
satoshi c9858325cd Use genesis coinbase address for ckpool startup self-test
ckpool-solo validates conf btcaddress once at startup to prime the
coinbase-builder, then pays solves to the worker's stratum address.
The conf value never sees a satoshi, so use the active network's
genesis coinbase address instead of a burn placeholder.
2026-04-14 17:26:42 +03:00
satoshi a63e7256c4 Tidy config: drop payout-address field, group niche options under Advanced
Worker stratum username is the payout address in ckpool-solo, so the
separate field was redundant. Niche vardiff/logging/zmq knobs now
live under an Advanced group with sensible defaults.
2026-04-14 17:10:51 +03:00
satoshi cb739867cc Add optional stratum TLS via stunnel sidecar
New 'tls' union config (disabled by default) spins up an
stunnel4 process inside the container that terminates TLS on
a configurable port (3334 by default) and forwards decrypted
stratum traffic to 127.0.0.1:${STRATUM_PORT}.

Cert is self-signed, generated once on first start with a
10-year validity and persisted at /root/.kamado/tls/ so the
fingerprint stays stable across restarts. SHA-256 fingerprint
is printed to container logs on each startup so users can
pin it on their miners. Miners must connect with
verification disabled (no CA trust chain for a private pool).

Runtime image grows by ~3MB for stunnel4 + openssl. The
supervisor loop now waits on three PIDs and tears all of them
down together if any one exits.
2026-04-14 11:21:45 +03:00
satoshi 74387b8c45 Expose ZMQ block notifications toggle in config
New 'zmq-enabled' boolean (default true) makes the entrypoint
export BITCOIN_ZMQ_BLOCK=tcp://<bitcoind-host>:28332, which
kamado-api's zmqmon subscribes to for sub-second chain refresh
on the dashboard. Disable it if your bitcoind doesn't have
zmqpubhashblock exposed.
2026-04-14 11:16:04 +03:00
satoshi 31abbbd4a1 Use 3-arg compat.setConfig form in setConfig
The 1-arg form tried to call effects.createDir which doesn't
exist in the 0.3.5.1 effects API, crashing config save with
'TypeError: effects.createDir is not a function'. The 3-arg
form (effects, newConfig, deps) just wires up dependencies
based on the chosen bitcoind variant without touching the
filesystem.
2026-04-14 10:28:37 +03:00
satoshi 8c9bfb33af Drop unused compat assets volume
start-sdk pack was failing on 'Copying Assets: No such file'
because the compat volume was declared with type: assets but
had no assets/compat/ directory to populate it.
2026-04-14 10:18:56 +03:00
satoshi 9a64dae04b Use start-sdk's docker-images/<arch>.tar convention
start-sdk pack discovers per-arch tarballs at docker-images/
x86_64.tar and docker-images/aarch64.tar by filename convention,
not via a manifest assets entry. Dropping the invalid
'docker-images: image.tar' assets key and reworking the Makefile
to build one type=docker tarball per arch with arm/x86 single-
arch convenience targets.
2026-04-14 10:14:07 +03:00
satoshi 2812d6dac3 Make PLATFORMS overridable for single-arch test builds
Default still builds linux/arm64/v8+linux/amd64 for shipping,
but 'make PLATFORMS=linux/amd64' skips the arm64 leg on hosts
without qemu-user-static registered.
2026-04-14 10:03:33 +03:00
satoshi 070260002b Build from local KamadoPool checkout via buildx build-context
Replaces the git-clone-at-SHA source stage with a 'FROM scratch
AS source' stage that COPYs from a named build context. The
Makefile passes '--build-context kamado=../KamadoPool' by
default; override with 'make KAMADO_SRC=/elsewhere'. No more
SHA placeholder, no GitHub dependency, no re-clone on every
build — and the image always reflects the working tree.
2026-04-14 09:56:26 +03:00
satoshi 90e745f160 Align Dockerfile and entrypoint with upstream KamadoPool build
Previous scaffold referenced a non-existent 'make ckpool-src'
target. Rewritten to inline the real build steps from the
upstream KamadoPool repo: clone ckpool at CKPOOL_COMMIT, apply
patches/*.patch, build with the same portable CFLAGS the
ckpool Dockerfile uses. The ui and api stages now match
api/Dockerfile exactly.

Entrypoint now uses the same env-var interface as the upstream
ckpool entrypoint (POOL_BTCADDRESS, BITCOIN_RPC_*, STRATUM_PORT,
etc.) and renders ckpool.conf from the bundled template via
sed. kamado-api env vars corrected to match config.FromEnv
(BITCOIN_RPC_URL, CKPOOL_SOCKDIR, CKPOOL_LOGFILE, LISTEN_ADDR).
2026-04-13 18:10:17 +03:00
satoshi 54935bf638 Add configurable stratum port (default 3333)
Exposes stratum-port in the StartOS config UI so users running
simpleproxy or another TCP forwarder can point Kamado at a
non-default port. Entrypoint substitutes the value into
ckpool.conf serverurl.

Also pins placeholder KAMADO_SHA in the Dockerfile — swap to a
real pushed commit before the first build.
2026-04-13 03:54:49 +03:00
satoshi 4064f9e56a Initial StartOS 0.3.5.1 packaging scaffold for Kamado Pool
Multi-stage Dockerfile clones KamadoPool at a pinned SHA, builds
ckpool and kamado-api (with embedded Svelte UI), runtime image
supervises both processes via tini + wait -n. Config covers
bitcoind mainnet/testnet4 variant, payout address, coinbase tag,
vardiff knobs, and log level. Web UI interface only — stratum
:3333 requires a router port-forward or simpleproxy workaround
because StartOS 0.3.x does not forward raw TCP on LAN.

TODO before first build: pin KAMADO_REPO + KAMADO_SHA in the
Dockerfile to a pushed commit.
2026-04-13 03:51:23 +03:00