feat(librechat): install librechat

This commit is contained in:
Masaki Yatsu
2025-12-03 16:09:24 +09:00
parent 3534c31eda
commit 6d34cba4ba
8 changed files with 935 additions and 111 deletions

246
README.md
View File

@@ -62,6 +62,8 @@ A remotely accessible Kubernetes home lab with OIDC authentication. Build a mode
### LLM & AI Applications (Optional) ### LLM & AI Applications (Optional)
- **[Ollama](https://ollama.com/)**: Local LLM inference server with GPU acceleration
- **[LibreChat](https://www.librechat.ai/)**: Web-based chat interface with multi-model support and MCP integration
- **[Langfuse](https://langfuse.com/)**: LLM observability and analytics platform for tracking and debugging AI applications - **[Langfuse](https://langfuse.com/)**: LLM observability and analytics platform for tracking and debugging AI applications
### Orchestration (Optional) ### Orchestration (Optional)
@@ -116,21 +118,13 @@ Lightweight Kubernetes distribution optimized for edge computing:
- **Production Ready**: Full Kubernetes functionality with minimal overhead - **Production Ready**: Full Kubernetes functionality with minimal overhead
- **Easy Deployment**: Single binary installation with built-in ingress - **Easy Deployment**: Single binary installation with built-in ingress
### Longhorn ### PostgreSQL
Enterprise-grade distributed storage system: Production-ready relational database:
- **Highly Available**: Block storage with no single point of failure - **High Availability**: Clustered deployment with CloudNativePG
- **Backup & Recovery**: Built-in disaster recovery capabilities - **pgvector Extension**: Vector similarity search for AI/ML workloads
- **NFS Support**: Persistent volumes with NFS compatibility - **Multi-Tenant**: Shared database for Keycloak and applications
### HashiCorp Vault
Centralized secrets management:
- **Secure Storage**: Encrypted secret storage with access control
- **Dynamic Secrets**: Automatic credential generation and rotation
- **External Secrets Integration**: Syncs with Kubernetes via External Secrets Operator
### Keycloak ### Keycloak
@@ -140,13 +134,21 @@ Open-source identity and access management:
- **User Federation**: Identity brokering and external provider integration - **User Federation**: Identity brokering and external provider integration
- **Group-Based Access**: Role and permission management - **Group-Based Access**: Role and permission management
### PostgreSQL ### HashiCorp Vault
Production-ready relational database: Centralized secrets management:
- **High Availability**: Clustered deployment with CloudNativePG - **Secure Storage**: Encrypted secret storage with access control
- **pgvector Extension**: Vector similarity search for AI/ML workloads - **Dynamic Secrets**: Automatic credential generation and rotation
- **Multi-Tenant**: Shared database for Keycloak and applications - **External Secrets Integration**: Syncs with Kubernetes via External Secrets Operator
### External Secrets Operator
Kubernetes operator for secret synchronization:
- **Vault Integration**: Automatically syncs secrets from Vault to Kubernetes
- **Multiple Backends**: Supports various secret management systems
- **Secure Rotation**: Automatic secret lifecycle management
### Prometheus and Grafana ### Prometheus and Grafana
@@ -160,13 +162,27 @@ Comprehensive monitoring and observability stack:
[📖 See Prometheus Documentation](./prometheus/README.md) [📖 See Prometheus Documentation](./prometheus/README.md)
### External Secrets Operator ### Goldilocks
Kubernetes operator for secret synchronization: Resource recommendation dashboard for right-sizing workloads:
- **Vault Integration**: Automatically syncs secrets from Vault to Kubernetes - **VPA Integration**: Powered by Vertical Pod Autoscaler for metrics-based recommendations
- **Multiple Backends**: Supports various secret management systems - **Visual Dashboard**: User-friendly interface for viewing resource recommendations
- **Secure Rotation**: Automatic secret lifecycle management - **QoS Guidance**: Recommendations for Guaranteed, Burstable, and BestEffort classes
- **Monitoring-Only Mode**: Observes workloads without automatic scaling
- **Namespace-Based**: Enable monitoring per namespace with labels
[📖 See Goldilocks Documentation](./goldilocks/README.md)
[📖 See VPA Documentation](./vpa/README.md)
### Longhorn
Enterprise-grade distributed storage system:
- **Highly Available**: Block storage with no single point of failure
- **Backup & Recovery**: Built-in disaster recovery capabilities
- **NFS Support**: Persistent volumes with NFS compatibility
### MinIO ### MinIO
@@ -187,68 +203,6 @@ Multi-user platform for interactive computing:
[📖 See JupyterHub Documentation](./jupyterhub/README.md) [📖 See JupyterHub Documentation](./jupyterhub/README.md)
### MLflow
Machine learning lifecycle management platform:
- **Experiment Tracking**: Log parameters, metrics, and artifacts for ML experiments
- **Model Registry**: Version and manage ML models with deployment lifecycle
- **Keycloak Authentication**: OAuth2 integration with group-based access control
[📖 See MLflow Documentation](./mlflow/README.md)
### KServe
Model serving platform for deploying ML models on Kubernetes:
- **Multi-Framework Support**: TensorFlow, PyTorch, scikit-learn, XGBoost, MLflow, and more
- **MLflow Integration**: Deploy models directly from MLflow Model Registry
- **Inference Protocols**: REST and gRPC with v2 Open Inference Protocol
- **RawDeployment Mode**: Uses native Kubernetes Deployments without Knative dependency
[📖 See KServe Documentation](./kserve/README.md)
### Langfuse
LLM observability and analytics platform:
- **Trace Tracking**: Monitor LLM calls, chains, and agent executions with detailed traces
- **Prompt Management**: Version and test prompts with playground interface
- **Analytics**: Track costs, latency, and token usage across all LLM applications
- **Keycloak Authentication**: OAuth2 integration with automatic user provisioning
[📖 See Langfuse Documentation](./langfuse/README.md)
### Apache Superset
Modern business intelligence platform:
- **Rich Visualizations**: 40+ chart types including mixed charts, treemaps, and heatmaps
- **SQL Lab**: Powerful editor for complex queries and dataset creation
- **Keycloak & Trino**: OAuth2 authentication and Iceberg data lake integration
[📖 See Superset Documentation](./superset/README.md)
### Metabase
Lightweight business intelligence:
- **Simple Setup**: Quick configuration with clean, modern UI
- **Multiple Databases**: Connect to PostgreSQL, Trino, and more
- **Keycloak Authentication**: OAuth2 integration for user management
[📖 See Metabase Documentation](./metabase/README.md)
### Querybook
Big data querying UI with notebook interface:
- **Trino Integration**: SQL queries against multiple data sources with user impersonation
- **Notebook Interface**: Shareable datadocs with queries and visualizations
- **Real-time Execution**: WebSocket-based query progress updates
[📖 See Querybook Documentation](./querybook/README.md)
### Trino ### Trino
Fast distributed SQL query engine: Fast distributed SQL query engine:
@@ -259,15 +213,15 @@ Fast distributed SQL query engine:
[📖 See Trino Documentation](./trino/README.md) [📖 See Trino Documentation](./trino/README.md)
### DataHub ### Querybook
Modern data catalog and metadata management: Big data querying UI with notebook interface:
- **OIDC Integration**: Keycloak authentication for unified access - **Trino Integration**: SQL queries against multiple data sources with user impersonation
- **Metadata Discovery**: Search and browse data assets across platforms - **Notebook Interface**: Shareable datadocs with queries and visualizations
- **Lineage Tracking**: Visualize data flow and dependencies - **Real-time Execution**: WebSocket-based query progress updates
[📖 See DataHub Documentation](./datahub/README.md) [📖 See Querybook Documentation](./querybook/README.md)
### ClickHouse ### ClickHouse
@@ -309,15 +263,88 @@ Apache Iceberg REST Catalog:
[📖 See Lakekeeper Documentation](./lakekeeper/README.md) [📖 See Lakekeeper Documentation](./lakekeeper/README.md)
### Apache Airflow ### Apache Superset
Workflow orchestration platform: Modern business intelligence platform:
- **DAG-Based**: Define data pipelines as code with Python - **Rich Visualizations**: 40+ chart types including mixed charts, treemaps, and heatmaps
- **JupyterHub Integration**: Develop and test workflows in notebooks - **SQL Lab**: Powerful editor for complex queries and dataset creation
- **Keycloak Authentication**: OAuth2 for user management - **Keycloak & Trino**: OAuth2 authentication and Iceberg data lake integration
[📖 See Airflow Documentation](./airflow/README.md) [📖 See Superset Documentation](./superset/README.md)
### Metabase
Lightweight business intelligence:
- **Simple Setup**: Quick configuration with clean, modern UI
- **Multiple Databases**: Connect to PostgreSQL, Trino, and more
- **Keycloak Authentication**: OAuth2 integration for user management
[📖 See Metabase Documentation](./metabase/README.md)
### DataHub
Modern data catalog and metadata management:
- **OIDC Integration**: Keycloak authentication for unified access
- **Metadata Discovery**: Search and browse data assets across platforms
- **Lineage Tracking**: Visualize data flow and dependencies
[📖 See DataHub Documentation](./datahub/README.md)
### MLflow
Machine learning lifecycle management platform:
- **Experiment Tracking**: Log parameters, metrics, and artifacts for ML experiments
- **Model Registry**: Version and manage ML models with deployment lifecycle
- **Keycloak Authentication**: OAuth2 integration with group-based access control
[📖 See MLflow Documentation](./mlflow/README.md)
### KServe
Model serving platform for deploying ML models on Kubernetes:
- **Multi-Framework Support**: TensorFlow, PyTorch, scikit-learn, XGBoost, MLflow, and more
- **MLflow Integration**: Deploy models directly from MLflow Model Registry
- **Inference Protocols**: REST and gRPC with v2 Open Inference Protocol
- **RawDeployment Mode**: Uses native Kubernetes Deployments without Knative dependency
[📖 See KServe Documentation](./kserve/README.md)
### Ollama
Local LLM inference server:
- **Local Inference**: Run LLMs locally without external API dependencies
- **GPU Acceleration**: NVIDIA GPU support with automatic runtime configuration
- **Model Library**: Access to thousands of open-source models (Llama, Qwen, DeepSeek, etc.)
- **OpenAI-Compatible API**: Drop-in replacement for OpenAI API endpoints
[📖 See Ollama Documentation](./ollama/README.md)
### LibreChat
Web-based chat interface for LLMs:
- **Multi-Model Support**: Connect to Ollama, OpenAI, Anthropic, and custom endpoints
- **MCP Integration**: Model Context Protocol support for web search and tools
- **Keycloak Authentication**: OAuth2 integration for user management
[📖 See LibreChat Documentation](./librechat/README.md)
### Langfuse
LLM observability and analytics platform:
- **Trace Tracking**: Monitor LLM calls, chains, and agent executions with detailed traces
- **Prompt Management**: Version and test prompts with playground interface
- **Analytics**: Track costs, latency, and token usage across all LLM applications
- **Keycloak Authentication**: OAuth2 integration with automatic user provisioning
[📖 See Langfuse Documentation](./langfuse/README.md)
### Dagster ### Dagster
@@ -329,6 +356,16 @@ Modern data orchestration platform:
[📖 See Dagster Documentation](./dagster/README.md) [📖 See Dagster Documentation](./dagster/README.md)
### Apache Airflow
Workflow orchestration platform:
- **DAG-Based**: Define data pipelines as code with Python
- **JupyterHub Integration**: Develop and test workflows in notebooks
- **Keycloak Authentication**: OAuth2 for user management
[📖 See Airflow Documentation](./airflow/README.md)
### Fairwinds Polaris ### Fairwinds Polaris
Kubernetes configuration validation and best practices auditing: Kubernetes configuration validation and best practices auditing:
@@ -340,20 +377,6 @@ Kubernetes configuration validation and best practices auditing:
[📖 See Fairwinds Polaris Documentation](./fairwinds-polaris/README.md) [📖 See Fairwinds Polaris Documentation](./fairwinds-polaris/README.md)
### Goldilocks
Resource recommendation dashboard for right-sizing workloads:
- **VPA Integration**: Powered by Vertical Pod Autoscaler for metrics-based recommendations
- **Visual Dashboard**: User-friendly interface for viewing resource recommendations
- **QoS Guidance**: Recommendations for Guaranteed, Burstable, and BestEffort classes
- **Monitoring-Only Mode**: Observes workloads without automatic scaling
- **Namespace-Based**: Enable monitoring per namespace with labels
[📖 See Goldilocks Documentation](./goldilocks/README.md)
[📖 See VPA Documentation](./vpa/README.md)
## Common Operations ## Common Operations
### User Management ### User Management
@@ -462,6 +485,7 @@ kubectl --context yourpc-oidc get nodes
# JupyterHub: https://jupyter.yourdomain.com # JupyterHub: https://jupyter.yourdomain.com
# MLflow: https://mlflow.yourdomain.com # MLflow: https://mlflow.yourdomain.com
# Langfuse: https://langfuse.yourdomain.com # Langfuse: https://langfuse.yourdomain.com
# LibreChat: https://chat.yourdomain.com
``` ```
## Customization ## Customization

View File

@@ -22,6 +22,7 @@ mod k8s
mod kserve mod kserve
mod langfuse mod langfuse
mod lakekeeper mod lakekeeper
mod librechat
mod longhorn mod longhorn
mod metabase mod metabase
mod mlflow mod mlflow

2
librechat/.gitignore vendored Normal file
View File

@@ -0,0 +1,2 @@
values.yaml
librechat-config.yaml

227
librechat/README.md Normal file
View File

@@ -0,0 +1,227 @@
# LibreChat
Web-based chat interface for interacting with LLMs:
- **Multi-Model Support**: Connect to Ollama, OpenAI, Anthropic, and custom endpoints
- **MCP Integration**: Model Context Protocol for web search and external tools
- **Keycloak Authentication**: OAuth2/OIDC integration for user management
- **Conversation History**: MongoDB-backed chat history with search via Meilisearch
- **Persistent Storage**: User-uploaded images stored persistently
## Prerequisites
- [Keycloak](../keycloak/README.md) for OIDC authentication
- [Vault](../vault/README.md) for secrets management
- [Ollama](../ollama/README.md) for local LLM inference (optional)
## Installation
```bash
just librechat::install
```
During installation, you will be prompted for:
- **LibreChat host**: FQDN for LibreChat (e.g., `chat.example.com`)
- **Keycloak host**: FQDN for Keycloak (e.g., `auth.example.com`)
- **Tavily MCP**: Enable web search via Tavily API (requires API key)
### Environment Variables
| Variable | Default | Description |
| -------- | ------- | ----------- |
| `LIBRECHAT_NAMESPACE` | `librechat` | Kubernetes namespace |
| `LIBRECHAT_CHART_VERSION` | `1.9.3` | Helm chart version |
| `LIBRECHAT_HOST` | (prompt) | LibreChat FQDN |
| `LIBRECHAT_OIDC_CLIENT_ID` | `librechat` | Keycloak client ID |
| `KEYCLOAK_HOST` | (prompt) | Keycloak FQDN |
| `KEYCLOAK_REALM` | `buunstack` | Keycloak realm |
| `OLLAMA_HOST` | `ollama.ollama.svc.cluster.local` | Ollama service host |
| `TAVILY_MCP_ENABLED` | (prompt) | Enable Tavily MCP (`true`/`false`) |
### Example with Environment Variables
```bash
LIBRECHAT_HOST=chat.example.com \
KEYCLOAK_HOST=auth.example.com \
TAVILY_MCP_ENABLED=true \
just librechat::install
```
## Ollama Integration
LibreChat automatically connects to Ollama using the internal Kubernetes service
URL. The default models configured are:
- `qwen3:8b`
- `deepseek-r1:8b`
LibreChat fetches the available model list from Ollama, so any models you pull
will be available.
## MCP (Model Context Protocol)
LibreChat supports MCP servers for extending model capabilities with external tools.
### Tavily Web Search
When `TAVILY_MCP_ENABLED=true`, LibreChat can search the web using Tavily API:
1. Get a Tavily API key from [tavily.com](https://tavily.com/)
2. During installation, enter the API key when prompted (stored in Vault)
3. In the chat interface, select "tavily" from the MCP Servers dropdown
4. The model can now search the web to answer questions
### Adding Custom MCP Servers
Edit `librechat-config.gomplate.yaml` to add additional MCP servers:
```yaml
mcpServers:
tavily:
command: npx
args:
- "-y"
- "tavily-mcp@latest"
env:
TAVILY_API_KEY: "${TAVILY_API_KEY}"
filesystem:
command: npx
args:
- "-y"
- "@anthropic/mcp-server-filesystem"
- "/app/data"
```
## Adding API Providers
Edit `librechat-config.gomplate.yaml` to add OpenAI, Anthropic, or other providers:
```yaml
endpoints:
openAI:
apiKey: "${OPENAI_API_KEY}"
models:
default:
- gpt-4o
- gpt-4o-mini
fetch: true
anthropic:
apiKey: "${ANTHROPIC_API_KEY}"
models:
default:
- claude-sonnet-4-20250514
- claude-3-5-haiku-20241022
```
Store the API keys in Kubernetes secrets and reference them in `values.gomplate.yaml`.
## Operations
### Check Status
```bash
just librechat::status
```
### View Logs
```bash
just librechat::logs
```
### Restart
```bash
just librechat::restart
```
## Upgrade
```bash
just librechat::upgrade
```
## Uninstall
```bash
just librechat::uninstall
```
This removes the Helm release, namespace, and Keycloak client. Vault secrets
are preserved.
To delete Vault secrets:
```bash
just vault::delete librechat/credentials
```
## Architecture
LibreChat deployment includes:
- **LibreChat**: Main application (Node.js)
- **MongoDB**: Conversation and user data storage
- **Meilisearch**: Full-text search for conversations
All components run with Pod Security Standards set to `restricted`.
## Troubleshooting
### OIDC Login Fails
**Symptom**: Redirect loop or error after Keycloak login
**Check**:
1. Verify `DOMAIN_CLIENT` and `DOMAIN_SERVER` match your LibreChat URL
2. Check Keycloak client redirect URI matches `https://<host>/oauth/openid/callback`
```bash
just keycloak::get-client buunstack librechat
```
### Ollama Models Not Showing
**Symptom**: No models available in the model selector
**Check**:
1. Verify Ollama is running: `just ollama::status`
2. Check Ollama has models: `just ollama::list`
3. Check LibreChat logs for connection errors: `just librechat::logs`
### MCP Not Working
**Symptom**: MCP server not available in dropdown
**Check**:
1. Verify Tavily secret exists:
```bash
kubectl get secret tavily-api-key -n librechat
```
2. Check for MCP errors in logs:
```bash
just librechat::logs | grep -i mcp
```
3. Verify `librechat-config` ConfigMap has MCP configuration:
```bash
kubectl get configmap librechat-config -n librechat -o yaml
```
## References
- [LibreChat Website](https://www.librechat.ai/)
- [LibreChat Documentation](https://www.librechat.ai/docs)
- [LibreChat GitHub](https://github.com/danny-avila/LibreChat)
- [LibreChat Helm Chart](https://github.com/danny-avila/librechat-helm)
- [Model Context Protocol](https://modelcontextprotocol.io/)
- [Tavily API](https://tavily.com/)

309
librechat/justfile Normal file
View File

@@ -0,0 +1,309 @@
set fallback := true
export LIBRECHAT_NAMESPACE := env("LIBRECHAT_NAMESPACE", "librechat")
export LIBRECHAT_CHART_VERSION := env("LIBRECHAT_CHART_VERSION", "1.9.3")
export LIBRECHAT_HOST := env("LIBRECHAT_HOST", "")
export LIBRECHAT_OIDC_CLIENT_ID := env("LIBRECHAT_OIDC_CLIENT_ID", "librechat")
export KEYCLOAK_REALM := env("KEYCLOAK_REALM", "buunstack")
export KEYCLOAK_HOST := env("KEYCLOAK_HOST", "")
export K8S_VAULT_NAMESPACE := env("K8S_VAULT_NAMESPACE", "vault")
export EXTERNAL_SECRETS_NAMESPACE := env("EXTERNAL_SECRETS_NAMESPACE", "external-secrets")
export OLLAMA_NAMESPACE := env("OLLAMA_NAMESPACE", "ollama")
export OLLAMA_HOST := env("OLLAMA_HOST", "ollama.ollama.svc.cluster.local")
export TAVILY_MCP_ENABLED := env("TAVILY_MCP_ENABLED", "")
[private]
default:
@just --list --unsorted --list-submodules
# Create LibreChat namespace
create-namespace:
#!/bin/bash
set -euo pipefail
if ! kubectl get namespace ${LIBRECHAT_NAMESPACE} &>/dev/null; then
kubectl create namespace ${LIBRECHAT_NAMESPACE}
fi
kubectl label namespace ${LIBRECHAT_NAMESPACE} \
pod-security.kubernetes.io/enforce=restricted \
pod-security.kubernetes.io/enforce-version=latest \
pod-security.kubernetes.io/warn=restricted \
pod-security.kubernetes.io/warn-version=latest \
--overwrite
# Delete LibreChat namespace
delete-namespace:
kubectl delete namespace ${LIBRECHAT_NAMESPACE} --ignore-not-found
# Generate credentials and store in Vault
generate-credentials:
#!/bin/bash
set -euo pipefail
if just vault::exist librechat/credentials &>/dev/null; then
echo "LibreChat credentials already exist in Vault"
exit 0
fi
echo "Generating LibreChat credentials..."
CREDS_KEY=$(openssl rand -hex 32)
CREDS_IV=$(openssl rand -hex 16)
JWT_SECRET=$(openssl rand -hex 32)
JWT_REFRESH_SECRET=$(openssl rand -hex 32)
MEILI_MASTER_KEY=$(openssl rand -hex 32)
OPENID_SESSION_SECRET=$(openssl rand -hex 32)
just vault::put librechat/credentials \
creds_key="${CREDS_KEY}" \
creds_iv="${CREDS_IV}" \
jwt_secret="${JWT_SECRET}" \
jwt_refresh_secret="${JWT_REFRESH_SECRET}" \
meili_master_key="${MEILI_MASTER_KEY}" \
openid_session_secret="${OPENID_SESSION_SECRET}"
echo "Credentials stored in Vault"
# Create Keycloak client for LibreChat
create-keycloak-client:
#!/bin/bash
set -euo pipefail
while [ -z "${LIBRECHAT_HOST}" ]; do
LIBRECHAT_HOST=$(
gum input --prompt="LibreChat host (FQDN): " --width=100 \
--placeholder="e.g., chat.example.com"
)
done
echo "Creating Keycloak client for LibreChat..."
just keycloak::delete-client ${KEYCLOAK_REALM} ${LIBRECHAT_OIDC_CLIENT_ID} || true
CLIENT_SECRET=$(just utils::random-password)
just keycloak::create-client \
realm=${KEYCLOAK_REALM} \
client_id=${LIBRECHAT_OIDC_CLIENT_ID} \
redirect_url="https://${LIBRECHAT_HOST}/oauth/openid/callback" \
client_secret="${CLIENT_SECRET}"
just vault::put keycloak/client/librechat \
client_id="${LIBRECHAT_OIDC_CLIENT_ID}" \
client_secret="${CLIENT_SECRET}"
echo "Keycloak client created successfully"
echo "Client ID: ${LIBRECHAT_OIDC_CLIENT_ID}"
echo "Redirect URI: https://${LIBRECHAT_HOST}/oauth/openid/callback"
# Delete Keycloak client
delete-keycloak-client:
#!/bin/bash
set -euo pipefail
echo "Deleting Keycloak client for LibreChat..."
just keycloak::delete-client ${KEYCLOAK_REALM} ${LIBRECHAT_OIDC_CLIENT_ID} || true
if just vault::exist keycloak/client/librechat &>/dev/null; then
just vault::delete keycloak/client/librechat
fi
# Create Kubernetes secrets
create-secrets:
#!/bin/bash
set -euo pipefail
just create-namespace
CREDS_KEY=$(just vault::get librechat/credentials creds_key)
CREDS_IV=$(just vault::get librechat/credentials creds_iv)
JWT_SECRET=$(just vault::get librechat/credentials jwt_secret)
JWT_REFRESH_SECRET=$(just vault::get librechat/credentials jwt_refresh_secret)
MEILI_MASTER_KEY=$(just vault::get librechat/credentials meili_master_key)
OPENID_SESSION_SECRET=$(just vault::get librechat/credentials openid_session_secret)
OPENID_CLIENT_ID=$(just vault::get keycloak/client/librechat client_id)
OPENID_CLIENT_SECRET=$(just vault::get keycloak/client/librechat client_secret)
kubectl delete secret librechat-credentials-env -n ${LIBRECHAT_NAMESPACE} --ignore-not-found
kubectl create secret generic librechat-credentials-env -n ${LIBRECHAT_NAMESPACE} \
--from-literal=CREDS_KEY="${CREDS_KEY}" \
--from-literal=CREDS_IV="${CREDS_IV}" \
--from-literal=JWT_SECRET="${JWT_SECRET}" \
--from-literal=JWT_REFRESH_SECRET="${JWT_REFRESH_SECRET}" \
--from-literal=MEILI_MASTER_KEY="${MEILI_MASTER_KEY}" \
--from-literal=OPENID_SESSION_SECRET="${OPENID_SESSION_SECRET}" \
--from-literal=OPENID_CLIENT_ID="${OPENID_CLIENT_ID}" \
--from-literal=OPENID_CLIENT_SECRET="${OPENID_CLIENT_SECRET}"
echo "Secrets created successfully"
# Install LibreChat
install:
#!/bin/bash
set -euo pipefail
while [ -z "${LIBRECHAT_HOST}" ]; do
LIBRECHAT_HOST=$(
gum input --prompt="LibreChat host (FQDN): " --width=100 \
--placeholder="e.g., chat.example.com"
)
done
while [ -z "${KEYCLOAK_HOST}" ]; do
KEYCLOAK_HOST=$(
gum input --prompt="Keycloak host (FQDN): " --width=100 \
--placeholder="e.g., auth.example.com"
)
done
# Ask about Tavily MCP if not set
if [ -z "${TAVILY_MCP_ENABLED}" ]; then
if gum confirm "Enable Tavily MCP for web search?"; then
TAVILY_MCP_ENABLED="true"
else
TAVILY_MCP_ENABLED="false"
fi
fi
# Check External Secrets Operator if Tavily is enabled
if [ "${TAVILY_MCP_ENABLED}" = "true" ]; then
if ! helm status external-secrets -n ${EXTERNAL_SECRETS_NAMESPACE} &>/dev/null; then
echo "Error: Tavily MCP requires External Secrets Operator, but it is not installed."
echo "Please install External Secrets Operator first or set TAVILY_MCP_ENABLED=false"
exit 1
fi
# Check if Tavily API key exists in Vault
if ! just vault::exist tavily/api &>/dev/null; then
echo "Tavily API key not found in Vault."
TAVILY_API_KEY=$(
gum input --prompt="Enter Tavily API Key: " --width=100 \
--placeholder="tvly-xxxxxxxxxxxxxxxx"
)
just vault::put tavily/api api_key="${TAVILY_API_KEY}"
echo "Tavily API key stored in Vault"
fi
fi
just create-namespace
just generate-credentials
just create-keycloak-client
just create-secrets
# Create Tavily ExternalSecret if enabled
if [ "${TAVILY_MCP_ENABLED}" = "true" ]; then
gomplate -f tavily-external-secret.gomplate.yaml | kubectl apply -f -
echo "Waiting for Tavily secret to be synced..."
kubectl wait --for=condition=Ready externalsecret/tavily-api-key \
-n ${LIBRECHAT_NAMESPACE} --timeout=60s
fi
gomplate -f values.gomplate.yaml -o values.yaml
gomplate -f librechat-config.gomplate.yaml -o librechat-config.yaml
kubectl delete configmap librechat-config -n ${LIBRECHAT_NAMESPACE} --ignore-not-found
kubectl create configmap librechat-config -n ${LIBRECHAT_NAMESPACE} \
--from-file=librechat.yaml=librechat-config.yaml
helm upgrade --install librechat oci://ghcr.io/danny-avila/librechat-chart/librechat \
--version ${LIBRECHAT_CHART_VERSION} \
-n ${LIBRECHAT_NAMESPACE} \
--wait --timeout=10m \
-f values.yaml
echo ""
echo "LibreChat installed successfully"
echo "URL: https://${LIBRECHAT_HOST}"
echo "Login with Keycloak OIDC"
if [ "${TAVILY_MCP_ENABLED}" = "true" ]; then
echo "Tavily MCP: Enabled"
fi
# Upgrade LibreChat
upgrade:
#!/bin/bash
set -euo pipefail
while [ -z "${LIBRECHAT_HOST}" ]; do
LIBRECHAT_HOST=$(
gum input --prompt="LibreChat host (FQDN): " --width=100 \
--placeholder="e.g., chat.example.com"
)
done
while [ -z "${KEYCLOAK_HOST}" ]; do
KEYCLOAK_HOST=$(
gum input --prompt="Keycloak host (FQDN): " --width=100 \
--placeholder="e.g., auth.example.com"
)
done
# Ask about Tavily MCP if not set
if [ -z "${TAVILY_MCP_ENABLED}" ]; then
if gum confirm "Enable Tavily MCP for web search?"; then
TAVILY_MCP_ENABLED="true"
else
TAVILY_MCP_ENABLED="false"
fi
fi
# Check External Secrets Operator if Tavily is enabled
if [ "${TAVILY_MCP_ENABLED}" = "true" ]; then
if ! helm status external-secrets -n ${EXTERNAL_SECRETS_NAMESPACE} &>/dev/null; then
echo "Error: Tavily MCP requires External Secrets Operator, but it is not installed."
echo "Please install External Secrets Operator first or set TAVILY_MCP_ENABLED=false"
exit 1
fi
# Check if Tavily API key exists in Vault
if ! just vault::exist tavily/api &>/dev/null; then
echo "Tavily API key not found in Vault."
TAVILY_API_KEY=$(
gum input --prompt="Enter Tavily API Key: " --width=100 \
--placeholder="tvly-xxxxxxxxxxxxxxxx"
)
just vault::put tavily/api api_key="${TAVILY_API_KEY}"
echo "Tavily API key stored in Vault"
fi
# Create/update Tavily ExternalSecret
gomplate -f tavily-external-secret.gomplate.yaml | kubectl apply -f -
echo "Waiting for Tavily secret to be synced..."
kubectl wait --for=condition=Ready externalsecret/tavily-api-key \
-n ${LIBRECHAT_NAMESPACE} --timeout=60s
fi
gomplate -f values.gomplate.yaml -o values.yaml
gomplate -f librechat-config.gomplate.yaml -o librechat-config.yaml
kubectl delete configmap librechat-config -n ${LIBRECHAT_NAMESPACE} --ignore-not-found
kubectl create configmap librechat-config -n ${LIBRECHAT_NAMESPACE} \
--from-file=librechat.yaml=librechat-config.yaml
helm upgrade librechat oci://ghcr.io/danny-avila/librechat-chart/librechat \
--version ${LIBRECHAT_CHART_VERSION} \
-n ${LIBRECHAT_NAMESPACE} \
--wait --timeout=10m \
-f values.yaml
echo "LibreChat upgraded successfully"
if [ "${TAVILY_MCP_ENABLED}" = "true" ]; then
echo "Tavily MCP: Enabled"
fi
# Uninstall LibreChat
uninstall:
#!/bin/bash
set -euo pipefail
helm uninstall librechat -n ${LIBRECHAT_NAMESPACE} --wait --ignore-not-found
just delete-namespace
just delete-keycloak-client || true
echo "LibreChat uninstalled successfully"
echo ""
echo "Note: Vault secrets were NOT deleted:"
echo " - librechat/credentials"
echo ""
echo "To delete, run:"
echo " just vault::delete librechat/credentials"
# Show LibreChat logs
logs:
kubectl logs -n ${LIBRECHAT_NAMESPACE} -l app.kubernetes.io/name=librechat -f
# Get pod status
status:
kubectl get pods -n ${LIBRECHAT_NAMESPACE}
# Restart LibreChat
restart:
kubectl rollout restart deployment/librechat-librechat -n ${LIBRECHAT_NAMESPACE}

View File

@@ -0,0 +1,89 @@
version: 1.2.1
cache: true
interface:
endpointsMenu: true
modelSelect: true
parameters: true
sidePanel: true
presets: true
registration:
socialLogins:
- openid
endpoints:
# Ollama - Local LLM (configured as custom endpoint)
# Note: Name must NOT start with "ollama" to avoid legacy code issues
custom:
- name: "LocalLLM"
apiKey: "ollama"
baseURL: "http://{{ .Env.OLLAMA_HOST }}:11434/v1/"
models:
default:
- "qwen3:8b"
- "deepseek-r1:8b"
fetch: true
titleConvo: true
titleModel: "current_model"
summarize: false
summaryModel: "current_model"
forcePrompt: false
modelDisplayLabel: "LocalLLM"
# OpenAI - Optional, requires API key
# openAI:
# apiKey: "${OPENAI_API_KEY}"
# models:
# default:
# - gpt-4o
# - gpt-4o-mini
# fetch: true
# Anthropic - Optional, requires API key
# anthropic:
# apiKey: "${ANTHROPIC_API_KEY}"
# models:
# default:
# - claude-sonnet-4-20250514
# - claude-3-5-haiku-20241022
# Additional custom endpoints example (OpenRouter, etc.)
# - name: "OpenRouter"
# apiKey: "${OPENROUTER_KEY}"
# baseURL: "https://openrouter.ai/api/v1"
# models:
# default:
# - "anthropic/claude-sonnet-4"
# fetch: true
# titleConvo: true
# modelDisplayLabel: "OpenRouter"
# MCP Servers configuration
{{- if eq .Env.TAVILY_MCP_ENABLED "true" }}
mcpServers:
tavily:
command: npx
args:
- "-y"
- "tavily-mcp@latest"
env:
TAVILY_API_KEY: "${TAVILY_API_KEY}"
{{- end }}
# Additional MCP Servers (examples)
# mcpServers:
# filesystem:
# command: npx
# args:
# - "-y"
# - "@anthropic/mcp-server-filesystem"
# - "/app/data"
# brave-search:
# command: npx
# args:
# - "-y"
# - "@anthropic/mcp-server-brave-search"
# env:
# BRAVE_API_KEY: "${BRAVE_API_KEY}"

View File

@@ -0,0 +1,22 @@
apiVersion: external-secrets.io/v1
kind: ExternalSecret
metadata:
name: tavily-api-key
namespace: {{ .Env.LIBRECHAT_NAMESPACE }}
spec:
refreshInterval: 1h
secretStoreRef:
name: vault-secret-store
kind: ClusterSecretStore
target:
name: tavily-api-key
creationPolicy: Owner
template:
type: Opaque
data:
TAVILY_API_KEY: "{{ `{{ .api_key }}` }}"
data:
- secretKey: api_key
remoteRef:
key: tavily/api
property: api_key

View File

@@ -0,0 +1,150 @@
replicaCount: 1
global:
librechat:
existingSecretName: "librechat-credentials-env"
existingSecretApiKey: OPENAI_API_KEY
{{- if eq .Env.TAVILY_MCP_ENABLED "true" }}
env:
- name: TAVILY_API_KEY
valueFrom:
secretKeyRef:
name: tavily-api-key
key: TAVILY_API_KEY
{{- end }}
librechat:
configEnv:
# Domain configuration (required for OIDC redirects)
DOMAIN_CLIENT: "https://{{ .Env.LIBRECHAT_HOST }}"
DOMAIN_SERVER: "https://{{ .Env.LIBRECHAT_HOST }}"
# Ollama endpoint (internal k8s service)
OLLAMA_BASE_URL: "http://{{ .Env.OLLAMA_HOST }}:11434"
# OpenID Connect / Keycloak
ALLOW_SOCIAL_LOGIN: "true"
OPENID_BUTTON_LABEL: "Login with Keycloak"
OPENID_ISSUER: "https://{{ .Env.KEYCLOAK_HOST }}/realms/{{ .Env.KEYCLOAK_REALM }}"
OPENID_CALLBACK_URL: "/oauth/openid/callback"
OPENID_SCOPE: "openid profile email"
# Optional: Role-based access control
# OPENID_REQUIRED_ROLE_PARAMETER_PATH: "realm_access.roles"
# OPENID_REQUIRED_ROLE_TOKEN_KIND: "access"
# Optional: Group sync from Keycloak roles
# OPENID_SYNC_GROUPS_FROM_TOKEN: "true"
# OPENID_GROUPS_CLAIM_PATH: "realm_access.roles"
# OPENID_GROUPS_TOKEN_KIND: "access"
# Disable email registration (use Keycloak only)
ALLOW_EMAIL_LOGIN: "false"
ALLOW_REGISTRATION: "false"
ALLOW_SOCIAL_REGISTRATION: "true"
# Debug (set to true for troubleshooting)
DEBUG_OPENID_REQUESTS: "false"
DEBUG_PLUGINS: "false"
existingSecretName: "librechat-credentials-env"
# Use external configmap for librechat.yaml
existingConfigYaml: "librechat-config"
imageVolume:
enabled: true
size: 10Gi
accessModes: ReadWriteOnce
image:
repository: danny-avila/librechat
registry: ghcr.io
pullPolicy: IfNotPresent
podSecurityContext:
fsGroup: 2000
securityContext:
capabilities:
drop:
- ALL
runAsNonRoot: true
runAsUser: 1000
allowPrivilegeEscalation: false
seccompProfile:
type: RuntimeDefault
service:
type: ClusterIP
port: 3080
ingress:
enabled: true
className: "traefik"
annotations:
traefik.ingress.kubernetes.io/router.entrypoints: websecure
traefik.ingress.kubernetes.io/router.tls: "true"
hosts:
- host: {{ .Env.LIBRECHAT_HOST }}
paths:
- path: /
pathType: Prefix
tls: []
resources:
requests:
cpu: 100m
memory: 512Mi
limits:
cpu: 1000m
memory: 1Gi
mongodb:
enabled: true
auth:
enabled: false
databases:
- LibreChat
image:
tag: "latest"
persistence:
size: 8Gi
podSecurityContext:
fsGroup: 1001
seccompProfile:
type: RuntimeDefault
containerSecurityContext:
runAsUser: 1001
runAsNonRoot: true
allowPrivilegeEscalation: false
seccompProfile:
type: RuntimeDefault
capabilities:
drop:
- ALL
meilisearch:
enabled: true
persistence:
enabled: true
image:
tag: "v1.7.3"
auth:
existingMasterKeySecret: "librechat-credentials-env"
podSecurityContext:
fsGroup: 1000
seccompProfile:
type: RuntimeDefault
containerSecurityContext:
runAsUser: 1000
runAsNonRoot: true
allowPrivilegeEscalation: false
seccompProfile:
type: RuntimeDefault
capabilities:
drop:
- ALL
librechat-rag-api:
enabled: false