Production‑ready, geo‑distributed NATS messaging backbone with clustering, gateways, leafnodes, JWT authentication, and mutual TLS — all running on ARM64.
This repository provides a production‑ready, geo‑distributed NATS messaging backbone running natively on ARM64 hardware (Raspberry Pi, Apple Silicon, AWS Graviton). It features:
All communication is secured with mutual TLS, and authentication is handled via NKeys and JWT credentials.
| Component | Version/Spec |
|---|---|
| CPU | ARM64 (aarch64) |
| OS | Debian GNU/Linux 12 (bookworm) or later |
| Docker | 24+ |
| NATS CLI | 0.4.0+ |
| Python | 3.9+ with nats-py |
| OpenTofu | 1.12.1 |
| nsc | 2.15.0 |
| Service | Port | Description |
|---|---|---|
| Client MSG | 4222 | Client connections (via HAProxy) |
| Cluster Route | 6222 | Internal cluster mesh |
| Gateway | 7222 | Cross site gateway connections |
| Leafnode | 7333 | Leafnode listener |
| Monitoring | 8222 | HTTP monitoring endpoint |
| NATS UI | 31311 | Web UI (exposed on host) |
All connections (client, cluster, leafnode, gateway) use TLS with mutual authentication.
certs/
├── ca/
│ └── ca.crt
└── tls/
├── nats-s1-1.crt
├── nats-s1-1.key
├── nats-s1-2.crt
├── nats-s1-2.key
├── nats-s1-3.crt
├── nats-s1-3.key
├── nats-s2-1.crt
├── nats-s2-1.key
├── nats-s2-2.crt
├── nats-s2-2.key
├── nats-s2-3.crt
├── nats-s2-3.key
├── nats-leaf-s1-1.crt
├── nats-leaf-s1-1.key
├── testclient.crt
└── testclient.key
Routes
╭─────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────╮
│ Cluster Report │
├───────────┬─────────┬───────────┬─────────────────────────┬───────────────────┬────────┬──────────┬───────┬──────┬──────────┬───────────┤
│ Server │ Cluster │ Name │ Account │ Address │ ID │ Uptime │ RTT │ Subs │ Bytes In │ Bytes Out │
├───────────┼─────────┼───────────┼─────────────────────────┼───────────────────┼────────┼──────────┼───────┼──────┼──────────┼───────────┤
│ nats-s1-1 │ c1_red │ nats-s1-2 │ │ 172.22.0.11:6222 │ rid:9 │ 1h28m54s │ 371µs │ 22 │ 0 B │ 0 B │
│ │ │ │ │ 172.22.0.11:6222 │ rid:13 │ 1h28m54s │ 375µs │ 0 │ 0 B │ 0 B │
│ │ │ │ │ 172.22.0.11:6222 │ rid:17 │ 1h28m54s │ 353µs │ 0 │ 0 B │ 0 B │
│ │ │ │ ACMJJEA4TT...UZ5PIJR6QR │ 172.22.0.11:6222 │ rid:8 │ 1h28m54s │ 206µs │ 80 │ 1.7 MiB │ 3.1 MiB │
│ │ │ nats-s1-3 │ │ 172.22.0.12:6222 │ rid:14 │ 1h28m54s │ 313µs │ 0 │ 0 B │ 0 B │
│ │ │ │ │ 172.22.0.12:33742 │ rid:11 │ 1h28m54s │ 530µs │ 6 │ 0 B │ 0 B │
│ │ │ │ │ 172.22.0.12:6222 │ rid:10 │ 1h28m54s │ 359µs │ 0 │ 0 B │ 0 B │
│ │ │ │ ACMJJEA4TT...UZ5PIJR6QR │ 172.22.0.12:33756 │ rid:12 │ 1h28m54s │ 632µs │ 79 │ 4.1 MiB │ 3.1 MiB │
│ nats-s1-2 │ c1_red │ nats-s1-1 │ │ 172.22.0.10:38838 │ rid:17 │ 1h28m54s │ 221µs │ 0 │ 0 B │ 0 B │
│ │ │ │ │ 172.22.0.10:38816 │ rid:9 │ 1h28m54s │ 750µs │ 2 │ 0 B │ 0 B │
│ │ │ │ │ 172.22.0.10:38828 │ rid:14 │ 1h28m54s │ 211µs │ 0 │ 0 B │ 0 B │
│ │ │ │ ACMJJEA4TT...UZ5PIJR6QR │ 172.22.0.10:38826 │ rid:8 │ 1h28m54s │ 196µs │ 76 │ 3.1 MiB │ 1.7 MiB │
│ │ │ nats-s1-3 │ │ 172.22.0.12:60276 │ rid:10 │ 1h28m54s │ 176µs │ 6 │ 0 B │ 0 B │
│ │ │ │ │ 172.22.0.12:60292 │ rid:13 │ 1h28m54s │ 229µs │ 0 │ 0 B │ 0 B │
│ │ │ │ │ 172.22.0.12:60296 │ rid:16 │ 1h28m54s │ 307µs │ 0 │ 0 B │ 0 B │
│ │ │ │ ACMJJEA4TT...UZ5PIJR6QR │ 172.22.0.12:60264 │ rid:11 │ 1h28m54s │ 758µs │ 79 │ 4.3 MiB │ 1.9 MiB │
│ nats-s1-3 │ c1_red │ nats-s1-1 │ │ 172.22.0.10:6222 │ rid:11 │ 1h28m54s │ 784µs │ 2 │ 0 B │ 0 B │
│ │ │ │ │ 172.22.0.10:55438 │ rid:8 │ 1h28m54s │ 240µs │ 0 │ 0 B │ 0 B │
│ │ │ │ │ 172.22.0.10:55442 │ rid:14 │ 1h28m54s │ 271µs │ 0 │ 0 B │ 0 B │
│ │ │ │ ACMJJEA4TT...UZ5PIJR6QR │ 172.22.0.10:6222 │ rid:12 │ 1h28m54s │ 246µs │ 76 │ 3.1 MiB │ 4.1 MiB │
│ │ │ nats-s1-2 │ │ 172.22.0.11:6222 │ rid:9 │ 1h28m54s │ 219µs │ 22 │ 0 B │ 0 B │
│ │ │ │ │ 172.22.0.11:6222 │ rid:13 │ 1h28m54s │ 227µs │ 0 │ 0 B │ 0 B │
│ │ │ │ │ 172.22.0.11:6222 │ rid:17 │ 1h28m54s │ 209µs │ 0 │ 0 B │ 0 B │
│ │ │ │ ACMJJEA4TT...UZ5PIJR6QR │ 172.22.0.11:6222 │ rid:10 │ 1h28m54s │ 600µs │ 80 │ 1.9 MiB │ 4.2 MiB │
│ nats-s2-1 │ c2_blu │ nats-s2-2 │ │ 172.22.0.31:6222 │ rid:10 │ 1h28m58s │ 409µs │ 0 │ 0 B │ 0 B │
│ │ │ │ │ 172.22.0.31:6222 │ rid:13 │ 1h28m58s │ 254µs │ 0 │ 0 B │ 0 B │
│ │ │ │ │ 172.22.0.31:6222 │ rid:15 │ 1h28m58s │ 543µs │ 0 │ 0 B │ 0 B │
│ │ │ │ ACMJJEA4TT...UZ5PIJR6QR │ 172.22.0.31:6222 │ rid:11 │ 1h28m58s │ 190µs │ 65 │ 4.6 MiB │ 1.6 MiB │
│ │ │ nats-s2-3 │ │ 172.22.0.32:6222 │ rid:14 │ 1h28m58s │ 502µs │ 0 │ 0 B │ 0 B │
│ │ │ │ │ 172.22.0.32:6222 │ rid:8 │ 1h28m58s │ 158µs │ 0 │ 0 B │ 0 B │
│ │ │ │ │ 172.22.0.32:6222 │ rid:16 │ 1h28m58s │ 151µs │ 0 │ 0 B │ 0 B │
│ │ │ │ ACMJJEA4TT...UZ5PIJR6QR │ 172.22.0.32:6222 │ rid:9 │ 1h28m58s │ 194µs │ 66 │ 2.8 MiB │ 1.6 MiB │
│ nats-s2-2 │ c2_blu │ nats-s2-1 │ │ 172.22.0.30:38494 │ rid:12 │ 1h28m58s │ 226µs │ 0 │ 0 B │ 0 B │
│ │ │ │ │ 172.22.0.30:38524 │ rid:16 │ 1h28m58s │ 228µs │ 0 │ 0 B │ 0 B │
│ │ │ │ │ 172.22.0.30:38526 │ rid:18 │ 1h28m58s │ 255µs │ 0 │ 0 B │ 0 B │
│ │ │ │ ACMJJEA4TT...UZ5PIJR6QR │ 172.22.0.30:38508 │ rid:13 │ 1h28m58s │ 181µs │ 76 │ 1.6 MiB │ 4.6 MiB │
│ │ │ nats-s2-3 │ │ 172.22.0.32:6222 │ rid:9 │ 1h28m59s │ 236µs │ 0 │ 0 B │ 0 B │
│ │ │ │ │ 172.22.0.32:6222 │ rid:14 │ 1h28m58s │ 235µs │ 0 │ 0 B │ 0 B │
│ │ │ │ │ 172.22.0.32:38162 │ rid:10 │ 1h28m59s │ 420µs │ 0 │ 0 B │ 0 B │
│ │ │ │ ACMJJEA4TT...UZ5PIJR6QR │ 172.22.0.32:6222 │ rid:8 │ 1h28m59s │ 685µs │ 66 │ 2.6 MiB │ 4.2 MiB │
│ nats-s2-3 │ c2_blu │ nats-s2-1 │ │ 172.22.0.30:36868 │ rid:12 │ 1h28m58s │ 174µs │ 0 │ 0 B │ 0 B │
│ │ │ │ │ 172.22.0.30:36886 │ rid:15 │ 1h28m58s │ 486µs │ 0 │ 0 B │ 0 B │
│ │ │ │ │ 172.22.0.30:36900 │ rid:17 │ 1h28m58s │ 381µs │ 0 │ 0 B │ 0 B │
│ │ │ │ ACMJJEA4TT...UZ5PIJR6QR │ 172.22.0.30:36874 │ rid:13 │ 1h28m58s │ 210µs │ 76 │ 1.6 MiB │ 2.8 MiB │
│ │ │ nats-s2-2 │ │ 172.22.0.31:33248 │ rid:14 │ 1h28m58s │ 258µs │ 0 │ 0 B │ 0 B │
│ │ │ │ │ 172.22.0.31:6222 │ rid:10 │ 1h28m59s │ 253µs │ 0 │ 0 B │ 0 B │
│ │ │ │ │ 172.22.0.31:33226 │ rid:9 │ 1h28m59s │ 599µs │ 0 │ 0 B │ 0 B │
│ │ │ │ ACMJJEA4TT...UZ5PIJR6QR │ 172.22.0.31:33240 │ rid:8 │ 1h28m59s │ 225µs │ 65 │ 4.3 MiB │ 2.6 MiB │
├───────────┼─────────┼───────────┼─────────────────────────┼───────────────────┼────────┼──────────┼───────┼──────┼──────────┼───────────┤
│ 6 │ 2 │ │ │ 48 │ │ │ │ 944 │ 36 MiB │ 36 MiB │
╰───────────┴─────────┴───────────┴─────────────────────────┴───────────────────┴────────┴──────────┴───────┴──────┴──────────┴───────────╯
Gateways
╭──────────────────────────────────────────────────────────────────────────────────────────────────────────────────╮
│ Super Cluster Report │
├───────────┬────────┬──────┬──────────┬──────────────────────────┬────────┬──────────┬───────┬─────────┬──────────┤
│ Server │ Name │ Port │ Kind │ Connection │ ID │ Uptime │ RTT │ Bytes │ Accounts │
├───────────┼────────┼──────┼──────────┼──────────────────────────┼────────┼──────────┼───────┼─────────┼──────────┤
│ nats-s1-1 │ c1_red │ 7222 │ │ │ │ │ │ │ │
│ │ │ │ Inbound │ c2_blu 172.22.0.30:36202 │ gid:18 │ 1h28m54s │ 216µs │ 1.7 MiB │ 4 │
│ │ │ │ Outbound │ c2_blu 172.22.0.31:7222 │ gid:23 │ 1h28m53s │ 660µs │ 1.5 MiB │ 3 │
│ nats-s1-2 │ c1_red │ 7222 │ │ │ │ │ │ │ │
│ │ │ │ Outbound │ c2_blu 172.22.0.31:7222 │ gid:18 │ 1h28m54s │ 163µs │ 1.7 MiB │ 3 │
│ nats-s1-3 │ c1_red │ 7222 │ │ │ │ │ │ │ │
│ │ │ │ Inbound │ c2_blu 172.22.0.32:34068 │ gid:18 │ 1h28m54s │ 172µs │ 1.2 MiB │ 4 │
│ │ │ │ │ c2_blu 172.22.0.31:46288 │ gid:19 │ 1h28m54s │ 142µs │ 1.4 MiB │ 4 │
│ │ │ │ Outbound │ c2_blu 172.22.0.32:7222 │ gid:22 │ 1h28m54s │ 586µs │ 1.6 MiB │ 3 │
│ nats-s2-1 │ c2_blu │ 7222 │ │ │ │ │ │ │ │
│ │ │ │ Outbound │ c1_red 172.22.0.10:7222 │ gid:21 │ 1h28m54s │ 287µs │ 1.7 MiB │ 4 │
│ nats-s2-2 │ c2_blu │ 7222 │ │ │ │ │ │ │ │
│ │ │ │ Inbound │ c1_red 172.22.0.11:52530 │ gid:22 │ 1h28m54s │ 431µs │ 1.7 MiB │ 3 │
│ │ │ │ │ c1_red 172.22.0.10:39888 │ gid:24 │ 1h28m53s │ 534µs │ 1.5 MiB │ 3 │
│ │ │ │ Outbound │ c1_red 172.22.0.12:7222 │ gid:21 │ 1h28m54s │ 314µs │ 1.4 MiB │ 4 │
│ nats-s2-3 │ c2_blu │ 7222 │ │ │ │ │ │ │ │
│ │ │ │ Inbound │ c1_red 172.22.0.12:41524 │ gid:22 │ 1h28m54s │ 543µs │ 1.6 MiB │ 3 │
│ │ │ │ Outbound │ c1_red 172.22.0.12:7222 │ gid:20 │ 1h28m54s │ 176µs │ 1.2 MiB │ 4 │
├───────────┼────────┼──────┼──────────┼──────────────────────────┼────────┼──────────┼───────┼─────────┼──────────┤
│ 6 │ 2 │ │ │ 12 │ │ │ │ 18 MiB │ │
╰───────────┴────────┴──────┴──────────┴──────────────────────────┴────────┴──────────┴───────┴─────────┴──────────╯
Leaf
╭───────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────╮
│ Leafnode Report │
├───────────┬────────────────┬─────────────────────────┬───────────────────┬───────────┬─────────┬──────────┬──────────┬───────────┬──────┬─────────────────┬───────┤
│ Server │ Name │ Account │ Address │ RTT │ Msgs In │ Msgs Out │ Bytes In │ Bytes Out │ Subs │ Compressed │ Spoke │
├───────────┼────────────────┼─────────────────────────┼───────────────────┼───────────┼─────────┼──────────┼──────────┼───────────┼──────┼─────────────────┼───────┤
│ nats-s1-2 │ nats-leaf-s1-1 │ AB7D63GOTO...2VWS6C6DM6 │ 172.22.0.50:46582 │ 1.53154ms │ 1 │ 4,952 │ 578 B │ 364 KiB │ 15 │ s2_uncompressed │ false │
╰───────────┴────────────────┴─────────────────────────┴───────────────────┴───────────┴─────────┴──────────┴──────────┴───────────┴──────┴─────────────────┴───────╯
JWT Authentication (Operator
Mode)
NATS uses Operator Mode for secure, scalable authentication. Accounts
and users are defined as JWTs (JSON Web Tokens) managed by nsc. This
replaces the older inline authentication method.
Ansible Role for JWT
Management
The nats_jwt Ansible role automates the creation and management of: -
Operator (IFRI) – the root of trust. - Accounts – teams with JetStream
limits (e.g., TEAM_ABB, TEAM_INFRA). - Users – applications with
subject‑based permissions. - Credentials (.creds files) – the secure
identity for connecting to NATS.
Directory structure
config
├── IFRI.jwt
├── jwt-mem-resolver.conf
└── jwt-nats-resolver.conf
nsc-store
└── IFRI
├── accounts
│ ├── SYS
│ │ ├── SYS.jwt
│ │ └── users
│ │ └── sys.jwt
│ ├── TEAM_ABB
│ │ ├── TEAM_ABB.jwt
│ │ └── users
│ │ ├── tabb_app11.jwt
│ │ └── tabb_app12.jwt
│ ├── TEAM_CDD
│ │ ├── TEAM_CDD.jwt
│ │ └── users
│ │ ├── tcdd_app21.jwt
│ │ └── tcdd_app22.jwt
│ └── TEAM_INFRA
│ ├── TEAM_INFRA.jwt
│ └── users
│ ├── tinfra_leaf.jwt
│ └── tinfra_test.jwt
└── IFRI.jwt
nkeys/creds
└── IFRI
├── SYS
│ └── sys.creds
├── TEAM_ABB
│ ├── tabb_app11.creds
│ └── tabb_app12.creds
├── TEAM_CDD
│ ├── tcdd_app21.creds
│ └── tcdd_app22.creds
└── TEAM_INFRA
├── tinfra_leaf.creds
└── tinfra_test.creds
OpenTofu Provisioning
The NATS JetStream provider allows infrastructure‑as‑code management
of streams and consumers.
provider "jetstream" {
alias = "s1"
servers = "tls://lb-s1.ifri.akl:4222"
credentials = "${path.module}/../creds/tinfra_test.creds"
tls {
ca_file = "${path.module}/../certs/ca/ca.crt"
}
}
provider "jetstream" {
alias = "s2"
servers = "tls://lb-s2.ifri.akl:4222"
credentials = "${path.module}/../creds/tinfra_test.creds"
tls {
ca_file = "${path.module}/../certs/ca/ca.crt"
}
}
provider "jetstream" {
alias = "leaf"
servers = "tls://nats-leaf-s1-1.ifri.akl:4222"
credentials = "${path.module}/../creds/tinfra_test.creds"
tls {
ca_file = "${path.module}/../certs/ca/ca.crt"
}
}