This repository contains the infrastructure and deployment configuration for running LibreChat on Hetzner Cloud. The setup uses Terraform to provision a K3s Kubernetes cluster on Hetzner Cloud servers and GitHub Actions for Continuous Deployment.
graph TD
User[User] -->|HTTPS| Master[K3s Master Node]
Master -->|Traffic| Worker[K3s Worker Node]
subgraph Hetzner Cloud
Master
Worker
Network[Private Network]
end
CI[GitHub Actions] -->|Terraform| Hetzner[Hetzner API]
CI -->|Helm| Master
- Terraform: Provisions the VMs (
hcloud_server) and Network (hcloud_network). - K3s: Lightweight Kubernetes distribution installed via Cloud-Init.
- Helm: Manages the application deployment.
This repository aggregates several key components as Git submodules:
-
LibreChat (
LibreChat/)
The core open-source chat application. We track the official repository to stay updated with the latest features and fixes. -
LibreChat-MCP (
LibreChat-MCP/)
A custom Model Context Protocol (MCP) server designed for managing LibreChat. It provides tools for agent management, user-specific file storage, and RAG-powered semantic search. -
zotero-mcp (
zotero-mcp/)
An MCP server that integrates Zotero reference management into LibreChat, allowing agents to access and cite research papers. -
librechat-docs (
docs/librechat-docs/)
The official LibreChat documentation source, kept here for easy reference and offline access.
- GitHub Repository: You must have this repository cloned or forked.
- Hetzner Cloud Account: Create an account and generate an API token.
- Terraform Cloud Account: Create an organization and workspace for remote state management.
If you do not have an SSH key pair:
ssh-keygen -t ed25519 -C "TheMaryAnne-ssh-key" -f TheMaryAnne-ssh-key -N ""- Add
TheMaryAnne-ssh-keytext content as GitHub secret with keySSH_PRIVATE_KEY. - Add
TheMaryAnne-ssh-key.pubtext content as GitHub secret with keySSH_PUBLIC_KEY.
Add the following secrets to your GitHub repository (Settings → Secrets and variables → Actions):
HETZNER_API_TOKEN: Your Hetzner Cloud API token.TF_API_TOKEN: Your Terraform Cloud user API token (for CLI authentication).TF_WORKSPACE_ID: The workspace ID from Terraform Cloud (e.g.,ws-xxxxxx).SSH_PRIVATE_KEY: The private SSH key for server access.SSH_PUBLIC_KEY: The public SSH key to register in Hetzner Cloud.LIBRECHAT_ENV: The contents of your.envfile for LibreChat (optional, for secret management).HOST: The domain name for LibreChat ingress (e.g.,chat.example.com). This will automatically get an SSL certificate via Let's Encrypt.CERT_MANAGER_EMAIL: Email address for Let's Encrypt certificate registration and renewal notifications.
- The
.envfile must not contain the&symbol in any value. This will break secret creation and deployment in Kubernetes and CI/CD workflows. - Only use valid
KEY=VALUEpairs. Avoid shell operators and special characters that may be interpreted by the shell.
- In Terraform Cloud, create a workspace and choose "Version Control workflow".
- Connect your GitHub repository to the workspace using the Terraform Cloud UI.
- Terraform Cloud will automatically manage state and runs for you—no backend block is needed in your Terraform code.
- Add any required Terraform variables in the workspace UI (e.g.,
hcloud_token,ssh_public_key). - Copy the workspace ID and add it to the
TF_WORKSPACE_IDsecret if your workflow requires it.
The deployment is fully automated via GitHub Actions. The workflow (.github/workflows/deploy.yml) consists of the following steps:
- Checkout: Retrieves the code.
- Terraform Apply: Provisions the K3s cluster on Hetzner.
- Get Kubeconfig: Retrieves the
k3s.yamlconfig from the master node via SSH. - Deploy Configs: Creates Kubernetes ConfigMaps and Secrets from local files.
- Helm Upgrade: Deploys the application.
- Push any change to the
mainbranch, or trigger the workflow manually in GitHub Actions. - The workflow will:
- Check for required secrets.
- Register the SSH public key in Hetzner Cloud if not present.
- If the key was newly registered, automatically recreate the servers with the correct key.
- Provision infrastructure using Terraform Cloud.
- Fetch kubeconfig from the main node via SSH.
- Deploy LibreChat using Helm with automatic HTTPS/SSL certificate setup via cert-manager and Let's Encrypt.
- The SSL certificate for your domain (specified in
HOSTsecret) will be automatically issued and renewed.
The application is packaged and deployed using Helm.
- Chart Location:
./helm/librechat - Installation:
helm upgrade --install librechat ./helm/librechat \ --set ingress.host=$HOST \ --set ingress.enabled=true \ --set librechat-mcp.image=ghcr.io/simonvanlaak/librechat-mcp \ --set librechat-mcp.tag=latest
cd terraform
terraform init
terraform applyTo SSH into your main node (using your DNS record and the correct key), use:
ssh -i ./TheMaryAnne-ssh-key -o IdentitiesOnly=yes root@chat.simonvanlaak.deThis ensures only your specified key is used and avoids authentication failures due to multiple loaded keys.
To access your Kubernetes cluster from your local machine:
-
Copy kubeconfig from the remote host:
scp -i ./TheMaryAnne-ssh-key -o IdentitiesOnly=yes root@chat.simonvanlaak.de:/etc/rancher/k3s/k3s.yaml ~/.kube/config -
Update kubeconfig to use your DNS name:
sed -i "s/127.0.0.1/chat.simonvanlaak.de/g" ~/.kube/config chmod 600 ~/.kube/config
-
Access the cluster:
kubectl get nodes kubectl get pods -A kubectl get svc -A
- Logging: Use
kubectl logs -l app=librechatto view application logs. - Monitoring: Can be added via Prometheus/Grafana Helm charts.
LibreChat MCP is deployed as part of your Kubernetes stack. The CI/CD pipeline will build and push the Docker image, then deploy it using Helm.
-
Build Docker image:
docker build -t ghcr.io/simonvanlaak/librechat-mcp:latest -f LibreChat-MCP/Dockerfile LibreChat-MCP
-
Push Docker image:
docker push ghcr.io/simonvanlaak/librechat-mcp:latest
-
Deploy with Helm: (see Helm Installation above)
- SSH Permission Denied: Ensure the public key is registered in Hetzner Cloud and the private key matches.
- Kubeconfig Error: Ensure
SSH_PRIVATE_KEYis correct and the master node is reachable. - Terraform Token Error: Make sure
TF_API_TOKENis set and valid. - Missing Secrets: The workflow will fail early and print a clear error if any required secret is missing.
- Kubeconfig Not Found: Wait for the server to finish provisioning, or check SSH key setup.
- Pod Pending: Check if worker nodes are joined (in this minimal setup, check
kubectl get nodes).
- You may need to destroy/recreate servers if you change the SSH key after initial deployment.
- You can manually run
terraform taintandterraform applyin theterraform/directory if needed.
This repository uses GitHub Actions for automated CI/CD. The following secrets must be configured in the repository settings (Settings → Secrets and variables → Actions):
PARENT_REPO_TOKEN- Personal Access Token (PAT) withreposcope to trigger the parent repository (TheMaryAnne) workflow after successful image push. This token must have permissions to triggerrepository_dispatchevents in the parent repository.
- Go to GitHub Settings → Developer settings → Personal access tokens → Tokens (classic)
- Generate a new token with the
reposcope - Add it as a secret named
PARENT_REPO_TOKENin this repository's secrets
When code is pushed to the main branch (affecting McpService or Worker):
- Tests run for both MCP Service and Worker
- Both Docker images are built and pushed to GitHub Container Registry (unified workflow ensures both are built)
- Parent repository (TheMaryAnne) is automatically triggered to update the submodule reference and deploy both services
Note: The unified build-and-deploy.yml workflow ensures both MCP Service and Worker images are built and pushed before triggering the parent repo, guaranteeing atomic deployments.
ObsidianSync includes comprehensive testing infrastructure with git hooks for automated quality checks.
Git hooks run automatically when you commit or push code in the ObsidianSync submodule.
Hooks are installed automatically when you run the root repository's installation script:
# From root repository
./scripts/install-git-hooks.shOr manually install hooks in this submodule:
cd ObsidianSync
chmod +x .git/hooks/pre-commit .git/hooks/pre-pushThe pre-commit hook runs fast tests before each commit:
- Linting:
ruff check McpService/ Worker/ - Formatting:
ruff format --checkandblack --check - Type Checking:
mypy McpService/ Worker/(non-blocking) - Security:
bandit -r McpService/ Worker/ -ll(non-blocking) - Unit Tests:
pytest McpService/tests/unit/ Worker/tests/unit/ -v
Run manually:
./scripts/run-fast-tests.shOr use the existing comprehensive check script:
./scripts/run-checks.shThe pre-push hook runs integration tests before pushing:
- Integration Tests:
pytest McpService/tests/integration/ Worker/tests/integration/ -v - Full Test Suite:
pytest tests/ -v - Coverage Check: Ensures coverage threshold is met
- Docker Build Tests: Validates both McpService and Worker Dockerfiles build successfully
- Dockerfile Lint:
hadolintfor both Dockerfiles (if available)
Run manually:
./scripts/run-integration-tests.shTo bypass hooks when needed:
# Skip pre-commit hook
git commit --no-verify
# Skip pre-push hook
git push --no-verify
# Skip hooks in CI/CD
export SKIP_HOOKS=true# Run all checks (lint, format, type-check, security, tests)
./scripts/run-checks.sh
# Run with auto-fix
./scripts/run-checks.sh --fix
# Skip tests
./scripts/run-checks.sh --skip-tests# Run McpService unit tests
cd McpService
pytest tests/unit/ -v
# Run Worker unit tests
cd Worker
pytest tests/unit/ -v# Run McpService integration tests
cd McpService
pytest tests/integration/ -v
# Run Worker integration tests
cd Worker
pytest tests/integration/ -v# Run tests with coverage
pytest --cov=McpService --cov=Worker --cov-report=term-missing --cov-report=html tests/ -v# Test McpService Docker build
docker build -t test-obsidian-mcp -f McpService/Dockerfile McpService/
# Test Worker Docker build
docker build -t test-obsidian-worker -f Worker/Dockerfile Worker/For current bugs, todos, and planned features, see ROADMAP.md.