Deploy MemDBEnterprise
Operator guide for self-hosted MemDB: Docker, Docker Compose, Helm on Kubernetes, Azure and Google Cloud, plus how engineers connect local memtrace clients.
MemDB is the shared graph database behind Memtrace on the Teams plan. You run one MemDB cluster per org on infrastructure you control. Every engineer's local memtrace connects as a pure gRPC client — graph data, embeddings, and episode history live on your cluster, not on laptops. This page is the operator guide; engineer onboarding is Self-hosted MemDB (connect).
Overview#
MemDB is stateful with a local data directory and HNSW index. Azure VMSS autoscale, Kubernetes HPA, and elastic node pools will split or corrupt state. Scale vertically (more RAM, faster disk) or run a fixed 3-node raft cluster — never an elastic replica pool.
Choose a deployment path#
| Path | Best for | HA |
|---|---|---|
| Docker on one Linux VM | Azure VM, GCP Compute Engine, on-prem — no Kubernetes team. Start here. | Crash recovery via WAL; disk loss → restore from backup |
| Kubernetes + Helm | AKS, GKE, EKS — production with PVC snapshots and ingress TLS | Optional 3-replica raft (fixed replica count) |
| Docker Compose HA | Three containers on one host — process failover only | 3-node raft; not separate machines |
Your provisioning bundle's cluster/INSTALL.md is rendered with your org's database name, vector dimensions, and image tag — follow that file first when it disagrees with generic examples here.
Provisioning bundle#
Teams customers receive a tarball with two halves. The cluster/ half is for platform engineers (secrets). The engineer/ half is distributed to developers.
bundle/ ├── cluster/ # platform team — treat as secrets │ ├── imagePullSecret.yaml # ghcr.io pull credential (image + OCI Helm chart) │ ├── tokens.store # server token store (BLAKE3 hashes, no plaintext) │ ├── enrollment.secret # organization assertion verification secret │ ├── owner-connect.json # bootstrap admin bearer — owner only │ ├── values.enterprise.yaml # pre-rendered Helm values for your org │ └── INSTALL.md # org-specific install steps └── engineer/ └── connect.json # endpoint/license metadata — no admin bearer
tokens.store is the read-only bootstrap source. enrollment.secret lets MemDB verify short-lived organization assertions issued after member login. The owner's bootstrap bearer remains in cluster/owner-connect.json for recovery. Do not distribute the cluster half to engineers.
Prerequisites#
All paths require:
- Registry access to
ghcr.io/syncable-dev/memcore(private image) viacluster/imagePullSecret.yaml cluster/tokens.storeandcluster/enrollment.secret— auth is oncluster/owner-connect.jsonkept in your secret manager until the owner workstation is connected- Outbound HTTPS to
memtrace.iofrom engineer machines for online license validation (offline licenses available — see memtrace connect) - Immutable vector dimensions: default
768(jina-embeddings-v2-base-code). Set--vector-dims=768on first boot; changing later requires a fresh empty data volume.
Docker on a VM (Azure, GCP, on-prem)#
Recommended first deploy when you do not run Kubernetes. Works on an Azure VM, a GCP Compute Engine instance, or any Linux host with Docker Engine 24+.
Pull the image
# Extract GHCR credentials from cluster/imagePullSecret.yaml, then: docker pull ghcr.io/syncable-dev/memcore:<version-from-your-bundle>
Run single-node MemDB
docker volume create memcore-data docker run -d --name memcore \ --restart unless-stopped \ -p 2424:2424 -p 2480:2480 \ -v memcore-data:/var/lib/memcore \ -v "$(pwd)/cluster/tokens.store:/etc/memcore/tokens/tokens.store:ro" \ -v "$(pwd)/cluster/enrollment.secret:/etc/memcore/tokens/enrollment.secret:ro" \ ghcr.io/syncable-dev/memcore:<version> \ --bind 0.0.0.0:2424 \ --rest-bind 0.0.0.0:2480 \ --data-dir /var/lib/memcore \ --default-db=<your-database-from-bundle> \ --vector-dims=768 \ --require-auth \ --auth-token-store /etc/memcore/tokens/tokens.store \ --auth-enrollment-secret-file /etc/memcore/tokens/enrollment.secret \ --auth-enrollment-org <organization-id-from-bundle>
Ports: 2424 gRPC (authenticated), 2480 REST /health and /ready (no auth). Restrict gRPC to your VPN or engineer subnet — avoid exposing it on the public internet without TLS.
The memcore-data volume also persists the live user registry at /var/lib/memcore/auth/managed_tokens.toml. Keep tokens.store mounted read-only; adding, rotating, or revoking a user does not modify that mount or restart the container.
Stop the container before copying the data directory — live copies of LSM + WAL can be inconsistent. Pattern: docker stop memcore → tar the volume → docker start memcore.
Docker Compose#
The single-node Compose file ships in the MemDB repository under deploy/. Copy both auth files next to it before up; missing files fail fast.
Single node
cp <bundle>/cluster/tokens.store deploy/tokens.store cp <bundle>/cluster/enrollment.secret deploy/enrollment.secret MEMCORE_IMAGE=ghcr.io/syncable-dev/memcore:<version> \ MEMCORE_ENROLLMENT_ORG=<organization-id-from-bundle> \ docker compose -f deploy/docker-compose.single.yml up -d # Health from the host (distroless image — no in-container curl): curl -fsS http://localhost:2480/health curl -fsS http://localhost:2480/ready
Three-node raft (one host)
cp <bundle>/cluster/tokens.store deploy/tokens.store MEMCORE_IMAGE=ghcr.io/syncable-dev/memcore:<version> \ docker compose -f deploy/docker-compose.ha.yml \ -f deploy/docker-compose.ha.publish-all.yml up -d # Engineers use ordered failover — writes must reach the leader: export MEMTRACE_MEMDB_ENDPOINTS=http://<host>:2424,http://<host>:2425,http://<host>:2426
Compose HA adds replication on a single machine — you get leader failover between containers, not separate fault domains. Organization enrollment is currently a single-replica feature because managed bearer state is local; keep static bootstrap credentials coordinated for raft deployments.
Kubernetes + Helm#
The canonical chart lives at memcore-rs/helm/memcore in the MemDB repo and publishes as oci://ghcr.io/syncable-dev/charts/memcore. Your bundle's values.enterprise.yaml pins image, auth, and pull secrets.
kubectl create namespace memcore kubectl -n memcore apply -f cluster/imagePullSecret.yaml kubectl -n memcore create secret generic memcore-auth \ --from-file=tokens.store=cluster/tokens.store \ --from-file=enrollment.secret=cluster/enrollment.secret helm registry login ghcr.io --username <user> --password <token> helm install memcore oci://ghcr.io/syncable-dev/charts/memcore \ --version <chart-version-from-bundle> \ --namespace memcore \ -f cluster/values.enterprise.yaml \ --set auth.existingSecret=memcore-auth
For HA with raft consensus (fixed 3 or 5 replicas, not autoscaling):
helm upgrade --install memcore oci://ghcr.io/syncable-dev/charts/memcore \ --namespace memcore \ -f cluster/values.enterprise.yaml \ --set replicas=3 \ --set memcore.replication=raft \ --set networkPolicy.enabled=true \ --set auth.existingSecret=memcore-auth
In-cluster gRPC endpoint: http://memcore:2424 (Service name follows the Helm release). Engineers outside the cluster need an ingress, VPN, or port-forward — see TLS below.
In the default single-replica deployment, the managed user registry lives on the pod's MemDB PVC and survives rescheduling or upgrades. The memcore-auth Secret remains the bootstrap credential only; normal user changes do not require a Secret update or StatefulSet rollout.
Managed token mutations are not yet raft-replicated. Use memtrace access with Docker/single-node or a single-replica Helm deployment. For a multi-replica raft cluster, keep the static bootstrap store coordinated across replicas until replicated token state is available.
Azure quick reference#
| Item | Recommendation |
|---|---|
VM SKU | Standard_D4s_v5 (4 vCPU / 16 GiB) or larger for production pilot |
Data disk | Separate Premium SSD managed disk (≥ 100 GiB), not OS disk only |
NSG | Allow 2424/tcp from engineer VPN/subnet only; avoid public gRPC |
Monitoring | 2480/tcp for /health and /ready from your monitor subnet |
Egress | HTTPS to memtrace.io for license validation |
Autoscale | Off — scale vertically or use fixed 3-node raft on AKS |
Path A on Azure: provision a Linux VM, attach a Premium SSD data disk, install Docker, run the single-node command above. Set engineer/connect.json endpoint to http://<vm-private-ip>:2424 or your internal DNS name.
Path B on AKS: create a dedicated node pool (no cluster autoscaler on the MemDB pool), install via Helm as above, expose gRPC through an internal load balancer or gRPC-capable ingress.
Google Cloud quick reference#
| Item | Recommendation |
|---|---|
Compute Engine | e2-standard-4 (4 vCPU / 16 GiB) or larger; pd-ssd data disk ≥ 100 GiB |
Firewall | Allow tcp:2424 from engineer VPC/subnet only; tcp:2480 for health checks |
GKE | Standard cluster, dedicated node pool, Helm Path B — no HPA on MemDB StatefulSet |
Egress | HTTPS to memtrace.io from engineer workstations |
Path A on GCP: same Docker flow as Azure — one Compute Engine VM with Docker Engine, persistent disk for /var/lib/memcore, NSG-equivalent firewall rules.
Path B on GKE: identical Helm steps to AKS/EKS. Use a regional persistent disk StorageClass for PVCs; snapshot backups via GCE volume snapshots or your CSI driver.
Verify the cluster#
# REST probes (no auth): curl -fsS http://<host>:2480/health curl -fsS http://127.0.0.1:2480/ready # via kubectl port-forward on K8s # Auth enforcement (grpcurl + memcore.proto — server has no reflection): # Must REJECT without token: grpcurl -plaintext -proto memcore.proto \ <host>:2424 memcore.v1.Memcore/Ping # Must SUCCEED with writer token: grpcurl -plaintext -proto memcore.proto \ -H "authorization: Bearer ${MEMCORE_TOKEN}" \ <host>:2424 memcore.v1.Memcore/Ping
On Kubernetes: kubectl -n memcore rollout status statefulset/memcore and confirm pods are 2/2 Ready when Studio sidecar is enabled (off by default in current chart).
Connect local memtrace instances#
After MemDB is up, pin its endpoint in the organization enterprise settings and add members on memtrace.io/account. Each member then enrolls with their own signed-in identity:
Organization member onboarding
memtrace auth login memtrace connect <organization-slug> memtrace connect --status # verify endpoint + token + probe memtrace start # external mode — no env vars needed
connect verifies the active organization member, exchanges a signed assertion with this MemDB, writes secretless .memtrace/team.toml, and stores the expiring bearer in the member's own credentials.json. No administrator copies or distributes user tokens. Full walkthrough: Self-hosted MemDB and memtrace access.
Environment-variable fallback (CI / scripts)
| Variable | Default | Description |
|---|---|---|
MEMTRACE_MEMDB_MODE | — | Set to external (aliases hosted, remote). Also inferred when the endpoint is non-loopback. |
MEMTRACE_MEMDB_ENDPOINT | — | Remote gRPC URL, e.g. http://memdb.corp.example:2424 or ingress https:// when TLS is configured. |
MEMTRACE_MEMDB_ENDPOINTS | — | Comma-separated failover list for compose HA or multi-port publish — replaces singular MEMTRACE_MEMDB_ENDPOINT. |
MEMTRACE_MEMDB_DB | — | Database name from your bundle (not always memtrace). |
MEMTRACE_MEMDB_AUTH_TOKEN | — | Writer bearer token — attached to every RPC. |
MEMTRACE_MEMDB_TLS_CA | — | Path to private CA for https:// endpoints with ingress or native TLS. |
In external mode the machine runs only the watcher, indexer, and MCP tools as gRPC clients — no local memcore-server sidecar. memtrace reset clears local lock/cache only; it cannot wipe the shared cluster.
TLS, sizing, and operations#
TLS (ingress): enable chart ingress with a gRPC-capable controller (nginx by default) and cert-manager. Only the gRPC port is routed; REST probes stay cluster-internal. Set ingress.enabled=true, ingress.host=memdb.example.com, networkPolicy.enabled=true.
Sizing (planning guidance):
| Tier | Indexed code | RAM | Disk |
|---|---|---|---|
| S — pilot | ≤ ~0.5 MLOC | 4–8 GB | 50 Gi |
| M — typical org | ~0.5–3 MLOC | 16 GB | 100 Gi |
| L — large monorepo | 3–10+ MLOC | 64 GB | 250–500 Gi |
Day-two ops: add or remove normal users through organization membership. Removed users cannot renew and their local bearer expires within 24 hours. Use memtrace access revoke for urgent immediate removal and memtrace access add for offline/service accounts. Reserve memcore-auth Secret changes for bootstrap rotation. Upgrade MemDB with a fresh backup first. Prometheus metrics are on :9090/metrics (no auth). Detailed runbooks ship in the MemDB repo under docs/ops/.
Troubleshooting#
| Symptom | Likely cause | Fix |
|---|---|---|
helm install fails: auth.existingSecret required | Auth-on is mandatory | Create memcore-auth Secret from tokens.store and enrollment.secret (§ Helm) |
ImagePullBackOff | Private registry | Apply imagePullSecret in the release namespace; match values.enterprise.yaml |
Every RPC UNAUTHENTICATED | Missing, expired, or wrong organization credential | Run memtrace auth login, then memtrace connect <organization-slug> |
Engineer cannot connect | Network / TLS / token | VPN, firewall on 2424, http vs https, memtrace connect --status |
Vector dimension error on first index | Client embed model mismatch | Align MEMTRACE_EMBED_MODEL / 768 dims across all clients |
Next: engineer onboarding, user access management, memtrace connect flags, and Teams plan quotas.