Skip to main content
This guide installs citadel-core as a systemd service on each host of a three-node cluster. It is the production path for bare-metal or virtual-machine deployments; for containers see Kubernetes or ECS.

Prerequisites

  • At least three Linux hosts with network connectivity between them. ARM hosts are supported.
  • A production NATS cluster with JetStream, TLS and credentials, reachable from every host.
  • A production Consul cluster reachable from every host.
  • git and mkcert (or your own CA) for TLS material; age if you encrypt identity keys.
  • The citadel-core binaries from Blockops, installed to /usr/local/bin/citadel-core and /usr/local/bin/citadel-core-cli.
Every command below that generates key material (peers, identities, the initiator key, passwords, the chain code) produces secrets that protect customer funds. Run them on a secure workstation, store the outputs in your secrets manager, and never leave copies in shell history or shared directories.

Install

1

Create the service user and directories (every host)

2

Generate the peer registry (one host only)

This writes peers.json, mapping node0, node1 and node2 to random IDs. Copy the same file to /opt/citadel-core/peers.json on every host; the registry must be identical everywhere.
3

Generate the event initiator key (one host only)

This produces event_initiator.identity.json (public key) and event_initiator.key.age (encrypted private key). The private key goes to the system that initiates MPC operations, citadel-api. The public key goes into every node’s configuration in the next step.
4

Write the configuration (every host)

Copy the production template to /etc/citadel-core/config.yaml and set:
  • nats.url, nats.username, nats.password and the nats.tls certificate paths
  • consul.address and its credentials
  • mpc_threshold: 2 for a three-node cluster
  • event_initiator_pubkey: the public_key from event_initiator.identity.json
  • chain_code: one value generated with openssl rand -hex 32, identical on every node
  • environment: production
Then lock the file down:
The configuration reference explains each key.
5

Register peers and generate the node identity (every host)

generate-identity writes identity/node0_identity.json and identity/node0_private.key.age. Copy every node’s *_identity.json (never the private key) into /opt/citadel-core/identity/ on every host, so each node can verify its peers.
6

Install TLS certificates

Place the NATS client certificate, key and CA under /opt/citadel-core/certs/ (client-cert.pem, client-key.pem, rootCA.pem) and reference them from nats.tls in the configuration.
7

Provide the share-store password

The share store is encrypted under a password that is supplied to the service through systemd’s encrypted credentials, not written to the configuration file. Blockops’ setup-citadel-core-cred.sh prompts for the password and seals it for the unit.
Back the password up in your secrets manager before starting the node. The share store cannot be opened without it, and it cannot be changed after the database is created.
8

Install and start the service

A healthy start logs, in order: the version banner, Connected to badger kv store, Loaded peers from consul, [READY] Node is ready, Starting consumers.

The service unit

The unit installed by setup-config.sh runs the node as the unprivileged citadel-core user with the configuration directory read-only and the data directory writable, and applies systemd hardening:
CITADEL_CORE_NODE_NAME is set in /opt/citadel-core/.env on each host (node0, node1, node2).

Resulting layout

Next

Continue with Operate a cluster for health checks, backups, upgrades and recovery, and confirm the security checklist before the cluster holds production shares.