This episode covers ChromaDB deployment and networking: running the server in Docker containers and Kubernetes with Helm, securing the communication path with TLS and a reverse proxy, load balancing, and network isolation with firewalls and security groups.

The ChromaDB server is now secure by default — patched, authenticated, and isolated. Episode 15 takes you to the next step: deploying the server properly onto real infrastructure. We will cover Docker containers, Kubernetes with Helm, TLS and reverse proxies, load balancing, and network isolation.
After this episode, you will not only be able to run ChromaDB — you will be able to deploy it as a service worthy of a production team.
ChromaDB provides an official image. Running the Rust server in a container with a persistent volume:
docker run -d --name chroma \
-p 8000:8000 \
-v chroma-data:/chroma/chroma \
-e CHROMA_SERVER_HOST=0.0.0.0 \
-e CHROMA_SERVER_AUTHN_PROVIDER=chromadb.auth.token_authn.TokenAuthenticationServerProvider \
-e CHROMA_SERVER_AUTHN_CREDENTIALS_FILE=/chroma/creds.txt \
ghcr.io/chroma-core/chromaThe command docker run -d --name chroma ... ghcr.io/chroma-core/chroma maps port 8000, mounts the chroma-data volume so data survives, and enables token auth. The persistent volume is key — without it, data is lost every time the container restarts.
For team development, docker-compose.yml is far more convenient:
services:
chroma:
image: ghcr.io/chroma-core/chroma:1.5.9
ports:
- "8000:8000"
volumes:
- chroma-data:/chroma/chroma
volumes:
chroma-data:Pinning the image to a specific tag ghcr.io/chroma-core/chroma:1.5.9 — not latest — preserves reproducibility and avoids unexpected upgrades that change behavior.
Info
Always pin the image tag to a specific version in production. The latest tag can change at any time and produce different behavior between pulls. A pinned version also makes rollbacks easier.
For full orchestration, use the ChromaDB Helm chart. Add the repo and install:
helm repo add chroma https://chroma-core.github.io/chroma
helm install chroma chroma/chroma \
--namespace chroma \
--create-namespacehelm install chroma chroma/chroma creates the Deployment, Service, and PersistentVolumeClaim automatically. This chart handles replicas, storage, and resource requests pre-tuned for production.
All settings from episodes 12-13 can be managed through a values file:
persistence:
size: 50Gi
auth:
token:
enabled: true
token: "rahasia-kuat-2026"
service:
type: ClusterIPThe values.yaml above configures 50Gi of storage, enables token auth, and hides the Service inside the cluster (ClusterIP). The Service can only be reached from within the cluster — your RAG application connects to it.
The ChromaDB server itself does not have to handle TLS — let the reverse proxy do it. Example Nginx configuration:
server {
listen 443 ssl;
server_name chroma.example.com;
ssl_certificate /etc/ssl/chroma.crt;
ssl_certificate_key /etc/ssl/chroma.key;
location / {
proxy_pass http://127.0.0.1:8000;
proxy_set_header Authorization $http_authorization;
}
}location / { proxy_pass http://127.0.0.1:8000; ... } forwards HTTPS to the ChromaDB server on the internal network. The proxy_set_header Authorization block ensures client tokens are forwarded — losing this header makes every request rejected by auth.
Without TLS, the token auth from episode 13 is sent in plaintext — anyone sniffing the network could steal it. The correct combination: TLS in front (reverse proxy), auth inside (ChromaDB). They are not replacements for each other, but different layers.
ChromaDB can run with several replicas behind a load balancer. In Kubernetes, simply change the replica count:
helm upgrade chroma chroma/chroma \
--set replicaCount=2helm upgrade chroma chroma/chroma --set replicaCount=2 raises the replica count. The Kubernetes load balancer distributes load across replicas — combine with episode 17 for a complete scaling strategy.
In the cloud, network isolation starts with the security group. Recommended rules for a ChromaDB server:
inbound: 8000 dari <CIDR host aplikasi> (TCP)
inbound: 8000 dari <CIDR load balancer> (TCP)
outbound: semuaThere is no public CIDR in inbound — only the application host and load balancer may connect. This is the most concrete example of the network isolation from episode 14. Periodically verify with an external scanner that port 8000 is not exposed to the internet.
Episode 15 brought ChromaDB to production infrastructure: Docker containers with persistent volumes and version pinning, Kubernetes via Helm with values customization, TLS and a reverse proxy as an HTTPS gateway that preserves the auth header, load balancing for read scale, and network isolation with firewalls and security groups.
Key takeaways:
latest.In the next episode, episode 16, we will discuss privacy and data handling — the embedding inversion risk that can reconstruct documents from vectors, data-at-rest encryption, PII handling, retention policies, and data access audit logs. Technical security is strong; now it is time to secure the data and regulatory side.