Getting started
Install JACO on three Linux hosts, form a cluster, and ship a deployment. End-to-end in one page.
Prerequisites
- Three Linux hosts with Docker Engine ≥ 24.0, reachable on a private network (LAN, VPC, Tailscale, or any other overlay).
- Each host needs
CAP_NET_ADMINplus a kernel with WireGuard andnftinstalled. The.deb/.rpmpackages depend on a Docker package that satisfies the engine requirement. - TCP
7000(cluster gRPC) and7001(raft) reachable between nodes; UDP51820for the WireGuard mesh. TCP80and443reachable from whichever clients hit your ingress.
The cross-host gRPC control plane (:7000) runs over TLS with the
cluster CA — the CLI and peer nodes pin it — and the operator bearer
token authenticates the caller on top. The raft transport (:7001)
is still plaintext TCP, so run it over a private network or overlay you
control. See Networking and the README
"Network model" section.
1. Install on every host
Pick the snippet for your distro from Installation. The Debian path looks like:
curl -fsSL -O https://github.com/PatrickRuddiman/JACO/releases/latest/download/jaco_amd64.deb
sudo dpkg -i jaco_amd64.deb
sudo systemctl enable --now jacoAfter install the daemon is uninitialized — every RPC except
Cluster.{Init,Join,Status} returns cluster_uninitialized until one of
the next two steps runs. Confirm with jaco cluster status on each node.
2. Initialize the first node
On node 1:
sudo jaco cluster init
# Cluster initialized.
# cluster_id: <uuid>
# operator_token: <64 hex chars>
#
# Save the operator token now — it cannot be recovered.Save the operator token in your password manager. It is the only
credential that authorizes state-changing RPCs against this cluster
until you issue more via jaco token issue.
3. Join the other nodes
On node 1, mint a single-use 24-hour join token:
export JACO_TOKEN=<operator_token>
jaco node issue-join-token
# Join token issued. On the joining node, run:
#
# sudo jaco node join --peer=<node-1-host:port> --token=<single-use>
#
# Token expires in 24h (single-use).On each follower:
sudo jaco node join --peer <node-1-host>:7000 --token <single-use>
# Joined cluster.Confirm everyone is in:
export LEADER=<node-1-host>:7000
jaco node list --server $LEADERWait for every node to show READY. The cross-host gRPC port comes from
/etc/jaco/jacod.yaml::listen_addr and defaults to 7000. See
Configuration.
4. Ship a deployment
You need two files in a directory: jaco.yaml and a docker-compose.yml.
JACO consumes the compose file unmodified; the jaco.yaml overlay declares
replica counts, placement, and ingress routes.
./hello/jaco.yaml:
deployment: hello
services:
- name: web
replicas: 3
routes:
- domain: hello.example.com
service: web
port: 80
tls: auto./hello/docker-compose.yml:
services:
web:
image: nginx:1.27
healthcheck:
test: ["CMD", "curl", "-fsS", "http://127.0.0.1/"]
interval: 5s
timeout: 3s
retries: 5Apply from any node (the CLI dials the leader for you):
jaco apply --server $LEADER ./hello/jaco.yaml
# Applied revision: 1JACO pulls the image on each scheduled host, starts containers, attaches
them to the per-(deployment, network) bridge, registers the route with
the embedded Caddy, and queues ACME issuance for hello.example.com.
5. Watch the rollout
jaco status --server $LEADER hello -wThe -w flag re-renders on every state change. You'll see three replicas
move through pending → pulling → running, and a Routes row land for
hello.example.com. Cert state shows up under Certs once ACME succeeds
(DNS for the domain must resolve to your nodes for that to happen).
Stream logs from all replicas across every node:
jaco logs --server $LEADER hello/web --follow6. Roll an update
Edit ./hello/docker-compose.yml, bump image: to nginx:1.28, and
re-apply:
jaco apply --server $LEADER ./hello/jaco.yamlThe scheduler replaces replicas one at a time, never dropping below
replicas - 1 running. jaco status hello -w shows the rollout state.
If something looks wrong, roll back to the previous revision:
jaco rollback --server $LEADER helloWhat to read next
- CLI reference — every subcommand, every flag.
jaco.yamlschema and supported compose fields — what's actually accepted.- Architecture — the moving parts and the current status.
- Troubleshooting — the error codes you will hit and how to clear them.