simd for the chain binary. The node home is ~/.kms-demo-node and the signer home is ~/.kms-demo.
Prerequisites
- Go 1.26 or later, make, git, jq, and curl.
- A chain binary at Cosmos SDK 0.55 or later. The tutorial uses
simd, built withmake installin the cosmos-sdk repo. To build it and run a node, see Run a node.
1. Install Cosmos-KMS
Clone and install the signer:2. Create a single-node chain
Set up a fresh chain home with one validator. Do not start the node yet:3. Initialize the signer
Scaffold the signer’s home. This writes a stubkms.yaml and generates identity.json, the key the signer uses to authenticate its connection:
initialized kms in /Users/you/.kms-demo. Pass the --home flag on every kms command. Without it, the signer uses the current directory.
4. Give the signer the consensus key
Copy the consensus key thatsimd init generated into the signer’s home:
Once the node is configured for remote signing, it never reads its local key file again. In production, move the key instead of copying it. Note that the node regenerates a fresh, unused consensus key file if it finds none, so moving the key reduces what is on the node host rather than leaving it key-free. For this tutorial, the copy keeps things simple.
5. Configure the signer
Replace the contents of~/.kms-demo/kms.yaml with:
kms-demo-1, dial its node at port 26659, and read the copied key file as an ed25519 key. The file backend has no default algorithm, so the algorithm line is required. Relative paths resolve against the signer’s home.
6. Point the node at the signer
Open~/.kms-demo-node/config/config.toml, find the priv_validator_laddr line, and set it:
7. Start the signer
The node needs its signer available the moment it starts, so bring the signer up first:kms-demo-1, so no sign-state file exists yet. --allow-fresh-state writes the height-0 double-sign floor on this first start. Without it the signer refuses to start rather than risk re-signing a height it cannot prove it has already passed.
To seed the floor as a separate step instead, run kms state init --chain kms-demo-1 --height 0 --home ~/.kms-demo and then start the signer with no flag.
The signer logs kms started and dials the node. The node is not running yet, so the signer logs dial failed; backing off and keeps retrying. That is expected. Leave it running.
8. Start the node
In a second terminal, start the node within five seconds of starting the signer:If
simd start exits with can't get pubkey: ... endpoint connection timed out, the signer has backed off to slow retries. Restart the signer, then start the node again within five seconds.9. Prove the signer is doing the signing
Stop the signer with Ctrl-C and watch the node’s logs. Block production stalls because the validator can no longer sign. Start the signer again, this time with no--allow-fresh-state, because the state file now exists and carries the highest height signed so far:
What you built
A validator whose consensus key lives outside the node. The node handles consensus and networking. The signer holds the key and signs, and the double-sign state file travels with it. The file backend keeps this tutorial self-contained, but it holds the key in plaintext on disk and is not production custody. The production version of this setup swaps one config block to move the key into an HSM or AWS KMS.Next steps
- Swap the file backend for real custody, AWS KMS or an HSM. See Configure a signing backend.
- Harden the signer’s placement and transport. See Remote signing best practices.
- Understand the architecture you just ran. See Cosmos-KMS and remote signing.
- Look up any config field. See the configuration reference.