Mnemonic management
This is the page with no undo. Everything else in ChainOS can be re-derived, restored from a backup or rebuilt from the chain. The mnemonic cannot.
Ziklag never receives your mnemonic and holds nothing from which it can be reconstructed. There is no reset flow, no support escalation and no key escrow — because any of those would mean Ziklag held something that could reconstruct your keys, which is the property the product exists to deny.
Lose the phrase and the funds derived from it are unreachable. By anyone, permanently.
Treat it as you would an HSM master key, because that is what it is.
Generating
Offline, on a machine you trust, with a tool you trust.
- 12 or 24 words. Both are accepted. 24 words is 256 bits of entropy against 128 for 12; 128 bits is already beyond brute force, so the practical argument for 24 is margin against a future nobody has predicted rather than a present weakness.
- Use a real generator. Any BIP-39 implementation from a hardware wallet, a reputable offline tool, or your language's audited library. Do not compose a phrase from words you chose; human-chosen "random" words are guessable at a rate that has emptied real wallets.
- Do not use a passphrase-derived seed, brain wallet or any scheme where the entropy comes from something memorable.
- Do not reuse a mnemonic that has ever been typed into a website, an online generator, a note-taking app, or a wallet on a machine that has been compromised.
- Generate a separate one for sandbox. Cloud actively refuses the same identity in both
environments (
409 CROSS_ENVIRONMENT_IDENTITY), because sharing means your CI Edge holds the keys to live funds. See Environments.
Storing it for the Edge
The Edge reads the phrase from a file, once, at boot.
# On the host, outside any image build context.
umask 077
printf '%s' "$MNEMONIC" > /etc/chainos/mnemonic
chmod 0400 /etc/chainos/mnemonic
chown 10001 /etc/chainos/mnemonic # the uid the container runs as
Then mount it read-only, and set PASS_PHRASE_FILE to the mount path.
Things not to do, each of which has a specific leak:
| Don't | Because |
|---|---|
Pass it as PASS_PHRASE | Visible in docker inspect, /proc/<pid>/environ, crash dumps and most orchestrator UIs |
| Bake it into an image | Present in every layer, every registry copy, and every machine that pulls the image |
| Put it in a Compose file you commit | It is in git history forever, including after you delete it |
| Write it with a trailing newline you did not intend | Some tools include it in the phrase; BIP-39 validation then fails, which is at least loud |
echo it | Shell history. Use printf with the value from your secret manager, or a heredoc with a leading space where your shell supports it |
Secret managers. Vault, AWS Secrets Manager, Azure Key Vault, Google Secret Manager, Kubernetes Secrets with encryption-at-rest enabled and RBAC narrowed to the workload — any of these is appropriate. The Edge does not integrate with them directly; it reads a file, and your platform's existing secret-to-file mechanism is what you should use, because it is the one your operators already audit.
Backing it up
The backup is the part people get wrong, and they get it wrong in one of two directions: too few copies, or copies somewhere online.
- At least two copies, geographically separated, both offline. Paper in a safe, or a steel plate, or an encrypted volume on removable media held in different locations.
- Never in a password manager that syncs, in cloud storage, in email, in a screenshot, or in a photograph — a phone photo is in a cloud backup within minutes.
- Split it if your risk model calls for it. A 2-of-3 Shamir split (SLIP-39) or a documented split-custody arrangement is reasonable at a bank. What is not reasonable is an undocumented split where one holder leaves and nobody knows the reconstruction procedure.
- Restore it once, as a test, before you go live. An untested backup is not a backup. Do the restore into a throwaway sandbox Edge and confirm it derives the addresses you expect.
Export the address mapping too
The mnemonic recovers funds. It does not recover the mapping from address to customer — that is yours, and ChainOS is the only place it currently lives.
curl -s "$EDGE/addresses?size=1000" \
-H "X-API-Key: $CHAINOS_EDGE_KEY" \
| jq -r '.data.content[] | [.chain, .address, .derivationPath, .userRef, .tag] | @csv' \
>> chainos-addresses.csv
Run that on a schedule, page through if you have more than a thousand, and keep the result in your own systems. The console also exports CSV per screen.
With the mnemonic and this file you can reconstruct everything without ChainOS: the paths are deterministic and documented in HD derivation.
More than one wallet
If you arrived with wallets that predate ChainOS, your Edge can hold those too. They are
called key sources, they are registered with chainos-edge import-mnemonic, and
Migration covers the flow. Three
operational points belong here rather than there.
They are supplied the same way PASS_PHRASE is. A file your secret management mounts,
read at boot. The Edge does not invent a keystore for them and does not write key material
anywhere — which is the same rule as for the primary phrase, and the reason there is no
second thing to back up.
Mount each one on every replica that should be able to sign with it. A key source registered from one machine is registered for the account; the material is on whichever machines you put it on. A replica without it refuses a withdrawal from those addresses, which is correct and is not the failure you want to discover under load.
The manifest is metadata. chainos-edge import-mnemonic writes key-sources.json into
EDGE_DATA_DIR: a label, a fingerprint, the chains, the base path, and the path of the
file to read each phrase from. It contains no key material, it is safe to back up, and losing
it costs you the registration record on that machine and nothing else — re-running the import
rebuilds it, and ChainOS recognises the same wallet by its fingerprint rather than creating a
second one.
chainos-edge list-key-sources
shows what this machine knows about, and flags any source whose material is not configured here — the case where the phrase was piped in once and nothing kept it.
Signing with them happens at boot, or not at all. The Edge reads each source's secret when it starts, opens the wallet beside the primary one, and derives the addresses it registered so it knows which of them it holds keys for. A source whose secret is missing on that replica is reported at startup and its addresses are refused there — it is not retried later, because adding a wallet to a running signer would mean the same withdrawal got different answers depending on when it arrived. Mount the secret and restart.
chainos-edge list-key-sources --check
is the same work on demand: it loads every source and reports what this machine can actually
sign for, rather than what it was once told about. Run it on a new replica before you send
traffic to it. Without --check the command reads the manifest and nothing else, which is
why it is the default — a listing should not be a reason to read every recovery phrase on the
box.
Signing routes by address, never by what Cloud says. When a transaction arrives, the Edge
re-derives the sender from the primary phrase; if it does not match, it looks the address up
among the key sources it loaded and signs only if one of them actually derives it. ChainOS
knows which wallet owns which address and is never asked — the same principle as
chainos-edge prove-control, which searches for a derivation index rather than being handed
one. A withdrawal from an address no wallet on the machine derives is refused, and the
refusal names the sources whose material is not mounted there, because that is almost always
the cause.
Only EVM chains can be signed from a key source today. The Edge carries address codecs for Ethereum, BSC, Polygon, Avalanche and Base and deliberately not for Bitcoin, TRON or XRP — those addresses are derived in Cloud from the extended public key you registered. That is fine for watching and for reporting, and it means the Edge cannot tell whose address a Bitcoin sender is. So if you register a key source covering Bitcoin, TRON or XRP, withdrawals on that chain are refused on this Edge rather than signed with the primary phrase's key, which would produce a valid-looking signature for the wrong wallet. Sweep or withdraw those chains from the wallet that holds them.
Rotating
Prefer not to. Rotating a mnemonic is not like rotating an API key. Addresses derived from the old phrase stay valid on-chain and stay funded; addresses derived from the new one are different. Any deposit sent to an old address after rotation is recoverable only with the old phrase, so "rotation" in practice means "run two mnemonics indefinitely".
ChainOS handles that correctly — addresses derived from prior extended public keys stay monitored forever, so nothing already issued goes dark — but the operational burden of two sets of keys is real and permanent.
Rotate when the old phrase may be compromised. Do not rotate on a schedule.
The procedure
- Generate the new mnemonic and back it up, fully, before touching anything.
- Sweep or plan to sweep funds from addresses derived from the old phrase into your treasury, using the old phrase. Do this first — after step 4 you are running two Edges.
- Tell your customers which deposit addresses are changing, if you re-issue. If you do not re-issue, old addresses keep working and this step is unnecessary.
- Start an Edge with the new mnemonic. Cloud sees a different identity key, refuses to derive against it, quarantines the new extended public keys, and pages your account owner. This is the expected behaviour, not a failure.
- Approve the rotation in the console, with a fresh TOTP code, as an owner. Read Identity rotation before you do — that page is what explains why the gate is there.
- Keep the old phrase. Forever. It is the only key to funds already sitting at old addresses, including deposits that arrive after the rotation.
What must never happen
Do not start an Edge with a different mnemonic while expecting it to serve the same account, in the belief that ChainOS will "just use the new keys". It will not: it will refuse authentication before reading the payload, quarantine the keys, and alert. That refusal is the feature. An implementation that accepted the new phrase silently would derive new addresses for existing customers while their deposits kept arriving at addresses whose keys your new Edge does not hold.
If the Edge cannot read the file
The failure modes, in the order they occur:
| Symptom | Cause |
|---|---|
mnemonic file not readable | File mode or ownership. The container's uid must be able to read it |
invalid BIP-39 checksum | A typo, a wrong word, or a trailing newline included in the phrase |
mlock failed | The container lacks IPC_LOCK, or the host's memlock limit is too low. The Edge fails rather than continuing with a swappable seed |
| Derives the wrong addresses | The phrase is right but a word is transposed. Check against the published test vectors in Installation |
Troubleshooting has the diagnostics for each.