Dont duplicate interfaces on port change 3.0
This commit is contained in:
@@ -13,7 +13,7 @@ This is the 0.4.0 port of the [0.3.5.1 wrapper](../KamadoPool-StartOS-0351), reb
|
|||||||
| Config form (`getConfig`/`setConfig`) writing `start9/config.yaml` | `store.json` file model + **Configure** action with input spec; settings changes restart daemons reactively |
|
| Config form (`getConfig`/`setConfig`) writing `start9/config.yaml` | `store.json` file model + **Configure** action with input spec; settings changes restart daemons reactively |
|
||||||
| RPC credentials via config **pointers** to `bitcoind`/`bitcoind-testnet` | bitcoind **cookie** auth read from a read-only dependency mount; RPC/ZMQ reached over the LXC bridge address resolved reactively (no `.embassy` DNS) |
|
| RPC credentials via config **pointers** to `bitcoind`/`bitcoind-testnet` | bitcoind **cookie** auth read from a read-only dependency mount; RPC/ZMQ reached over the LXC bridge address resolved reactively (no `.embassy` DNS) |
|
||||||
| Two dependency variants (`bitcoind`, `bitcoind-testnet`) | Single `bitcoind` dependency; the active chain is detected at runtime from `getblockchaininfo` (the coinbase self-test address is chosen accordingly) |
|
| Two dependency variants (`bitcoind`, `bitcoind-testnet`) | Single `bitcoind` dependency; the active chain is detected at runtime from `getblockchaininfo` (the coinbase self-test address is chosen accordingly) |
|
||||||
| No LAN TCP forwarding — users needed router forwards / simpleproxy for stratum | Stratum (and TLS stratum) exposed as **raw TCP host bindings**, directly reachable on the LAN. The configured port drives both the in-container bind and the interface's `preferredExternalPort`, so the user's chosen number is what miners connect to when the OS can grant it |
|
| No LAN TCP forwarding — users needed router forwards / simpleproxy for stratum | Stratum (and TLS stratum) exposed as **raw TCP host bindings**, directly reachable on the LAN. In-container ports are fixed constants; the configured value sets only the interface's `preferredExternalPort`, so a port change is a pure rebind that neither orphans a binding nor restarts the pool |
|
||||||
| `properties` for TLS fingerprint/PEM | **Stratum TLS Certificate** action (fingerprint + PEM, copyable) |
|
| `properties` for TLS fingerprint/PEM | **Stratum TLS Certificate** action (fingerprint + PEM, copyable) |
|
||||||
| Health checks: web / ckpool / bitcoin / submit-gap | Same four, plus an optional **ZMQ Block Feed** check, as daemon `ready` checks + standalone health checks |
|
| Health checks: web / ckpool / bitcoin / submit-gap | Same four, plus an optional **ZMQ Block Feed** check, as daemon `ready` checks + standalone health checks |
|
||||||
| duplicity backup of both volumes | `sdk.setupBackups` of both volumes (`main`, `ckpool`) |
|
| duplicity backup of both volumes | `sdk.setupBackups` of both volumes (`main`, `ckpool`) |
|
||||||
@@ -74,13 +74,13 @@ make KAMADO_SRC=/path/to/KamadoPool
|
|||||||
```text
|
```text
|
||||||
startos/
|
startos/
|
||||||
manifest/ id, images (local Dockerfile build), volumes, bitcoind dependency
|
manifest/ id, images (local Dockerfile build), volumes, bitcoind dependency
|
||||||
main.ts subcontainer, ckpool.conf + stunnel.conf rendering, daemons + health checks
|
main.ts subcontainer, ckpool.conf + stunnel.conf rendering, daemons + health checks (fixed internal ports)
|
||||||
interfaces.ts Web UI (http 8080), Stratum (raw TCP, configurable), Stratum TLS (raw TCP, configurable + conditional)
|
interfaces.ts Web UI (http 8080), Stratum (raw TCP, configurable), Stratum TLS (raw TCP, configurable + conditional)
|
||||||
fileModels/ store.json (service settings, incl. stratum ports)
|
fileModels/ store.json (service settings, incl. stratum ports)
|
||||||
actions/ Configure, Pool Status, Stratum TLS Certificate, Regenerate TLS Certificate, Reset Block Latency
|
actions/ Configure, Pool Status, Stratum TLS Certificate, Regenerate TLS Certificate, Reset Block Latency
|
||||||
dependencies.ts bitcoind (running, synced) + ZMQ autoconfig task
|
dependencies.ts bitcoind (running, synced) + ZMQ autoconfig task
|
||||||
backups.ts volumes: main, ckpool
|
backups.ts volumes: main, ckpool
|
||||||
versions/ 0.2.0:0 with migration from the 0.3.5.1 wrapper
|
versions/ 0.2.0:3 with migration from the 0.3.5.1 wrapper
|
||||||
init/ store seeding, init ordering
|
init/ store seeding, init ordering
|
||||||
i18n/ dictionaries (en, es, de, pl, fr)
|
i18n/ dictionaries (en, es, de, pl, fr)
|
||||||
assets/
|
assets/
|
||||||
|
|||||||
+2
-2
@@ -19,7 +19,7 @@ There is no payout address to configure. CKPool-solo pays the full block reward
|
|||||||
|
|
||||||
## Connecting miners
|
## Connecting miners
|
||||||
|
|
||||||
The stratum port defaults to **3333** and can be changed in the *Configure* action. StartOS tries to publish the pool on that same port number on your network, so it is normally the port you give your miners — but check the **Stratum** interface after saving to see the actual external port, since the OS assigns a different one if your choice is already in use. Point each miner at:
|
The stratum port defaults to **3333** and can be changed in the *Configure* action — that setting is the network port your miners connect to. Check the **Stratum** interface after saving to see the port actually in use, since the OS assigns a different one if your choice is already claimed by another service. Point each miner at:
|
||||||
|
|
||||||
```text
|
```text
|
||||||
stratum+tcp://<your-server-lan-address>:<stratum-port>
|
stratum+tcp://<your-server-lan-address>:<stratum-port>
|
||||||
@@ -43,7 +43,7 @@ Otherwise connect with `stratum+ssl://` and certificate verification disabled. U
|
|||||||
|
|
||||||
Everything lives in the **Configure** action: the stratum and stratum-TLS ports, vardiff (starting/min/max difficulty), idle-client disconnect, the coinbase tag embedded in solved blocks, ZMQ, TLS, log level, and an optional self-hosted mempool explorer URL for dashboard links.
|
Everything lives in the **Configure** action: the stratum and stratum-TLS ports, vardiff (starting/min/max difficulty), idle-client disconnect, the coinbase tag embedded in solved blocks, ZMQ, TLS, log level, and an optional self-hosted mempool explorer URL for dashboard links.
|
||||||
|
|
||||||
Changing a port restarts the pool and rebinds the interface, so miners will reconnect on the new port — update them accordingly. Port choices that cannot work (colliding with each other, with the dashboard, or with ckpool's internal TLS bind) are rejected when you save rather than failing at startup.
|
Changing a port rebinds the interface without restarting the pool, so miners already connected on other ports keep hashing — but anything pointed at the old port must be updated. Setting both stratum ports to the same number is rejected when you save.
|
||||||
|
|
||||||
## Actions
|
## Actions
|
||||||
|
|
||||||
|
|||||||
@@ -14,7 +14,7 @@ export const inputSpec = InputSpec.of({
|
|||||||
stratumPort: Value.number({
|
stratumPort: Value.number({
|
||||||
name: i18n('Stratum Port'),
|
name: i18n('Stratum Port'),
|
||||||
description: i18n(
|
description: i18n(
|
||||||
'TCP port the plaintext stratum server listens on. StartOS also tries to publish the pool on this same port number on your network, so this is normally the port you give your miners — check the Stratum interface after saving, since the OS will pick a different external port if this one is already taken.',
|
'Network port your miners connect to for plaintext stratum. StartOS publishes the pool on this port; if it is already claimed by another service the OS assigns a different one, so check the Stratum interface after saving. Changing this does not interrupt connected miners.',
|
||||||
),
|
),
|
||||||
required: true,
|
required: true,
|
||||||
default: defaultStratumPort,
|
default: defaultStratumPort,
|
||||||
@@ -25,7 +25,7 @@ export const inputSpec = InputSpec.of({
|
|||||||
stratumTlsPort: Value.number({
|
stratumTlsPort: Value.number({
|
||||||
name: i18n('Stratum TLS Port'),
|
name: i18n('Stratum TLS Port'),
|
||||||
description: i18n(
|
description: i18n(
|
||||||
'TCP port stunnel accepts TLS stratum connections on. Only used when Stratum TLS is enabled below.',
|
'Network port your miners connect to for TLS stratum. Only used when Stratum TLS is enabled below.',
|
||||||
),
|
),
|
||||||
required: true,
|
required: true,
|
||||||
default: defaultStratumTlsPort,
|
default: defaultStratumTlsPort,
|
||||||
@@ -141,9 +141,9 @@ export const config = sdk.Action.withInput(
|
|||||||
|
|
||||||
// the execution function
|
// the execution function
|
||||||
async ({ effects, input }) => {
|
async ({ effects, input }) => {
|
||||||
// Refuse port choices that cannot bind — all of these processes share one
|
// Refuse an unusable pair (both stratum ports set to the same number).
|
||||||
// network namespace, so a collision would surface as a restart loop after
|
// In-container ports are fixed constants, so the user can no longer create
|
||||||
// saving rather than as an error here.
|
// a bind collision — only an ambiguous external-port request.
|
||||||
const conflict = validatePorts({
|
const conflict = validatePorts({
|
||||||
stratumPort: input.stratumPort,
|
stratumPort: input.stratumPort,
|
||||||
stratumTlsPort: input.stratumTlsPort,
|
stratumTlsPort: input.stratumTlsPort,
|
||||||
|
|||||||
@@ -19,12 +19,13 @@ export const storeJson = FileHelper.json(
|
|||||||
},
|
},
|
||||||
z.object({
|
z.object({
|
||||||
/**
|
/**
|
||||||
* Port ckpool binds for plaintext stratum. Also requested as the
|
* EXTERNAL port miners connect to for plaintext stratum — requested as the
|
||||||
* interface's preferred external port, so miners reach the pool on this
|
* interface's `preferredExternalPort`. The in-container bind is a fixed
|
||||||
* same number whenever the OS can grant it.
|
* constant (see utils.ts), so changing this rebinds without restarting
|
||||||
|
* ckpool and never orphans a binding.
|
||||||
*/
|
*/
|
||||||
stratumPort: z.number().int().min(1).max(65535).catch(defaultStratumPort),
|
stratumPort: z.number().int().min(1).max(65535).catch(defaultStratumPort),
|
||||||
/** Port stunnel accepts TLS stratum on (only used when tlsEnabled). */
|
/** EXTERNAL port for TLS stratum (only used when tlsEnabled). */
|
||||||
stratumTlsPort: z
|
stratumTlsPort: z
|
||||||
.number()
|
.number()
|
||||||
.int()
|
.int()
|
||||||
|
|||||||
@@ -87,6 +87,8 @@ const dict = {
|
|||||||
'TCP port the plaintext stratum server listens on. StartOS also tries to publish the pool on this same port number on your network, so this is normally the port you give your miners — check the Stratum interface after saving, since the OS will pick a different external port if this one is already taken.': 83,
|
'TCP port the plaintext stratum server listens on. StartOS also tries to publish the pool on this same port number on your network, so this is normally the port you give your miners — check the Stratum interface after saving, since the OS will pick a different external port if this one is already taken.': 83,
|
||||||
'Stratum TLS Port': 84,
|
'Stratum TLS Port': 84,
|
||||||
'TCP port stunnel accepts TLS stratum connections on. Only used when Stratum TLS is enabled below.': 85,
|
'TCP port stunnel accepts TLS stratum connections on. Only used when Stratum TLS is enabled below.': 85,
|
||||||
|
'Network port your miners connect to for plaintext stratum. StartOS publishes the pool on this port; if it is already claimed by another service the OS assigns a different one, so check the Stratum interface after saving. Changing this does not interrupt connected miners.': 86,
|
||||||
|
'Network port your miners connect to for TLS stratum. Only used when Stratum TLS is enabled below.': 87,
|
||||||
} as const
|
} as const
|
||||||
|
|
||||||
/**
|
/**
|
||||||
|
|||||||
@@ -88,6 +88,8 @@ export default {
|
|||||||
83: 'Puerto TCP en el que escucha el servidor stratum sin cifrar. StartOS también intenta publicar el pool en ese mismo número de puerto en su red, por lo que normalmente es el puerto que dará a sus mineros: revise la interfaz Stratum después de guardar, ya que el sistema elegirá otro puerto externo si este ya está ocupado.',
|
83: 'Puerto TCP en el que escucha el servidor stratum sin cifrar. StartOS también intenta publicar el pool en ese mismo número de puerto en su red, por lo que normalmente es el puerto que dará a sus mineros: revise la interfaz Stratum después de guardar, ya que el sistema elegirá otro puerto externo si este ya está ocupado.',
|
||||||
84: 'Puerto TLS de stratum',
|
84: 'Puerto TLS de stratum',
|
||||||
85: 'Puerto TCP en el que stunnel acepta conexiones stratum TLS. Solo se usa cuando Stratum TLS está activado más abajo.',
|
85: 'Puerto TCP en el que stunnel acepta conexiones stratum TLS. Solo se usa cuando Stratum TLS está activado más abajo.',
|
||||||
|
86: 'Puerto de red al que se conectan sus mineros para stratum sin cifrar. StartOS publica el pool en este puerto; si ya está ocupado por otro servicio, el sistema asigna otro, así que revise la interfaz Stratum después de guardar. Cambiarlo no interrumpe a los mineros conectados.',
|
||||||
|
87: 'Puerto de red al que se conectan sus mineros para stratum TLS. Solo se usa cuando Stratum TLS está activado más abajo.',
|
||||||
},
|
},
|
||||||
de_DE: {
|
de_DE: {
|
||||||
0: '(noch nicht erzeugt — starten Sie den Dienst einmal)',
|
0: '(noch nicht erzeugt — starten Sie den Dienst einmal)',
|
||||||
@@ -176,6 +178,8 @@ export default {
|
|||||||
83: 'TCP-Port, auf dem der unverschlüsselte Stratum-Server lauscht. StartOS versucht außerdem, den Pool unter derselben Portnummer im Netzwerk zu veröffentlichen — normalerweise ist dies also der Port für Ihre Miner. Prüfen Sie nach dem Speichern die Stratum-Schnittstelle, denn das System wählt einen anderen externen Port, falls dieser belegt ist.',
|
83: 'TCP-Port, auf dem der unverschlüsselte Stratum-Server lauscht. StartOS versucht außerdem, den Pool unter derselben Portnummer im Netzwerk zu veröffentlichen — normalerweise ist dies also der Port für Ihre Miner. Prüfen Sie nach dem Speichern die Stratum-Schnittstelle, denn das System wählt einen anderen externen Port, falls dieser belegt ist.',
|
||||||
84: 'Stratum-TLS-Port',
|
84: 'Stratum-TLS-Port',
|
||||||
85: 'TCP-Port, auf dem stunnel TLS-Stratum-Verbindungen annimmt. Wird nur verwendet, wenn Stratum-TLS unten aktiviert ist.',
|
85: 'TCP-Port, auf dem stunnel TLS-Stratum-Verbindungen annimmt. Wird nur verwendet, wenn Stratum-TLS unten aktiviert ist.',
|
||||||
|
86: 'Netzwerk-Port, über den sich Ihre Miner für unverschlüsseltes Stratum verbinden. StartOS veröffentlicht den Pool auf diesem Port; ist er bereits von einem anderen Dienst belegt, weist das System einen anderen zu — prüfen Sie daher nach dem Speichern die Stratum-Schnittstelle. Eine Änderung unterbricht verbundene Miner nicht.',
|
||||||
|
87: 'Netzwerk-Port, über den sich Ihre Miner für TLS-Stratum verbinden. Wird nur verwendet, wenn Stratum-TLS unten aktiviert ist.',
|
||||||
},
|
},
|
||||||
pl_PL: {
|
pl_PL: {
|
||||||
0: '(jeszcze nie wygenerowano — uruchom usługę raz)',
|
0: '(jeszcze nie wygenerowano — uruchom usługę raz)',
|
||||||
@@ -264,6 +268,8 @@ export default {
|
|||||||
83: 'Port TCP, na którym nasłuchuje nieszyfrowany serwer stratum. StartOS próbuje również udostępnić pulę pod tym samym numerem portu w sieci, więc zwykle jest to port podawany górnikom — po zapisaniu sprawdź interfejs Stratum, ponieważ system wybierze inny port zewnętrzny, jeśli ten jest zajęty.',
|
83: 'Port TCP, na którym nasłuchuje nieszyfrowany serwer stratum. StartOS próbuje również udostępnić pulę pod tym samym numerem portu w sieci, więc zwykle jest to port podawany górnikom — po zapisaniu sprawdź interfejs Stratum, ponieważ system wybierze inny port zewnętrzny, jeśli ten jest zajęty.',
|
||||||
84: 'Port TLS stratum',
|
84: 'Port TLS stratum',
|
||||||
85: 'Port TCP, na którym stunnel przyjmuje połączenia stratum TLS. Używany tylko, gdy Stratum TLS jest włączone poniżej.',
|
85: 'Port TCP, na którym stunnel przyjmuje połączenia stratum TLS. Używany tylko, gdy Stratum TLS jest włączone poniżej.',
|
||||||
|
86: 'Port sieciowy, na który łączą się górnicy dla nieszyfrowanego stratum. StartOS udostępnia pulę na tym porcie; jeśli jest już zajęty przez inną usługę, system przydzieli inny — sprawdź interfejs Stratum po zapisaniu. Zmiana nie przerywa połączeń górników.',
|
||||||
|
87: 'Port sieciowy, na który łączą się górnicy dla stratum TLS. Używany tylko, gdy Stratum TLS jest włączone poniżej.',
|
||||||
},
|
},
|
||||||
fr_FR: {
|
fr_FR: {
|
||||||
0: '(pas encore généré — démarrez le service une fois)',
|
0: '(pas encore généré — démarrez le service une fois)',
|
||||||
@@ -352,5 +358,7 @@ export default {
|
|||||||
83: 'Port TCP sur lequel le serveur stratum en clair écoute. StartOS tente également de publier le pool sur ce même numéro de port sur votre réseau : c’est donc normalement le port à donner à vos mineurs. Vérifiez l’interface Stratum après enregistrement, car le système choisira un autre port externe si celui-ci est déjà pris.',
|
83: 'Port TCP sur lequel le serveur stratum en clair écoute. StartOS tente également de publier le pool sur ce même numéro de port sur votre réseau : c’est donc normalement le port à donner à vos mineurs. Vérifiez l’interface Stratum après enregistrement, car le système choisira un autre port externe si celui-ci est déjà pris.',
|
||||||
84: 'Port TLS stratum',
|
84: 'Port TLS stratum',
|
||||||
85: 'Port TCP sur lequel stunnel accepte les connexions stratum TLS. Utilisé uniquement lorsque Stratum TLS est activé ci-dessous.',
|
85: 'Port TCP sur lequel stunnel accepte les connexions stratum TLS. Utilisé uniquement lorsque Stratum TLS est activé ci-dessous.',
|
||||||
|
86: 'Port réseau auquel vos mineurs se connectent pour le stratum en clair. StartOS publie le pool sur ce port ; s’il est déjà pris par un autre service, le système en attribue un autre — vérifiez donc l’interface Stratum après enregistrement. Le modifier n’interrompt pas les mineurs connectés.',
|
||||||
|
87: 'Port réseau auquel vos mineurs se connectent pour le stratum TLS. Utilisé uniquement lorsque Stratum TLS est activé ci-dessous.',
|
||||||
},
|
},
|
||||||
} satisfies Record<string, LangDict>
|
} satisfies Record<string, LangDict>
|
||||||
|
|||||||
+20
-19
@@ -5,15 +5,19 @@ import {
|
|||||||
defaultStratumPort,
|
defaultStratumPort,
|
||||||
defaultStratumTlsPort,
|
defaultStratumTlsPort,
|
||||||
stratumHostId,
|
stratumHostId,
|
||||||
|
stratumInternalPort,
|
||||||
stratumTlsHostId,
|
stratumTlsHostId,
|
||||||
|
stratumTlsInternalPort,
|
||||||
uiHostId,
|
uiHostId,
|
||||||
uiPort,
|
uiPort,
|
||||||
} from './utils'
|
} from './utils'
|
||||||
|
|
||||||
export const setInterfaces = sdk.setupInterfaces(async ({ effects }) => {
|
export const setInterfaces = sdk.setupInterfaces(async ({ effects }) => {
|
||||||
// Stratum ports are user config. Read reactively so changing them in the
|
// The user's stratum ports are EXTERNAL ports only. Read reactively so
|
||||||
// Configure action re-runs this and rebinds the interfaces — the same
|
// changing them in the Configure action re-runs this and updates the
|
||||||
// mechanism that adds/removes the TLS interface when TLS is toggled.
|
// binding — the same mechanism that adds/removes the TLS interface when TLS
|
||||||
|
// is toggled. The in-container ports stay fixed (see utils.ts), so each
|
||||||
|
// change updates the existing binding rather than orphaning it.
|
||||||
const ports = await storeJson
|
const ports = await storeJson
|
||||||
.read((s) => ({
|
.read((s) => ({
|
||||||
stratum: s.stratumPort,
|
stratum: s.stratumPort,
|
||||||
@@ -22,8 +26,8 @@ export const setInterfaces = sdk.setupInterfaces(async ({ effects }) => {
|
|||||||
}))
|
}))
|
||||||
.const(effects)
|
.const(effects)
|
||||||
|
|
||||||
const stratumPort = ports?.stratum ?? defaultStratumPort
|
const externalStratumPort = ports?.stratum ?? defaultStratumPort
|
||||||
const stratumTlsPort = ports?.stratumTls ?? defaultStratumTlsPort
|
const externalStratumTlsPort = ports?.stratumTls ?? defaultStratumTlsPort
|
||||||
|
|
||||||
// Web dashboard
|
// Web dashboard
|
||||||
const uiMulti = sdk.MultiHost.of(effects, uiHostId)
|
const uiMulti = sdk.MultiHost.of(effects, uiHostId)
|
||||||
@@ -50,9 +54,9 @@ export const setInterfaces = sdk.setupInterfaces(async ({ effects }) => {
|
|||||||
// forwards raw TCP on the LAN, so miners connect directly to the host at
|
// forwards raw TCP on the LAN, so miners connect directly to the host at
|
||||||
// the assigned external port; no router forward or simpleproxy needed.
|
// the assigned external port; no router forward or simpleproxy needed.
|
||||||
const stratumMulti = sdk.MultiHost.of(effects, stratumHostId)
|
const stratumMulti = sdk.MultiHost.of(effects, stratumHostId)
|
||||||
const stratumOrigin = await stratumMulti.bindPort(stratumPort, {
|
const stratumOrigin = await stratumMulti.bindPort(stratumInternalPort, {
|
||||||
protocol: null,
|
protocol: null,
|
||||||
preferredExternalPort: stratumPort,
|
preferredExternalPort: externalStratumPort,
|
||||||
addSsl: null,
|
addSsl: null,
|
||||||
secure: { ssl: false },
|
secure: { ssl: false },
|
||||||
})
|
})
|
||||||
@@ -77,9 +81,9 @@ export const setInterfaces = sdk.setupInterfaces(async ({ effects }) => {
|
|||||||
// the noSsl scheme is deliberately stratum+ssl.
|
// the noSsl scheme is deliberately stratum+ssl.
|
||||||
if (ports?.tlsEnabled) {
|
if (ports?.tlsEnabled) {
|
||||||
const tlsMulti = sdk.MultiHost.of(effects, stratumTlsHostId)
|
const tlsMulti = sdk.MultiHost.of(effects, stratumTlsHostId)
|
||||||
const tlsOrigin = await tlsMulti.bindPort(stratumTlsPort, {
|
const tlsOrigin = await tlsMulti.bindPort(stratumTlsInternalPort, {
|
||||||
protocol: null,
|
protocol: null,
|
||||||
preferredExternalPort: stratumTlsPort,
|
preferredExternalPort: externalStratumTlsPort,
|
||||||
addSsl: null,
|
addSsl: null,
|
||||||
secure: { ssl: false },
|
secure: { ssl: false },
|
||||||
})
|
})
|
||||||
@@ -99,20 +103,17 @@ export const setInterfaces = sdk.setupInterfaces(async ({ effects }) => {
|
|||||||
receipts.push(await tlsOrigin.export([stratumTls]))
|
receipts.push(await tlsOrigin.export([stratumTls]))
|
||||||
}
|
}
|
||||||
|
|
||||||
// Drop bindings we no longer use. `bindPort` registers a binding per
|
// Drop bindings we no longer use — primarily the stratum-tls binding after
|
||||||
// (hostId, internalPort) and nothing removes the old one when the user
|
// the user disables TLS. With fixed internal ports this no longer has to
|
||||||
// changes a port in Configure — the stale binding lingers and the OS lists
|
// clean up after port changes (the whole point of keeping them fixed), but
|
||||||
// its interface again, so the UI shows two identical "Stratum" entries (and
|
// it still matters for the TLS toggle, and it clears orphans left by older
|
||||||
// keeps a forward open on the abandoned port). Packages with fixed ports
|
// versions of this package that did move the internal port.
|
||||||
// never hit this; ours has user-configurable ports, so it must clean up
|
|
||||||
// after itself. Runs last, after the current bindings exist, so the `except`
|
|
||||||
// list is exactly what we just bound.
|
|
||||||
await sdk.clearBindings(effects, {
|
await sdk.clearBindings(effects, {
|
||||||
except: [
|
except: [
|
||||||
{ id: uiHostId, internalPort: uiPort },
|
{ id: uiHostId, internalPort: uiPort },
|
||||||
{ id: stratumHostId, internalPort: stratumPort },
|
{ id: stratumHostId, internalPort: stratumInternalPort },
|
||||||
...(ports?.tlsEnabled
|
...(ports?.tlsEnabled
|
||||||
? [{ id: stratumTlsHostId, internalPort: stratumTlsPort }]
|
? [{ id: stratumTlsHostId, internalPort: stratumTlsInternalPort }]
|
||||||
: []),
|
: []),
|
||||||
],
|
],
|
||||||
})
|
})
|
||||||
|
|||||||
+33
-14
@@ -18,7 +18,9 @@ import {
|
|||||||
kamadoRoot,
|
kamadoRoot,
|
||||||
parseCookie,
|
parseCookie,
|
||||||
tlsDir,
|
tlsDir,
|
||||||
tlsInternalPort,
|
ckpoolTlsLoopbackPort,
|
||||||
|
stratumInternalPort,
|
||||||
|
stratumTlsInternalPort,
|
||||||
uiPort,
|
uiPort,
|
||||||
} from './utils'
|
} from './utils'
|
||||||
|
|
||||||
@@ -30,9 +32,25 @@ export const main = sdk.setupMain(async ({ effects }) => {
|
|||||||
*/
|
*/
|
||||||
console.info('Starting Kamado Pool!')
|
console.info('Starting Kamado Pool!')
|
||||||
|
|
||||||
// Service settings; reactive, so any config-action change restarts the
|
// Service settings; reactive, so a config-action change restarts the daemons
|
||||||
// daemons with a freshly rendered ckpool.conf.
|
// with a freshly rendered ckpool.conf. Deliberately a projection rather than
|
||||||
const store = await storeJson.read().const(effects)
|
// the whole file: stratumPort / stratumTlsPort are EXTERNAL ports owned by
|
||||||
|
// interfaces.ts, and the in-container binds are fixed constants. Excluding
|
||||||
|
// them here means changing a port is a pure rebind that leaves the pool
|
||||||
|
// running instead of kicking every connected miner.
|
||||||
|
const store = await storeJson
|
||||||
|
.read((s) => ({
|
||||||
|
coinbaseTag: s.coinbaseTag,
|
||||||
|
startDiff: s.startDiff,
|
||||||
|
minDiff: s.minDiff,
|
||||||
|
maxDiff: s.maxDiff,
|
||||||
|
dropIdle: s.dropIdle,
|
||||||
|
logLevel: s.logLevel,
|
||||||
|
zmqEnabled: s.zmqEnabled,
|
||||||
|
tlsEnabled: s.tlsEnabled,
|
||||||
|
mempoolExplorerUrl: s.mempoolExplorerUrl,
|
||||||
|
}))
|
||||||
|
.const(effects)
|
||||||
if (!store) throw new Error('No store.json')
|
if (!store) throw new Error('No store.json')
|
||||||
|
|
||||||
// bitcoind's RPC + ZMQ endpoints over the LXC bridge (see bitcoindBridge in
|
// bitcoind's RPC + ZMQ endpoints over the LXC bridge (see bitcoindBridge in
|
||||||
@@ -122,8 +140,8 @@ export const main = sdk.setupMain(async ({ effects }) => {
|
|||||||
blockpoll: 100,
|
blockpoll: 100,
|
||||||
update_interval: 30,
|
update_interval: 30,
|
||||||
serverurl: [
|
serverurl: [
|
||||||
`0.0.0.0:${store.stratumPort}`,
|
`0.0.0.0:${stratumInternalPort}`,
|
||||||
`127.0.0.1:${tlsInternalPort}`,
|
`127.0.0.1:${ckpoolTlsLoopbackPort}`,
|
||||||
],
|
],
|
||||||
mindiff: store.minDiff,
|
mindiff: store.minDiff,
|
||||||
startdiff: store.startDiff,
|
startdiff: store.startDiff,
|
||||||
@@ -142,10 +160,11 @@ export const main = sdk.setupMain(async ({ effects }) => {
|
|||||||
ckpoolConfTemplate,
|
ckpoolConfTemplate,
|
||||||
)
|
)
|
||||||
|
|
||||||
// stunnel.conf is rendered here rather than shipped as a static asset,
|
// stunnel.conf is rendered here rather than shipped as a static asset so it
|
||||||
// because the accept port is user config now. `connect` stays on ckpool's
|
// stays next to the ports it references. `connect` targets ckpool's loopback
|
||||||
// fixed loopback bind so TLS clients keep getting tagged server == 1 (the
|
// bind so TLS clients keep getting tagged server == 1 (the dashboard's lock
|
||||||
// dashboard's lock icon).
|
// icon); `accept` is the fixed in-container TLS port, which the OS forwards
|
||||||
|
// the user's chosen external port to.
|
||||||
if (store.tlsEnabled) {
|
if (store.tlsEnabled) {
|
||||||
const stunnelConf = [
|
const stunnelConf = [
|
||||||
'foreground = yes',
|
'foreground = yes',
|
||||||
@@ -166,8 +185,8 @@ export const main = sdk.setupMain(async ({ effects }) => {
|
|||||||
'options = NO_TLSv1_1',
|
'options = NO_TLSv1_1',
|
||||||
'',
|
'',
|
||||||
'[stratum]',
|
'[stratum]',
|
||||||
`accept = 0.0.0.0:${store.stratumTlsPort}`,
|
`accept = 0.0.0.0:${stratumTlsInternalPort}`,
|
||||||
`connect = 127.0.0.1:${tlsInternalPort}`,
|
`connect = 127.0.0.1:${ckpoolTlsLoopbackPort}`,
|
||||||
`cert = ${tlsDir}/stratum.pem`,
|
`cert = ${tlsDir}/stratum.pem`,
|
||||||
// No client-cert auth — stratum over TLS is opportunistic encryption;
|
// No client-cert auth — stratum over TLS is opportunistic encryption;
|
||||||
// the stratum protocol layer handles miner auth via username.
|
// the stratum protocol layer handles miner auth via username.
|
||||||
@@ -253,7 +272,7 @@ export const main = sdk.setupMain(async ({ effects }) => {
|
|||||||
display: i18n('Stratum Server'),
|
display: i18n('Stratum Server'),
|
||||||
gracePeriod: 30_000,
|
gracePeriod: 30_000,
|
||||||
fn: () =>
|
fn: () =>
|
||||||
sdk.healthCheck.checkPortListening(effects, store.stratumPort, {
|
sdk.healthCheck.checkPortListening(effects, stratumInternalPort, {
|
||||||
successMessage: i18n('The stratum server is accepting connections'),
|
successMessage: i18n('The stratum server is accepting connections'),
|
||||||
errorMessage: i18n(
|
errorMessage: i18n(
|
||||||
'The stratum server is not accepting connections',
|
'The stratum server is not accepting connections',
|
||||||
@@ -372,7 +391,7 @@ export const main = sdk.setupMain(async ({ effects }) => {
|
|||||||
fn: () =>
|
fn: () =>
|
||||||
sdk.healthCheck.checkPortListening(
|
sdk.healthCheck.checkPortListening(
|
||||||
effects,
|
effects,
|
||||||
store.stratumTlsPort,
|
stratumTlsInternalPort,
|
||||||
{
|
{
|
||||||
successMessage: i18n(
|
successMessage: i18n(
|
||||||
'TLS stratum is accepting connections',
|
'TLS stratum is accepting connections',
|
||||||
|
|||||||
+22
-32
@@ -17,41 +17,40 @@ import { sdk } from './sdk'
|
|||||||
export const uiPort = 8080
|
export const uiPort = 8080
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* Stratum port defaults. The live values are user config (see store.json) —
|
* In-container bind ports. These are FIXED and never user-configurable, which
|
||||||
* each one sets both ckpool's/stunnel's in-container bind AND the interface's
|
* is load-bearing: a binding is keyed by (hostId, internalPort), so moving an
|
||||||
* preferred external port, so the number the user picks is the number miners
|
* internal port registers a *new* binding and orphans the old one — StartOS
|
||||||
* connect to whenever the OS can grant it.
|
* disables the orphan but keeps listing it, and the user sees a duplicate
|
||||||
|
* interface. Keeping these constant means each host has exactly one binding
|
||||||
|
* for the lifetime of the install, and a port change is a pure rebind that
|
||||||
|
* doesn't even restart the daemons.
|
||||||
*/
|
*/
|
||||||
export const defaultStratumPort = 3333
|
export const stratumInternalPort = 3333
|
||||||
export const defaultStratumTlsPort = 3334
|
export const stratumTlsInternalPort = 3334
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* ckpool's second, loopback-only stratum bind. stunnel forwards decrypted TLS
|
* ckpool's second, loopback-only stratum bind. stunnel forwards decrypted TLS
|
||||||
* traffic here. ckpool tags clients by serverurl index (server == 1 -> TLS),
|
* traffic here. ckpool tags clients by serverurl index (server == 1 -> TLS),
|
||||||
* which the dashboard reads to render a lock icon next to encrypted miners —
|
* which the dashboard reads to render a lock icon next to encrypted miners —
|
||||||
* no source-IP heuristics needed. The bind is harmless when TLS is disabled
|
* no source-IP heuristics needed. The bind is harmless when TLS is disabled
|
||||||
* (nothing connects to it). Never user-visible, so it stays fixed — but it
|
* (nothing connects to it).
|
||||||
* does occupy a port inside the container, hence validatePorts() below.
|
|
||||||
*/
|
*/
|
||||||
export const tlsInternalPort = 3437
|
export const ckpoolTlsLoopbackPort = 3437
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* Ports already taken inside the service container, mapped to what occupies
|
* Defaults for the user-facing *external* ports (see store.json). These are
|
||||||
* them. A user-chosen stratum port may not collide with these.
|
* what miners connect to; they are requested as each interface's
|
||||||
|
* `preferredExternalPort` and the OS grants them when free. Same numbers as
|
||||||
|
* the internal binds, so the out-of-the-box experience is unchanged.
|
||||||
*/
|
*/
|
||||||
const occupiedPorts: Record<number, string> = {
|
export const defaultStratumPort = 3333
|
||||||
[uiPort]: 'the web dashboard',
|
export const defaultStratumTlsPort = 3334
|
||||||
[tlsInternalPort]: "ckpool's internal TLS bind",
|
|
||||||
}
|
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* Reject stratum port choices that cannot work: the two stratum ports would
|
* Reject external-port choices that cannot work. Since the user no longer
|
||||||
* collide with each other, or with a port already bound inside the container.
|
* picks any container-side port, the only real conflict left is asking for the
|
||||||
* Returns a human-readable reason, or null when the pair is usable.
|
* same external port twice. Returns a human-readable reason, or null when the
|
||||||
*
|
* pair is usable.
|
||||||
* All of these processes share one container (and therefore one network
|
|
||||||
* namespace), so a collision is a real bind failure at startup — better to
|
|
||||||
* refuse it in the config action than to restart-loop later.
|
|
||||||
*/
|
*/
|
||||||
export function validatePorts(opts: {
|
export function validatePorts(opts: {
|
||||||
stratumPort: number
|
stratumPort: number
|
||||||
@@ -60,16 +59,7 @@ export function validatePorts(opts: {
|
|||||||
}): string | null {
|
}): string | null {
|
||||||
const { stratumPort, stratumTlsPort, tlsEnabled } = opts
|
const { stratumPort, stratumTlsPort, tlsEnabled } = opts
|
||||||
|
|
||||||
const clash = occupiedPorts[stratumPort]
|
if (tlsEnabled && stratumPort === stratumTlsPort)
|
||||||
if (clash) return `Stratum port ${stratumPort} is already used by ${clash}.`
|
|
||||||
|
|
||||||
if (!tlsEnabled) return null
|
|
||||||
|
|
||||||
const tlsClash = occupiedPorts[stratumTlsPort]
|
|
||||||
if (tlsClash)
|
|
||||||
return `Stratum TLS port ${stratumTlsPort} is already used by ${tlsClash}.`
|
|
||||||
|
|
||||||
if (stratumPort === stratumTlsPort)
|
|
||||||
return `The stratum port and the stratum TLS port must differ (both are ${stratumPort}).`
|
return `The stratum port and the stratum TLS port must differ (both are ${stratumPort}).`
|
||||||
|
|
||||||
return null
|
return null
|
||||||
|
|||||||
@@ -21,18 +21,18 @@ type LegacyConfig = {
|
|||||||
}
|
}
|
||||||
|
|
||||||
export const current = VersionInfo.of({
|
export const current = VersionInfo.of({
|
||||||
version: '0.2.0:2',
|
version: '0.2.0:3',
|
||||||
releaseNotes: {
|
releaseNotes: {
|
||||||
en_US:
|
en_US:
|
||||||
'Adds configurable stratum and stratum-TLS ports to the Configure action, and fixes a duplicate Stratum interface left behind when a port is changed. StartOS 0.4.0 port: stratum is exposed directly on the LAN as a raw TCP interface (no more router forwards or simpleproxy), Bitcoin Core is reached over the internal network bridge with cookie authentication, and settings moved from Config to the Configure action. Existing settings, found-block history, and the stratum TLS certificate are migrated automatically.',
|
'The configurable stratum ports now set only the external (network-facing) port. The in-container ports are fixed, so changing a port no longer leaves a duplicate Stratum interface behind and no longer restarts the pool — connected miners stay connected. StartOS 0.4.0 port: stratum is exposed directly on the LAN as a raw TCP interface (no more router forwards or simpleproxy), Bitcoin Core is reached over the internal network bridge with cookie authentication, and settings moved from Config to the Configure action. Existing settings, found-block history, and the stratum TLS certificate are migrated automatically.',
|
||||||
es_ES:
|
es_ES:
|
||||||
'Añade puertos stratum y stratum-TLS configurables en la acción Configurar, y corrige una interfaz Stratum duplicada que quedaba al cambiar un puerto. Adaptación a StartOS 0.4.0: Stratum se expone directamente en la LAN como interfaz TCP, Bitcoin Core se alcanza a través del puente de red interno con autenticación por cookie, y la configuración se movió a la acción Configurar. Los ajustes existentes, el historial de bloques y el certificado TLS se migran automáticamente.',
|
'Los puertos stratum configurables ahora solo definen el puerto externo (de red). Los puertos internos del contenedor son fijos, así que cambiar un puerto ya no deja una interfaz Stratum duplicada ni reinicia el pool: los mineros conectados siguen conectados. Adaptación a StartOS 0.4.0: Stratum se expone directamente en la LAN como interfaz TCP, Bitcoin Core se alcanza a través del puente de red interno con autenticación por cookie, y la configuración se movió a la acción Configurar. Los ajustes existentes, el historial de bloques y el certificado TLS se migran automáticamente.',
|
||||||
de_DE:
|
de_DE:
|
||||||
'Fügt konfigurierbare Stratum- und Stratum-TLS-Ports in der Aktion „Konfigurieren“ hinzu und behebt eine doppelte Stratum-Schnittstelle, die beim Ändern eines Ports zurückblieb. Portierung auf StartOS 0.4.0: Stratum wird direkt im LAN als TCP-Schnittstelle bereitgestellt, Bitcoin Core wird über die interne Netzwerk-Bridge mit Cookie-Authentifizierung erreicht, und die Einstellungen sind in die Aktion „Konfigurieren“ umgezogen. Bestehende Einstellungen, Blockhistorie und das TLS-Zertifikat werden automatisch migriert.',
|
'Die konfigurierbaren Stratum-Ports legen jetzt nur noch den externen (netzseitigen) Port fest. Die containerinternen Ports sind fix, sodass eine Portänderung keine doppelte Stratum-Schnittstelle hinterlässt und den Pool nicht neu startet — verbundene Miner bleiben verbunden. Portierung auf StartOS 0.4.0: Stratum wird direkt im LAN als TCP-Schnittstelle bereitgestellt, Bitcoin Core wird über die interne Netzwerk-Bridge mit Cookie-Authentifizierung erreicht, und die Einstellungen sind in die Aktion „Konfigurieren“ umgezogen. Bestehende Einstellungen, Blockhistorie und das TLS-Zertifikat werden automatisch migriert.',
|
||||||
pl_PL:
|
pl_PL:
|
||||||
'Dodaje konfigurowalne porty stratum i stratum-TLS w akcji Konfiguruj oraz naprawia zduplikowany interfejs Stratum pozostający po zmianie portu. Port na StartOS 0.4.0: Stratum jest udostępniany bezpośrednio w sieci LAN jako interfejs TCP, Bitcoin Core jest osiągany przez wewnętrzny mostek sieciowy z uwierzytelnianiem cookie, a ustawienia przeniesiono do akcji Konfiguruj. Istniejące ustawienia, historia bloków i certyfikat TLS są migrowane automatycznie.',
|
'Konfigurowalne porty stratum ustawiają teraz wyłącznie port zewnętrzny (sieciowy). Porty wewnątrz kontenera są stałe, więc zmiana portu nie pozostawia już zduplikowanego interfejsu Stratum ani nie restartuje puli — podłączeni górnicy pozostają połączeni. Port na StartOS 0.4.0: Stratum jest udostępniany bezpośrednio w sieci LAN jako interfejs TCP, Bitcoin Core jest osiągany przez wewnętrzny mostek sieciowy z uwierzytelnianiem cookie, a ustawienia przeniesiono do akcji Konfiguruj. Istniejące ustawienia, historia bloków i certyfikat TLS są migrowane automatycznie.',
|
||||||
fr_FR:
|
fr_FR:
|
||||||
'Ajoute des ports stratum et stratum-TLS configurables dans l’action Configurer, et corrige une interface Stratum en double laissée après un changement de port. Portage vers StartOS 0.4.0 : Stratum est exposé directement sur le LAN comme interface TCP, Bitcoin Core est atteint via le pont réseau interne avec authentification par cookie, et les réglages ont migré vers l’action Configurer. Les réglages existants, l’historique des blocs et le certificat TLS sont migrés automatiquement.',
|
'Les ports stratum configurables ne définissent plus que le port externe (côté réseau). Les ports internes au conteneur sont fixes : changer un port ne laisse plus d’interface Stratum en double et ne redémarre plus le pool — les mineurs connectés le restent. Portage vers StartOS 0.4.0 : Stratum est exposé directement sur le LAN comme interface TCP, Bitcoin Core est atteint via le pont réseau interne avec authentification par cookie, et les réglages ont migré vers l’action Configurer. Les réglages existants, l’historique des blocs et le certificat TLS sont migrés automatiquement.',
|
||||||
},
|
},
|
||||||
migrations: {
|
migrations: {
|
||||||
up: async ({ effects }) => {
|
up: async ({ effects }) => {
|
||||||
|
|||||||
Reference in New Issue
Block a user