fix: render the Electrum address as ssl://; 0.11.1:18 → 0.11.1:19 - #83
Merged
Merged
Conversation
A user who migrated from 0.3.5.1 could not connect Sparrow to either the
LAN or the onion endpoint, getting only "Retries exhausted". The endpoint
was fine: openssl s_client against it returned the StartOS chain, and
turning Sparrow's SSL toggle on connected immediately.
The Interfaces page gave no sign it had to be on. bindPort with
protocol: null returns an origin with no scheme, and StartOS renders a
scheme-less address as a bare host:port — so the page showed
192.168.x.x:50001 and nothing else. The only SSL marker on the row is the
certificate column reading "Root CA".
Sets schemeOverride: { ssl: 'ssl', noSsl: 'tcp' } so every address renders
ssl://host:port, the form Electrum wallets expect to be handed, and renames
the interface Main → Electrum (SSL) to match Fulcrum. The name is accurate:
no LAN or WAN gateway gets a forward for the plaintext port, so TLS is the
only way in from off the box.
The docs also named 50002 as if it were guaranteed. It is a preference, and
whatever StartOS assigns is permanent — an existing binding never changes
its external port, so the number is per-server for the life of the install.
That is why the reporter's server serves TLS on 50001 and will keep doing
so. instructions.md now points at the Interfaces page instead of naming a
port, and tells the user which toggle to look for.
And they claimed no plaintext port is exposed externally. One is allocated
and reachable at the bridge IP from the host and other services over
lxcbr0 — it is what getBridgeAddress hands to mempool, specter and canary,
and what replaced the retired electrs.startos name — it is just never
reachable from another machine. Corrected in README.md and AGENTS.md.
Freezes 0.11.1:18 into its own version file to keep its clearTask migration
reachable from :17 and below.
helix-nine
force-pushed
the
fix/electrum-address-shows-ssl-scheme
branch
from
August 9, 2026 16:08
113b527 to
64b42c1
Compare
MattDHill
added a commit
to Start9Labs/fulcrum-startos
that referenced
this pull request
Aug 9, 2026
Folded into 2.1.1:13. Same defect reported against electrs (Start9-Community/electrs-startos#83) and present here identically: bindPort with protocol: null returns an origin with no scheme, and StartOS renders a scheme-less address as a bare host:port. The Interfaces page showed no sign the endpoint was TLS, and a wallet configured from it failed with a generic timeout — Sparrow reports only "Retries exhausted", naming neither SSL nor the certificate. Fulcrum was partly shielded by already naming its interface Electrum (SSL), which is why this surfaced on electrs first, but the address itself was just as bare. Sets schemeOverride: { ssl: 'ssl', noSsl: 'tcp' } so every address renders ssl://host:port, the form Electrum wallets expect to be handed. instructions.md now tells the user which toggle to look for and to take the port from the address rather than assuming one: preferredExternalPort is a preference, and whatever StartOS assigns is permanent, so the number is per-server for the life of the install. README.md records that, and pins down the plaintext leg: no LAN or WAN gateway gets a forward for it, but it is reachable at the bridge IP from the host and other services over lxcbr0 — that is what getBridgeAddress returns and what replaced the retired fulcrum.startos name. Release notes gain a paragraph; no separate version, since 2.1.1:13 is unreleased.
MattDHill
approved these changes
Aug 9, 2026
MattDHill
added a commit
to Start9Labs/fulcrum-startos
that referenced
this pull request
Aug 9, 2026
…ss as ssl:// (#16) * feat(2.1.1:13): size db_mem to the box and reclaim it after sync Fulcrum's own db_mem default is a flat 2048 MiB regardless of box size, tuned for a dedicated Electrum server. On StartOS it is never alone — the package has a hard dependency on Bitcoin — and the package wrote no db_mem at all, so every install inherited that 2048 on top of Bitcoin's own cache. A 4 GB box got a RocksDB budget over half its RAM, which upstream explicitly advises against. Seed db_mem at install to a quarter of installed RAM, capped at upstream's 2048, then drop it to 512 once the address index is built (upstream: "even 256 works well on an SSD"). Only the value we seeded is ever lowered, so anything set through Configure is left alone. The migration backfills existing installs according to their sync state. main.ts now consts the whole fulcrum.conf, registered after the bitcoind bridge-address merge so that write is already part of the captured value — consting first would make the service restart itself once on every start. Fulcrum reads its config only at startup, so this is also what makes a Configure save take effect: previously the action wrote the file and nothing restarted, leaving db_mem, worker_threads and bitcoind_clients changes silently inert until something else restarted the service. The post-sync write is the package's sole allowWriteAfterConst. It is self-extinguishing twice over: syncNotified is persisted before it, and merge skips writing byte-identical output. Also folds in the abandoned bitcoind:other-config replay key that TODO.md had been holding for the next shipping version. Co-Authored-By: Claude Opus 5 (1M context) <noreply@anthropic.com> * fix: render the Electrum address as ssl:// Folded into 2.1.1:13. Same defect reported against electrs (Start9-Community/electrs-startos#83) and present here identically: bindPort with protocol: null returns an origin with no scheme, and StartOS renders a scheme-less address as a bare host:port. The Interfaces page showed no sign the endpoint was TLS, and a wallet configured from it failed with a generic timeout — Sparrow reports only "Retries exhausted", naming neither SSL nor the certificate. Fulcrum was partly shielded by already naming its interface Electrum (SSL), which is why this surfaced on electrs first, but the address itself was just as bare. Sets schemeOverride: { ssl: 'ssl', noSsl: 'tcp' } so every address renders ssl://host:port, the form Electrum wallets expect to be handed. instructions.md now tells the user which toggle to look for and to take the port from the address rather than assuming one: preferredExternalPort is a preference, and whatever StartOS assigns is permanent, so the number is per-server for the life of the install. README.md records that, and pins down the plaintext leg: no LAN or WAN gateway gets a forward for it, but it is reachable at the bridge IP from the host and other services over lxcbr0 — that is what getBridgeAddress returns and what replaced the retired fulcrum.startos name. Release notes gain a paragraph; no separate version, since 2.1.1:13 is unreleased. --------- Co-authored-by: Matt Hill <9935159+MattDHill@users.noreply.github.com> Co-authored-by: Claude Opus 5 (1M context) <noreply@anthropic.com>
This file contains hidden or bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Sign up for free
to join this conversation on GitHub.
Already have an account?
Sign in to comment
Add this suggestion to a batch that can be applied as a single commit.This suggestion is invalid because no changes were made to the code.Suggestions cannot be applied while the pull request is closed.Suggestions cannot be applied while viewing a subset of changes.Only one suggestion per line can be applied in a batch.Add this suggestion to a batch that can be applied as a single commit.Applying suggestions on deleted lines is not supported.You must change the existing code in this line in order to create a valid suggestion.Outdated suggestions cannot be applied.This suggestion has been applied or marked resolved.Suggestions cannot be applied from pending reviews.Suggestions cannot be applied on multi-line comments.Suggestions cannot be applied while the pull request is queued to merge.Suggestion cannot be applied right now. Please check back later.
The report
A user who had just migrated from 0.3.5.1 found Electrs running, fully synced, and reporting "Electrum Server is ready and accepting connections". The Interfaces page showed the Main IPv4 endpoint as
192.168.x.x:50001. Sparrow could reach neither that nor the onion, returning only "Retries exhausted".The endpoint was fine.
ncreached 50001, andopenssl s_clientagainst it came back with the StartOS certificate chain. Setting Private Electrum → port 50001 → Use SSL ON connected immediately, toelectrs/0.11.1, protocol 1.4.Their words: "the current Electrs Interfaces page shows :50001, but it isn't obvious from that screen that Sparrow needs SSL enabled. The Electrs Instructions also appear to reference SSL on port 50002, which made troubleshooting more confusing."
Both halves of that are our bug.
Nothing said the endpoint was TLS
MultiHost.bindPortwithprotocol: nullreturnsnew Origin(this, internalPort, null, null)—schemeandsslSchemeare both null, and this package passedschemeOverride: nullon top.addressHostToUrlomits the://prefix entirely when the effective scheme is null, so StartOS printed a barehost:port. The only SSL signal on the row is the certificate column reading "Root CA", which is easy to miss, and the interface was called "Main".schemeOverride: { ssl: 'ssl', noSsl: 'tcp' }makes every address renderssl://host:port— the form Electrum wallets expect to be handed. This is well-worn in the fleet: coturn usesturns/turn, owntracksmqtts/mqtt, lndlndconnect, simplexsmp.The interface is renamed Main → Electrum (SSL). That name is accurate rather than aspirational: the plaintext leg's forward is gated on
!reqs.secure && !info.secure()(net/forward.rs:705), andinfo.secure()holds only forLoopback | Bridge, so no LAN or WAN gateway ever gets a rule for it. TLS is the only way in from off the box.The plaintext port is not unbound, though — it is reachable at the bridge IP from the host and from other services over
lxcbr0, source-filtered to that subnet. That is whatgetBridgeAddress(…, { ssl: false })returns, and what replaced the retiredelectrs.startosDNS name.The docs named a port StartOS never promised
instructions.mdnamed 50002 three times.preferredExternalPortis a preference:BindInfo::newtries it and otherwise falls back toalloc(), and an assigned binding then never changes its external port — integrations depend on it, so only uninstall and reinstall reassigns. The number is per-server and fixed for the life of the install.Which is exactly why this user was on 50001. Their 0.3.x manifest bound one port and had
lan-configcommented out:The v1 compat shim maps that to
{preferredExternalPort: 50001, addSsl: null}(addSslcomes only fromlan-config), givingassignedPort: 50001, assignedSslPort: None. The 0.4 package reuses the same host id (electrum) and internal port, so installing it hitBindInfo::updaterather thannew, where the since-removedcarriedhanded that lone number to the TLS leg. Start9Labs/start-technologies#3638 stops that happening again; it does not and should not move servers already assigned.So
instructions.mdno longer names a port. It points at the Interfaces page, and names the toggle — Private Electrum → Use SSL in Sparrow, thessuffix in Electrum — since the failure mode is a generic timeout that mentions neither TLS nor the certificate.A wrong claim in the developer docs
README.mdandAGENTS.mdboth said no plain-TCP port is exposed externally. One is allocated and reachable over the bridge, as above. Corrected in both, andAGENTS.mdkeeps one bullet on it — the interface is TLS-only from off the box, the plaintext port is the bridge address dependents resolve, and no literal external port belongs in docs.Version
0.11.1:18 → 0.11.1:19. Interface metadata and docs only, so no migration — but :18 carried the
clearTaskmigration for bitcoind's action renames, so it is frozen intostartos/versions/v0.11.1_18.tsand added to the graph to keep it reachable from :17 and below.Verified with
npm run checkand prettier. Not installed on a box — the change isexportServiceInterfacemetadata, whichsetupInterfacesre-emits on update.