Minimal ChromaDB on Docker, exposed to the internet only through a Cloudflare Tunnel (cloudflared). There is no reverse proxy, no published host port for Chroma: the database listens on http://chromadb:8000 inside a private Docker bridge network, and traffic enters only after Cloudflare terminates HTTPS on your public hostname.
flowchart LR
Internet -->|"HTTPS (public hostname)"| CF[Cloudflare Edge]
CF -->|"Tunnel (QUIC/H2)"| cloudflared
subgraph backend ["Docker network: backend"]
cloudflared -->|"http://chromadb:8000"| chromadb
chromadb -->|"/data"| SSD[(SSD: CHROMA_DATA_DIR)]
end
Host -.->|"no direct access"| chromadb
chromadb-cloudflared/
βββ compose.yml # chromadb + cloudflared services
βββ Makefile # -include .env for Make; Compose still needs a project .env file
βββ make/
β βββ variables.mk # defaults (CHROMA_DATA_DIR, colors, PROJECT_NAME)
β βββ docker.mk # start, stop, logs, create-data-dir, etc.
β βββ help.mk # printable help
βββ AGENTS.md # contributor / agent conventions
βββ .env.template # placeholder env (copy to .env)
βββ README.md
chromadb
- Image:
chromadb/chroma:1.5.4(pinned; validate before upgrading). - Listens on port
8000inside thebackendnetwork only (noports:on the host). - Persists data via bind mount: host
${CHROMA_DATA_DIR}β container/data. - Healthcheck:
GET http://localhost:8000/api/v2/heartbeatinside the container. - Hardening:
security_opt: no-new-privileges,tmpfson/tmp, log rotation (10mΓ 3 files).
cloudflared
- Runs
tunnel runwithTUNNEL_TOKENfrom your environment. - Joins the same
backendnetwork and reaches Chroma athttp://chromadb:8000. - Starts only after
chromadbis healthy (depends_onwithcondition: service_healthy). - Sets
TUNNEL_MANAGEMENT_DIAGNOSTICS=false(see cloudflared CHANGES).
- Docker and the Docker Compose v2 plugin (
docker compose, not the legacydocker-composev1 CLI). - A Cloudflare Tunnel and its token (Zero Trust β Networks β Tunnels).
- A host directory for Chroma data (absolute path), created before first
docker compose up.
-
Environment
You need a project
.envfile beforemake startordocker compose up. Docker Compose reads.envin this directory for${CHROMA_DATA_DIR}and${TUNNEL_TOKEN}; it does not use Makeβs defaults frommake/variables.mk.cp .env.template .env
Edit
.envand set:CHROMA_DATA_DIRβ absolute path on the host (for example/srv/chroma-dataon a Pi or server).TUNNEL_TOKENβ your tunnel token (never commit this file).
make create-data-dir
create-data-dirusesCHROMA_DATA_DIRfrom.envwhen the file exists; if you run Make without.env,make/variables.mkfalls back to$HOME/chroma-datafor Make targets onlyβthat path is not applied to Compose until it appears in.env. You can still runmkdir -pyourself if you prefer. -
Cloudflare dashboard
For the tunnelβs public hostname, set the service URL to
http://chromadb:8000(Docker service name and internal port). Do not point the tunnel atlocalhostor a host LAN address unless you deliberately change the architecture; in this stack, onlycloudflaredtalks to Chroma on the Docker network. Because Chroma has no built-in API auth, add Cloudflare Access (or similar) on that hostname if the API must not be public. -
Run
make docker-check make start
Follow logs with
make logs. Default Make target ishelp.
| Command | Description |
|---|---|
help |
Show available commands (default target). |
docker-check |
Verify Docker and docker compose are installed. |
create-data-dir |
Create CHROMA_DATA_DIR on the host (mkdir -p; reads .env when present). |
start |
Start ChromaDB and cloudflared (docker compose up -d). |
stop |
Stop all compose services. |
restart |
Recreate the stack (down then up -d). |
logs |
Follow container logs. |
clean |
Stop services and remove compose-managed volumes and orphans. |
| Service | Inside Docker | Published on host |
|---|---|---|
chromadb |
8000 (HTTP API) |
None |
cloudflared |
(outbound tunnel) | None |
Clients on the internet reach Chroma only through your Cloudflare hostname (HTTPS at the edge). The host machine has no direct LAN/WAN port open to the Chroma API.
Only these variables are used (see AGENTS.md for the full contract):
| Variable | Required | Description |
|---|---|---|
CHROMA_DATA_DIR |
Yes | Absolute host path for persistence; mounted as /data in the Chroma container. Must exist before startup. |
TUNNEL_TOKEN |
Yes | Cloudflare Tunnel token for cloudflared. |
Do not add extra variables to compose without updating .env.template and AGENTS.md.