Prometheus, Loki and Tempo become tools the assistant can call, so the telemetry can be questioned rather than browsed — which is where the trace dashboard kept running out of road. Verified: LibreChat initialises the server in 168ms and loads its tool list. No oauth block, unlike every other server here. The others sit behind a Kong gateway enforcing openid-connect; this one is reached directly on the cluster network and authenticates to Grafana with a service account token of its own. LibreChat passes no user identity along, so there is no per-user scoping: every LibreChat user gets the same full read of all telemetry, including the Kong audit records and the LLM prompts now captured there. That is stated in the config rather than left to be discovered, and it is the reason to move this server behind a gateway like the others. allowedDomains gains the first http:// and first cluster-internal entry; without it LibreChat's SSRF protection refuses the address. Co-Authored-By: Claude Opus 5 <noreply@anthropic.com>
LibreChat — Kubernetes Deployment
Deploys LibreChat on Kubernetes with MongoDB, MeiliSearch, and the JIRA MCP server.
Architecture
Namespace: librechat
│
├── Ingress nginx (librechat.sttlab.pc — TLS wildcard *.sttlab.pc)
│ └── librechat :3080
│ ├── mongodb :27017 (StatefulSet, 5 Gi PVC)
│ └── meilisearch :7700 (Deployment, 2 Gi PVC)
│
└── MCP JIRA (namespace: mcp)
└── mcp-jira :9000 (streamable-http, 49 tools)
| Component | Image | Storage |
|---|---|---|
| LibreChat | ghcr.io/danny-avila/librechat:latest |
— (stateless) |
| MongoDB | mongo:7 |
5 Gi PVC |
| MeiliSearch | getmeili/meilisearch:v1.7 |
2 Gi PVC |
Directory structure
k8s/
├── namespace.yaml Namespace definition
├── secret.yaml Credentials (gitignored — never commit real values)
├── configmap.yaml Application environment config
├── kustomization.yaml Kustomize entry point
├── mongodb/
│ ├── pvc.yaml
│ ├── statefulset.yaml
│ └── service.yaml
├── meilisearch/
│ ├── pvc.yaml
│ ├── deployment.yaml
│ └── service.yaml
├── librechat/
│ ├── configmap-app.yaml Mounts librechat.yaml (MCP config, allowedDomains...)
│ ├── deployment.yaml
│ └── service.yaml
└── ingress/
├── ingress.yaml
└── tls.yaml TLS secret (gitignored — never commit)
Prerequisites
- Kubernetes cluster with an Nginx ingress controller
- A default StorageClass (for PVCs)
kubectlconfigured against your cluster- Wildcard TLS certificate for
*.sttlab.pcin$HOME/tls/
Initial deployment
1. Fill in secrets
Edit secret.yaml with real values. Generate them with:
openssl rand -base64 24 # MONGO_PASSWORD
openssl rand -base64 32 # MEILI_MASTER_KEY, JWT_SECRET, JWT_REFRESH_SECRET
openssl rand -hex 32 # CREDS_KEY
openssl rand -hex 8 # CREDS_IV
Important: MONGO_URI must include ?authSource=admin because MONGO_INITDB_ROOT_USERNAME creates the user in the admin database:
mongodb://librechat:<password>@mongodb:27017/LibreChat?authSource=admin
2. Create the TLS secret
kubectl apply -f k8s/namespace.yaml
kubectl create secret tls sttlab-tls \
--cert=$HOME/tls/sttlab.pc.crt \
--key=$HOME/tls/sttlab.pc.key \
--namespace=librechat \
--dry-run=client -o yaml > k8s/ingress/tls.yaml
kubectl apply -f k8s/ingress/tls.yaml
3. Deploy
export DOMAIN=librechat.sttlab.pc
kubectl kustomize k8s/ | envsubst '${DOMAIN}' | kubectl apply -f -
Note:
DOMAINmust be exported before the pipe. An inline assignment (DOMAIN=x cmd1 | cmd2) does not propagate toenvsubst.
4. Verify
kubectl get pods,ingress -n librechat
curl -sk https://librechat.sttlab.pc/health
MCP JIRA
The JIRA MCP server runs in the mcp namespace (mcp-jira:9000, streamable-http transport).
librechat/configmap-app.yaml mounts /app/librechat.yaml into the container:
mcpSettings:
allowedDomains:
- "http://mcp-jira.mcp.svc.cluster.local:9000"
mcpServers:
jira:
type: streamable-http
url: http://mcp-jira.mcp.svc.cluster.local:9000/mcp
mcpSettings.allowedDomainsis required to allow internal k8s domains, which are blocked by default as SSRF protection.
Updating
export DOMAIN=librechat.sttlab.pc
kubectl kustomize k8s/ | envsubst '${DOMAIN}' | kubectl apply -f -
Force a pod restart:
kubectl rollout restart deployment/librechat -n librechat
Teardown
kubectl delete namespace librechat
This also deletes all PVCs and their data. Back up MongoDB first if needed.