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).
This commit is contained in:
satoshi
2026-04-14 18:16:41 +03:00
parent c9858325cd
commit bfc9553bb9
2 changed files with 84 additions and 14 deletions
+1
View File
@@ -134,6 +134,7 @@ if [[ "${TLS_ENABLED}" == "enabled" ]]; then
chmod 600 "${TLS_DIR}/stratum.key" "${CERT}" chmod 600 "${TLS_DIR}/stratum.key" "${CERT}"
fi fi
FINGERPRINT=$(openssl x509 -in "${TLS_DIR}/stratum.crt" -noout -fingerprint -sha256 | cut -d= -f2) FINGERPRINT=$(openssl x509 -in "${TLS_DIR}/stratum.crt" -noout -fingerprint -sha256 | cut -d= -f2)
printf '%s\n' "${FINGERPRINT}" > "${TLS_DIR}/fingerprint.txt"
echo "kamado-entrypoint: stratum TLS SHA256 fingerprint: ${FINGERPRINT}" echo "kamado-entrypoint: stratum TLS SHA256 fingerprint: ${FINGERPRINT}"
STUNNEL_CONF=/etc/stunnel/stratum.conf STUNNEL_CONF=/etc/stunnel/stratum.conf
+80 -11
View File
@@ -1,22 +1,91 @@
import { types as T, YAML } from "../deps.ts"; import { types as T, YAML } from "../deps.ts";
const noProps: T.ExpectedExports.properties = async () => { // StartOS does not forward raw TCP on the LAN interface, so stratum is
return { // reached via a router forward or a simpleproxy on another host. We
result: { // can't know that external IP from inside the container, but we can
version: 2, // publish the ports, the variant, and the TLS cert fingerprint so the
data: { // user has everything they need to configure their miner.
"Dashboard": { 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 = "";
if (tlsEnabled) {
try {
fingerprint = (
await effects.readFile({
volumeId: "main",
path: "tls/fingerprint.txt",
})
).trim();
} catch {
fingerprint = "(not yet generated — start the service once)";
}
}
const data: Record<string, T.PackagePropertyObject["value"] | any> = {
"Network": {
type: "string", type: "string",
value: value: network,
"Open the Kamado web UI from the Services page for live stats.", description: "Bitcoin network Kamado is mining on.",
description: "Kamado exposes everything through the web dashboard.",
copyable: false, copyable: false,
qr: false, qr: false,
masked: 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. Miners must disable cert verification (self-signed cert) and connect with stratum+ssl://<host>:<port>.",
copyable: true,
qr: false,
masked: false,
};
data["TLS Cert Fingerprint (SHA-256)"] = {
type: "string",
value: fingerprint,
description:
"Pin this fingerprint on your miner if its firmware supports it. The certificate is self-signed and regenerated only if you delete tls/stratum.* in the data volume.",
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,
}, },
}; };
}; };
export const properties = noProps;