Files
infra-librechat/k8s
2026-05-09 06:42:45 +00:00
..
2026-05-09 06:42:45 +00:00
2026-05-09 06:42:45 +00:00
2026-05-09 06:42:45 +00:00
2026-05-09 06:42:45 +00:00
2026-05-09 06:42:45 +00:00
2026-05-09 06:42:45 +00:00
2026-05-09 06:42:45 +00:00
2026-05-09 06:42:45 +00:00
2026-05-09 06:42:45 +00:00

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)
  • kubectl configured against your cluster
  • Wildcard TLS certificate for *.sttlab.pc in $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: DOMAIN must be exported before the pipe. An inline assignment (DOMAIN=x cmd1 | cmd2) does not propagate to envsubst.

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.allowedDomains is 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.