Files
KamadoPool-StartOS-0351/scripts/procedures/properties.ts
T
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

115 lines
4.1 KiB
TypeScript

import { types as T, YAML } from "../deps.ts";
// StartOS does not forward raw TCP on the LAN interface, so stratum is
// reached via a router forward or a simpleproxy on another host. We
// can't know that external IP from inside the container, but we can
// publish the ports, the variant, and the TLS cert fingerprint + full
// PEM so the user has everything they need to configure their miner —
// including miners (e.g. AxeOS / Bitaxe) whose firmware verifies
// against a CA bundle and only accepts custom roots when the user
// pastes the cert in directly.
export const properties: T.ExpectedExports.properties = async (effects) => {
const cfg = (await effects
.readFile({ volumeId: "main", path: "start9/config.yaml" })
.then((s: string) => YAML.parse(s))
.catch(() => ({}))) as any;
const stratumPort = cfg?.["stratum-port"] ?? 3333;
const tlsEnabled = cfg?.tls?.enabled === "enabled";
const tlsPort = cfg?.tls?.port ?? 3334;
const variant = cfg?.bitcoind?.type ?? "bitcoind";
const network = variant === "bitcoind-testnet" ? "testnet4" : "mainnet";
let fingerprint = "";
let certPem = "";
if (tlsEnabled) {
try {
fingerprint = (
await effects.readFile({
volumeId: "main",
path: "tls/fingerprint.txt",
})
).trim();
} catch {
fingerprint = "(not yet generated — start the service once)";
}
try {
certPem = (
await effects.readFile({
volumeId: "main",
path: "tls/stratum.crt",
})
).trim();
} catch {
certPem = "(not yet generated — start the service once)";
}
}
const data: Record<string, T.PackagePropertyObject["value"] | any> = {
"Network": {
type: "string",
value: network,
description: "Bitcoin network Kamado is mining on.",
copyable: false,
qr: false,
masked: false,
},
"Stratum Port (plaintext)": {
type: "string",
value: String(stratumPort),
description:
"TCP port ckpool-solo listens on. Forward this from your router, or run simpleproxy on a LAN host, and point miners at stratum+tcp://<host>:<port>.",
copyable: true,
qr: false,
masked: false,
},
};
if (tlsEnabled) {
data["Stratum Port (TLS)"] = {
type: "string",
value: String(tlsPort),
description:
"TCP port stunnel listens on for TLS stratum. Connect miners with stratum+ssl://<host>:<port>. The cert is self-signed — miners that verify against a CA bundle (AxeOS / Bitaxe) need either the full PEM (below) pasted in as a custom root, the SHA-256 fingerprint pinned, or TLS verification disabled, depending on what the firmware exposes.",
copyable: true,
qr: false,
masked: false,
};
data["TLS Cert Fingerprint (SHA-256)"] = {
type: "string",
value: fingerprint,
description:
"SHA-256 fingerprint of the stratum TLS cert. Use this for fingerprint pinning on miner firmwares that support it. Changes only when the cert is regenerated (delete tls/stratum.* in the data volume to force a new one).",
copyable: true,
qr: false,
masked: false,
};
data["TLS Certificate (PEM)"] = {
type: "string",
value: certPem,
description:
"Full self-signed stratum certificate in PEM format. Paste this into your miner's TLS settings as a custom CA / trusted root (AxeOS exposes a 'Stratum SSL Cert' field for exactly this). Includes -----BEGIN/END CERTIFICATE----- markers; copy the whole block.",
copyable: true,
qr: false,
masked: false,
};
}
data["Worker Username"] = {
type: "string",
value: "<your-btc-address>[.<workername>]",
description:
"Configure each miner's stratum username as the Bitcoin address that should receive the block reward on a solve, optionally followed by .workername for dashboard labelling. Kamado refuses to authenticate workers whose username is not a valid address on the active network.",
copyable: false,
qr: false,
masked: false,
};
return {
result: {
version: 2,
data,
},
};
};