Skip to main content
This tutorial builds a working remote signer from scratch: a single-node local chain where a Cosmos-KMS process signs the votes instead of the node itself. It uses the file backend, which needs no HSM or cloud account and exists for exactly this kind of learning setup. At the end, you stop the signer and watch the chain stall, which proves where signing really happens. Commands use 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 with make install in the cosmos-sdk repo.

1. Install Cosmos-KMS

Clone and install the signer:
Confirm the binary works:

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 stub kms.yaml and generates identity.json, the key the signer uses to authenticate its connection:
The command prints 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 that simd 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, so no key material remains on the node host. For this tutorial, the copy keeps things simple.

5. Configure the signer

Replace the contents of ~/.kms-demo/kms.yaml with:
The three blocks say: sign for the chain 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:
With this set, the node signs nothing locally. It listens on that port for a signer connection and forwards every vote and proposal to it.

7. Start the signer

The node needs its signer available the moment it starts, so bring the signer up first:
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:
The node opens its private-validator listener on port 26659. The signer’s next dial connects, the node fetches its consensus public key from the signer, and block production begins. Confirm the height is climbing:
Also confirm the signer created its double-sign protection state file:
The node cannot start consensus without its signer. Start it while no signer is reachable and simd start exits with can't get pubkey: ... endpoint connection timed out instead of waiting. If the node exits this way, leave the signer running and rerun simd start; it keeps retrying and connects.

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:
The signer reconnects and the chain resumes. The node never touches a private key. Every signature comes from the signer.

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