Install AGLedger on Kubernetes
This guide brings up a single AGLedger Server on a generic Kubernetes cluster using the published Helm chart, fronted by TLS, backed by your own PostgreSQL. Every command below is a literal transcript captured against a live Server.
Validated against API v0.25.4 on 2026-05-25 (Kubernetes 1.35, Helm 3.20, cosign 3.0).
The API reference is the OpenAPI document the Server serves at /openapi.json. This guide
does not restate request or response schemas; it links to them.
What you provide
A Server is durable only as far as its database and its signing key. You bring both:
- A PostgreSQL database. AGLedger writes a hash-chained, Ed25519-signed record chain to it.
Use any PostgreSQL you can reach over a direct connection (pg-boss needs
LISTEN/NOTIFY, so no transaction-mode pooler). This guide runs one inside the cluster; production should use a managed or HA PostgreSQL. - An Ed25519 vault signing key. The Server signs every record with it. Generate it once, store it like any other root secret, and reuse it across upgrades — the published verification key is derived from it.
Prerequisites
- A Kubernetes cluster (1.27+) and
kubectlpointed at it helm3.x andcosign3.0+- An ingress controller and a way to issue TLS certificates. This guide uses ingress-nginx and cert-manager; any controller and certificate source work.
- A default
StorageClass(only if you run PostgreSQL in-cluster with a PersistentVolumeClaim)
1. Verify the release
The image and chart are signed with cosign. Verify both against the published key before you
install. Get cosign.pub from the install repository
(use a tagged release).
$ cosign verify --key cosign.pub --insecure-ignore-tlog=true agledger/agledger:0.25.4
$ cosign verify --key cosign.pub --insecure-ignore-tlog=true registry-1.docker.io/agledger/agledger-chart:0.25.4
Expected — each prints Verification for ... -- and a JSON block. --insecure-ignore-tlog=true
is expected on every command: signatures are not published to a public transparency log, so
verification is fully offline against cosign.pub. The image digest in the output
(sha256:489d5d21…) is the digest you pin in step 3.
2. Generate the vault signing key
Generate the Ed25519 key with the Server image itself, then keep the private key safe.
$ kubectl run agledger-keygen --restart=Never --image=agledger/agledger:0.25.4 \
--command -- /nodejs/bin/node dist/scripts/generate-signing-key.js
$ kubectl logs agledger-keygen
VAULT_SIGNING_KEY=<base64 Ed25519 private key>
Public key: MCowBQYDK2VwAyEAPInxjno26azIT9i6GVqJag9QuCJFMoDG96iljTd8fHo=
Fingerprint: dcd0573755f045c6
$ kubectl delete pod agledger-keygen
The fingerprint (dcd0573755f045c6) is the key id the Server later publishes at
/v1/verification-keys. Confirming they match (step 5) is how you prove the Server is signing
with the key you provided.
3. Bring up PostgreSQL and install
Create the namespace and a PostgreSQL the Server can reach. Then install the chart, pointing
database.externalUrl at it and passing the signing key.
$ kubectl create namespace agledger
$ kubectl apply -f postgres.yaml # your PostgreSQL Deployment + Service
$ kubectl rollout status deploy/agledger-postgres -n agledger --timeout=120s
deployment "agledger-postgres" successfully rolled out
values.yaml:
image:
digest: "sha256:489d5d215303d7920b6421f143dd6020674cbac5beef5b5326b9835dd2fa0f0b" # 0.25.4
database:
# sslmode is required under nodeEnv=production. Use sslmode=require (or verify-full) against a
# TLS-enabled database and set config.nodeExtraCaCerts to its CA. sslmode=disable only suits a
# local, non-TLS PostgreSQL like the in-cluster one here.
externalUrl: "postgresql://agledger:<db-password>@agledger-postgres.agledger.svc.cluster.local:5432/agledger?sslmode=disable"
config:
externalUrl: "https://agledger.k8s.example" # the Server's signed issuer identity; use your host
ingress:
enabled: true
className: nginx
annotations:
cert-manager.io/cluster-issuer: agledger-selfsigned
hosts:
- host: agledger.k8s.example
paths: [{ path: /, pathType: Prefix }]
tls:
- secretName: agledger-tls
hosts: [agledger.k8s.example]
$ helm install agledger oci://registry-1.docker.io/agledger/agledger-chart \
--version 0.25.4 --namespace agledger \
--values values.yaml --set secrets.vaultSigningKey=<vault-key>
NAME: agledger
STATUS: deployed
REVISION: 1
The chart runs schema migrations as a pre-install hook, then starts the API and worker.
$ kubectl rollout status deploy/agledger-agledger-chart-api -n agledger --timeout=180s
deployment "agledger-agledger-chart-api" successfully rolled out
$ kubectl rollout status deploy/agledger-agledger-chart-worker -n agledger --timeout=120s
deployment "agledger-agledger-chart-worker" successfully rolled out
4. Create the platform API key
The platform key is the first credential; you use it to provision organizations and agents. It is printed once.
$ kubectl exec deploy/agledger-agledger-chart-api -n agledger -- \
/nodejs/bin/node dist/scripts/init.js --non-interactive
✓ API_KEY_SECRET found in environment
✓ VAULT_SIGNING_KEY found in environment
✓ Platform API key created (ID: ...)
✓ Database query OK
│ Platform Key: agl_plt_<store-this-securely>
5. The readiness gate: up and signing
A Server is ready when it is healthy and signing with your key.
$ kubectl port-forward svc/agledger-agledger-chart -n agledger 3001:80 &
$ curl -s http://localhost:3001/health
{"status":"ok","version":"0.25.4","timestamp":"..."}
$ curl -s http://localhost:3001/health/ready
{"status":"ready","version":"0.25.4","timestamp":"..."}
Confirm the active signing key is the one you generated in step 2 — same fingerprint:
$ curl -s http://localhost:3001/v1/verification-keys
{
"data": [{ "keyId": "dcd0573755f045c6", "algorithm": "Ed25519",
"publicKey": "MCowBQYDK2VwAyEAPInxjno26azIT9i6GVqJag9QuCJFMoDG96iljTd8fHo=",
"status": "active" }],
"envelope": "COSE_Sign1", "signatureAlgorithm": "Ed25519"
}
keyId matches the keygen fingerprint: the Server is signing with your key, COSE_Sign1 / Ed25519.
With no license applied the Server runs as Developer Edition (all features enabled):
$ curl -s -H "Authorization: Bearer <platform-key>" http://localhost:3001/v1/admin/license
{"validity":"unlicensed","tier":"developer","source":"none","features":["custom_schemas","delegation_chains","federation", ...],"checkedAt":"..."}
6. TLS
With ingress-nginx and cert-manager, the chart's Ingress requests a certificate and serves it. A self-signed ClusterIssuer is portable and needs no public DNS; for production use an ACME (Let's Encrypt) or your-CA issuer.
$ kubectl get certificate -n agledger
NAME READY SECRET AGE
agledger-tls True agledger-tls ...
$ curl -sk https://agledger.k8s.example/health # through the ingress
{"status":"ok","version":"0.25.4","timestamp":"..."}
External database
The in-cluster PostgreSQL above is the simplest start. To use a managed PostgreSQL, point
database.externalUrl at it with sslmode=require and set config.nodeExtraCaCerts to its CA
bundle. External-database licensing is per database instance. For Amazon Aurora / RDS specifically,
see the AWS install guide.
Run more than one Server
You can run more than one Server and link them so chains reference records across Servers (we call linking Servers federation). Each Server is a full, independent install of this guide with its own database and signing key; linking is configured after both are healthy.
Air-gapped install
Nothing in install or runtime depends on agledger.ai, Docker Hub, or npm at runtime. For a
restricted network, mirror the image (agledger/agledger:0.25.4) and chart
(agledger/agledger-chart:0.25.4) into your internal registry, copy cosign.pub for offline
verification, and set image.repository (and image.pullSecrets) to your registry. The Server
makes no outbound calls except the webhook and federation endpoints you configure.
Uninstall
$ helm uninstall agledger -n agledger
release "agledger" uninstalled
This leaves your database and signing key intact, so a reinstall against the same database and key resumes the same chain.
Next
Keep the Server healthy over time with Day-2 Operations, and set up a backup and recovery routine.