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.
This commit is contained in:
+2
-2
@@ -73,7 +73,7 @@ FROM debian:bookworm-slim AS runtime
|
|||||||
ARG ARCH
|
ARG ARCH
|
||||||
ARG YQ_VERSION=v4.44.3
|
ARG YQ_VERSION=v4.44.3
|
||||||
RUN apt-get update && apt-get install -y --no-install-recommends \
|
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/*
|
&& rm -rf /var/lib/apt/lists/*
|
||||||
|
|
||||||
# yq for reading StartOS config.yaml in the entrypoint
|
# 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 \
|
RUN chmod +x /usr/local/bin/docker_entrypoint.sh \
|
||||||
&& mkdir -p /run/ckpool /var/log/ckpool /var/lib/kamado
|
&& mkdir -p /run/ckpool /var/log/ckpool /var/lib/kamado
|
||||||
|
|
||||||
EXPOSE 3333 8080
|
EXPOSE 3333 3334 8080
|
||||||
WORKDIR /root
|
WORKDIR /root
|
||||||
ENTRYPOINT ["/usr/bin/tini", "--", "/usr/local/bin/docker_entrypoint.sh"]
|
ENTRYPOINT ["/usr/bin/tini", "--", "/usr/local/bin/docker_entrypoint.sh"]
|
||||||
|
|||||||
+46
-5
@@ -43,6 +43,8 @@ export MAXDIFF=$(q '.maxdiff // 0')
|
|||||||
export DROPIDLE=$(q '.dropidle // 0')
|
export DROPIDLE=$(q '.dropidle // 0')
|
||||||
LOG_LEVEL=$(q '.log-level // "info"')
|
LOG_LEVEL=$(q '.log-level // "info"')
|
||||||
ZMQ_ENABLED=$(q '.zmq-enabled // true')
|
ZMQ_ENABLED=$(q '.zmq-enabled // true')
|
||||||
|
TLS_ENABLED=$(q '.tls.enabled // "disabled"')
|
||||||
|
TLS_PORT=$(q '.tls.port // 3334')
|
||||||
|
|
||||||
export LOGDIR=/var/log/ckpool
|
export LOGDIR=/var/log/ckpool
|
||||||
export SOCKET_DIR=/run/ckpool
|
export SOCKET_DIR=/run/ckpool
|
||||||
@@ -99,17 +101,56 @@ echo "kamado-entrypoint: starting kamado-api"
|
|||||||
/usr/local/bin/kamado-api &
|
/usr/local/bin/kamado-api &
|
||||||
API_PID=$!
|
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}" <<EOF
|
||||||
|
foreground = yes
|
||||||
|
pid =
|
||||||
|
output = /dev/stdout
|
||||||
|
debug = 4
|
||||||
|
|
||||||
|
[stratum]
|
||||||
|
accept = 0.0.0.0:${TLS_PORT}
|
||||||
|
connect = 127.0.0.1:${STRATUM_PORT}
|
||||||
|
cert = ${CERT}
|
||||||
|
EOF
|
||||||
|
|
||||||
|
echo "kamado-entrypoint: starting stunnel on :${TLS_PORT} -> :${STRATUM_PORT}"
|
||||||
|
/usr/bin/stunnel4 "${STUNNEL_CONF}" &
|
||||||
|
STUNNEL_PID=$!
|
||||||
|
fi
|
||||||
|
|
||||||
term() {
|
term() {
|
||||||
echo "kamado-entrypoint: SIGTERM — shutting down"
|
echo "kamado-entrypoint: SIGTERM — shutting down"
|
||||||
kill -TERM "${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}" 2>/dev/null || true
|
wait "${API_PID}" "${CKPOOL_PID}" ${STUNNEL_PID:-} 2>/dev/null || true
|
||||||
exit 0
|
exit 0
|
||||||
}
|
}
|
||||||
trap term TERM INT
|
trap term TERM INT
|
||||||
|
|
||||||
wait -n "${CKPOOL_PID}" "${API_PID}"
|
# shellcheck disable=SC2086
|
||||||
|
wait -n ${CKPOOL_PID} ${API_PID} ${STUNNEL_PID:-}
|
||||||
EXIT_CODE=$?
|
EXIT_CODE=$?
|
||||||
echo "kamado-entrypoint: one of ckpool/kamado-api exited (${EXIT_CODE}), stopping the other"
|
echo "kamado-entrypoint: a supervised process exited (${EXIT_CODE}), stopping the rest"
|
||||||
kill -TERM "${API_PID}" "${CKPOOL_PID}" 2>/dev/null || true
|
kill -TERM "${API_PID}" "${CKPOOL_PID}" ${STUNNEL_PID:-} 2>/dev/null || true
|
||||||
wait || true
|
wait || true
|
||||||
exit "${EXIT_CODE}"
|
exit "${EXIT_CODE}"
|
||||||
|
|||||||
+5
-1
@@ -11,7 +11,11 @@ Kamado is a solo Bitcoin mining pool built on a patched fork of CKPool-solo, wit
|
|||||||
|
|
||||||
## Connecting miners
|
## 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.
|
- **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 <startos-lan-ip>:3333` on any always-on LAN host and point miners at that host.
|
- **simpleproxy on a second host**: Run `simpleproxy -L 3333 -R <startos-lan-ip>:3333` on any always-on LAN host and point miners at that host.
|
||||||
|
|||||||
@@ -85,12 +85,43 @@ export const getConfig: T.ExpectedExports.getConfig = compat.getConfig({
|
|||||||
"type": "number",
|
"type": "number",
|
||||||
"name": "Stratum Port",
|
"name": "Stratum Port",
|
||||||
"description":
|
"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,
|
"nullable": false,
|
||||||
"default": 3333,
|
"default": 3333,
|
||||||
"range": "[1,65535]",
|
"range": "[1,65535]",
|
||||||
"integral": true,
|
"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": {
|
"startdiff": {
|
||||||
"type": "number",
|
"type": "number",
|
||||||
"name": "Starting Difficulty",
|
"name": "Starting Difficulty",
|
||||||
|
|||||||
Reference in New Issue
Block a user