3.8 KiB
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.