# LibreChat — Kubernetes Deployment Deploys [LibreChat](https://www.librechat.ai/) 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: ```bash 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:@mongodb:27017/LibreChat?authSource=admin ``` ### 2. Create the TLS secret ```bash 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 ```bash 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 ```bash 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: ```yaml 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 ```bash export DOMAIN=librechat.sttlab.pc kubectl kustomize k8s/ | envsubst '${DOMAIN}' | kubectl apply -f - ``` Force a pod restart: ```bash kubectl rollout restart deployment/librechat -n librechat ``` ## Teardown ```bash kubectl delete namespace librechat ``` > This also deletes all PVCs and their data. Back up MongoDB first if needed.