diff --git a/Dockerfile b/Dockerfile index f1088a4..4291633 100644 --- a/Dockerfile +++ b/Dockerfile @@ -73,7 +73,7 @@ FROM debian:bookworm-slim AS runtime ARG ARCH ARG YQ_VERSION=v4.44.3 RUN apt-get update && apt-get install -y --no-install-recommends \ - tini ca-certificates curl libzmq5 \ + tini ca-certificates curl libzmq5 stunnel4 openssl \ && rm -rf /var/lib/apt/lists/* # yq for reading StartOS config.yaml in the entrypoint @@ -95,6 +95,6 @@ COPY docker_entrypoint.sh /usr/local/bin/docker_entrypoint.sh RUN chmod +x /usr/local/bin/docker_entrypoint.sh \ && mkdir -p /run/ckpool /var/log/ckpool /var/lib/kamado -EXPOSE 3333 8080 +EXPOSE 3333 3334 8080 WORKDIR /root ENTRYPOINT ["/usr/bin/tini", "--", "/usr/local/bin/docker_entrypoint.sh"] diff --git a/docker_entrypoint.sh b/docker_entrypoint.sh index d0c2f11..fb7308b 100755 --- a/docker_entrypoint.sh +++ b/docker_entrypoint.sh @@ -43,6 +43,8 @@ export MAXDIFF=$(q '.maxdiff // 0') export DROPIDLE=$(q '.dropidle // 0') LOG_LEVEL=$(q '.log-level // "info"') ZMQ_ENABLED=$(q '.zmq-enabled // true') +TLS_ENABLED=$(q '.tls.enabled // "disabled"') +TLS_PORT=$(q '.tls.port // 3334') export LOGDIR=/var/log/ckpool export SOCKET_DIR=/run/ckpool @@ -99,17 +101,56 @@ echo "kamado-entrypoint: starting kamado-api" /usr/local/bin/kamado-api & API_PID=$! +# Optional TLS stratum via stunnel sidecar. +STUNNEL_PID="" +if [[ "${TLS_ENABLED}" == "enabled" ]]; then + TLS_DIR=/root/.kamado/tls + CERT="${TLS_DIR}/stratum.pem" + mkdir -p "${TLS_DIR}" + if [[ ! -f "${CERT}" ]]; then + echo "kamado-entrypoint: generating self-signed stratum TLS cert" + openssl req -x509 -newkey rsa:2048 -sha256 -nodes \ + -keyout "${TLS_DIR}/stratum.key" \ + -out "${TLS_DIR}/stratum.crt" \ + -days 3650 \ + -subj "/CN=kamado-pool-stratum" >/dev/null 2>&1 + cat "${TLS_DIR}/stratum.key" "${TLS_DIR}/stratum.crt" > "${CERT}" + chmod 600 "${TLS_DIR}/stratum.key" "${CERT}" + fi + FINGERPRINT=$(openssl x509 -in "${TLS_DIR}/stratum.crt" -noout -fingerprint -sha256 | cut -d= -f2) + echo "kamado-entrypoint: stratum TLS SHA256 fingerprint: ${FINGERPRINT}" + + STUNNEL_CONF=/etc/stunnel/stratum.conf + mkdir -p /etc/stunnel + cat > "${STUNNEL_CONF}" < :${STRATUM_PORT}" + /usr/bin/stunnel4 "${STUNNEL_CONF}" & + STUNNEL_PID=$! +fi + term() { echo "kamado-entrypoint: SIGTERM — shutting down" - kill -TERM "${API_PID}" "${CKPOOL_PID}" 2>/dev/null || true - wait "${API_PID}" "${CKPOOL_PID}" 2>/dev/null || true + kill -TERM "${API_PID}" "${CKPOOL_PID}" ${STUNNEL_PID:-} 2>/dev/null || true + wait "${API_PID}" "${CKPOOL_PID}" ${STUNNEL_PID:-} 2>/dev/null || true exit 0 } trap term TERM INT -wait -n "${CKPOOL_PID}" "${API_PID}" +# shellcheck disable=SC2086 +wait -n ${CKPOOL_PID} ${API_PID} ${STUNNEL_PID:-} EXIT_CODE=$? -echo "kamado-entrypoint: one of ckpool/kamado-api exited (${EXIT_CODE}), stopping the other" -kill -TERM "${API_PID}" "${CKPOOL_PID}" 2>/dev/null || true +echo "kamado-entrypoint: a supervised process exited (${EXIT_CODE}), stopping the rest" +kill -TERM "${API_PID}" "${CKPOOL_PID}" ${STUNNEL_PID:-} 2>/dev/null || true wait || true exit "${EXIT_CODE}" diff --git a/instructions.md b/instructions.md index 9a8d058..e848927 100644 --- a/instructions.md +++ b/instructions.md @@ -11,7 +11,11 @@ Kamado is a solo Bitcoin mining pool built on a patched fork of CKPool-solo, wit ## Connecting miners -Kamado's stratum server listens on TCP port **3333** inside the container. **StartOS 0.3.x does not forward raw TCP ports on the LAN interface**, so you have two options to reach stratum from miners on your local network: +Kamado's plaintext stratum server listens on TCP port **3333** inside the container (configurable). If you enable **Stratum TLS** in the config, an stunnel sidecar also terminates TLS on port **3334** (configurable) and forwards the decrypted traffic to the plaintext stratum locally. The TLS certificate is generated once on first start and persisted at `/root/.kamado/tls/stratum.crt` — the SHA-256 fingerprint is printed to the container logs so you can pin it on your miners. + +Because the cert is self-signed, miners must connect with certificate verification disabled (`stratum+ssl://`, plus whatever skip-verify / insecure flag your firmware exposes). + +**StartOS 0.3.x does not forward raw TCP ports on the LAN interface**, so you have two options to reach stratum — plaintext or TLS — from miners on your local network: - **Router port-forward**: Forward an external port on your router directly to your StartOS server's LAN IP on port 3333 and point miners at that. - **simpleproxy on a second host**: Run `simpleproxy -L 3333 -R :3333` on any always-on LAN host and point miners at that host. diff --git a/scripts/procedures/getConfig.ts b/scripts/procedures/getConfig.ts index bbc2c89..710a8e9 100644 --- a/scripts/procedures/getConfig.ts +++ b/scripts/procedures/getConfig.ts @@ -85,12 +85,43 @@ export const getConfig: T.ExpectedExports.getConfig = compat.getConfig({ "type": "number", "name": "Stratum Port", "description": - "TCP port the stratum server listens on inside the container. Defaults to 3333. Change this if you are running simpleproxy (or another TCP forwarder) and want Kamado to listen on a different port — useful when another service on the same host already uses 3333.", + "TCP port the plaintext stratum server listens on inside the container. Defaults to 3333. Change this if you are running simpleproxy (or another TCP forwarder) and want Kamado to listen on a different port.", "nullable": false, "default": 3333, "range": "[1,65535]", "integral": true, }, + "tls": { + "type": "union", + "name": "Stratum TLS", + "description": + "Accept stratum connections over TLS via an stunnel sidecar. A self-signed certificate is generated on first start and persisted across restarts — miners must connect with TLS verification disabled (most firmware exposes this as 'stratum+ssl://' with a skip-verify or insecure flag).", + "tag": { + "id": "enabled", + "name": "TLS Mode", + "description": "Disable or enable TLS termination in front of stratum.", + "variant-names": { + "disabled": "Disabled", + "enabled": "Enabled (stunnel sidecar)", + }, + }, + "default": "disabled", + "variants": { + "disabled": {}, + "enabled": { + "port": { + "type": "number", + "name": "TLS Stratum Port", + "description": + "TCP port stunnel listens on for TLS stratum connections. Forwards decrypted traffic to the plaintext stratum port locally.", + "nullable": false, + "default": 3334, + "range": "[1,65535]", + "integral": true, + }, + }, + }, + }, "startdiff": { "type": "number", "name": "Starting Difficulty",