No description
- Go 84.7%
- Jinja 14.9%
- Dockerfile 0.4%
| Filename | Latest commit message | Latest commit date |
|---|---|---|
| .gitea/workflows | ||
| defaults | ||
| files/otel/langfuse-fanout | ||
| handlers | ||
| meta | ||
| tasks | ||
| templates | ||
| .gitignore | ||
| CHANGELOG.md | ||
| LICENSE | ||
| README.md | ||
LibreChat
Deploys LibreChat via Docker Compose — API, bundled admin panel, MongoDB, Meilisearch, and a pgvector-backed RAG API — with an optional tenant-scoped Langfuse fanout gateway for multi-tenant observability.
Requirements
- Docker
community.dockerAnsible collection (>=5.2.0)
Variables
| Variable | Default | Description |
|---|---|---|
librechat_instance |
librechat |
Unique instance name. Used as Compose project name and a container-name prefix. |
librechat_version |
latest |
Tag for registry.librechat.ai/danny-avila/librechat-dev, or sha256:<digest> to pin an exact build. See Notes - latest is not safe to rely on for a deployment that cares about reproducibility. |
librechat_data_path |
/data/librechat |
Host path for persistent data (MongoDB, Meilisearch, pgvector, uploads, images, logs). |
librechat_docker_path |
/docker/librechat |
Host path for the Compose file and rendered .env. |
librechat_uid / librechat_gid |
1000 / 1000 |
Host UID/GID the api/mongodb/meilisearch containers run as. |
librechat_domain |
~ |
Public domain for the app. When set, enables Traefik routing and joins traefik_web. |
librechat_traefik_certresolver |
default |
Traefik certificate resolver for librechat_domain/librechat_admin_domain. |
librechat_port |
~ |
When set, publishes LibreChat on this host port (→ container port 3080) instead of using Traefik. |
librechat_admin_domain |
~ |
Public domain for the admin panel (independent of librechat_domain). |
librechat_admin_port |
~ |
When set, publishes the admin panel on this host port (→ container port 3000) instead of using Traefik. |
librechat_admin_panel_session_secret |
~ |
Required. Admin panel session encryption key (min 32 chars). Generate with openssl rand -hex 32. |
librechat_search_enabled |
false |
Enables Meilisearch-backed full-text search. Requires librechat_meili_master_key. |
librechat_meili_master_key |
~ |
Required when search is enabled. Generate with openssl rand -hex 32. |
librechat_custom_endpoint_enabled |
false |
Renders and mounts librechat.yaml with a single custom endpoint - replaces the built-in "openAI" endpoint, which always shows a hardcoded "OpenAI" name/icon regardless of what it's actually backed by. See Notes. |
librechat_endpoint_name / librechat_endpoint_api_key / librechat_endpoint_base_url |
~ |
Required when the custom endpoint is enabled. |
librechat_endpoint_models |
[] |
Required (at least one) when the custom endpoint is enabled. Static model list shown in the picker. |
librechat_endpoint_file_limit |
20 |
Max file size (MB) the custom endpoint accepts. PDFs are always delivered as extracted text rather than natively - see Notes. |
librechat_websearch_enabled |
false |
Enables web search in librechat.yaml: SearXNG + a Firecrawl-compatible scraper, no reranker, no third-party SaaS. Neither is deployed by this role - see Notes. |
librechat_stt_enabled |
false |
Enables speech-to-text/text-to-speech in librechat.yaml via a speaches instance. Not deployed by this role - see Notes. |
librechat_vectordb_db / librechat_vectordb_user |
librechat_rag / librechat_rag |
Postgres database/user for the RAG API's pgvector store (internal network only). |
librechat_vectordb_pass |
~ |
Required. Generate with openssl rand -hex 32. |
librechat_rag_port |
8000 |
Internal port the RAG API listens on. |
librechat_rag_embeddings_provider / librechat_rag_openai_baseurl / librechat_rag_openai_api_key |
openai / http://embeddings-not-configured.invalid/v1 / "" |
rag_api's embeddings backend. Point librechat_rag_openai_baseurl at any OpenAI-compatible endpoint (e.g. an internal litellm instance) to keep uploaded file content off the real OpenAI API. See Notes. |
librechat_rag_embeddings_model |
text-embedding-3-small |
Model name rag_api requests at librechat_rag_openai_baseurl. Must match a model_name that backend actually serves once the baseurl above is pointed somewhere real. |
librechat_creds_key / librechat_creds_iv |
~ |
Required. Encrypts stored provider credentials. Never change after first deploy. openssl rand -hex 32 / openssl rand -hex 16. |
librechat_jwt_secret / librechat_jwt_refresh_secret |
~ |
Required. Sign auth/session JWTs. openssl rand -hex 32 each. |
librechat_langfuse_public_key / librechat_langfuse_secret_key / librechat_langfuse_base_url |
~ / ~ / https://cloud.langfuse.com |
Central Langfuse project credentials. Leave librechat_langfuse_public_key unset to disable tracing. |
librechat_langfuse_fanout_central_auth_header |
~ |
Presence enables the tenant Langfuse fanout gateway (3 extra containers, built from files/otel/langfuse-fanout/). See Usage and Notes. |
librechat_langfuse_fanout_* |
see defaults/main.yml |
Fanout gateway tuning (destinations, timeouts, batching, metrics token). Sensible defaults for the 3-region Langfuse Cloud preset (eu/us/jp). |
librechat_env_extra |
"" |
Raw lines appended to the rendered .env for any of LibreChat's many optional settings not covered above (OAuth/SSO, SMTP, model provider keys, moderation, rate limits, MCP servers, ...). See dotenv docs. |
librechat_uninstall |
false |
Stops and removes containers and the compose directory. |
librechat_purge |
false |
Also removes the data directory (MongoDB, Meilisearch, pgvector, uploads, images, logs). Requires librechat_uninstall: true. Irreversible. |
Usage
Minimal setup, behind Traefik:
librechat_domain: "chat.example.com"
librechat_admin_domain: "admin-chat.example.com"
librechat_admin_panel_session_secret: "{{ vault_librechat_admin_panel_session_secret }}"
librechat_vectordb_pass: "{{ vault_librechat_vectordb_pass }}"
librechat_creds_key: "{{ vault_librechat_creds_key }}"
librechat_creds_iv: "{{ vault_librechat_creds_iv }}"
librechat_jwt_secret: "{{ vault_librechat_jwt_secret }}"
librechat_jwt_refresh_secret: "{{ vault_librechat_jwt_refresh_secret }}"
librechat_env_extra: |
OPENAI_API_KEY={{ vault_librechat_openai_api_key }}
ALLOW_REGISTRATION=true
Without a reverse proxy (direct host ports instead of the _domain vars):
librechat_port: 3080
librechat_admin_port: 3000
Enabling tenant-scoped Langfuse fanout (per-tenant Langfuse projects + a central rollup):
librechat_langfuse_public_key: "{{ vault_librechat_langfuse_public_key }}"
librechat_langfuse_secret_key: "{{ vault_librechat_langfuse_secret_key }}"
librechat_langfuse_fanout_central_auth_header: "{{ vault_librechat_langfuse_fanout_central_auth_header }}"
Tenant Langfuse keys and destinations are not set here — each tenant's key and destination are configured at runtime through Settings > Langfuse in the app.
Uninstall
librechat_uninstall: true
Add librechat_purge: true to also delete MongoDB/Meilisearch/pgvector/uploads data.
Notes
- rag_api ignores
.envand LibreChat's OpenAI/embeddings settings entirely. Only theapicontainer mounts the rendered.envfile;rag_apigets exactly the environment vars set on it directly incompose.yml.j2. Its embeddings backend must therefore be configured vialibrechat_rag_embeddings_provider/librechat_rag_openai_baseurl/librechat_rag_openai_api_key— settingRAG_OPENAI_BASEURL/EMBEDDINGS_PROVIDERvialibrechat_env_extrahas no effect on it. The defaults point nowhere resolvable on purpose (fail closed) rather than defaulting to the real OpenAI API, since rag_api falls back there itself when unconfigured — silently transmitting uploaded file content even without a valid key. .envstill carries the long tail. LibreChat has 250+ optional settings (OAuth providers, SMTP, moderation, rate limits, MCP servers, per-provider model config, ...). Rather than model every one as an Ansible variable, the handful that are required or security-sensitive for a working deploy are reallibrechat_*variables with asserts; everything else stays as commented reference intemplates/.env.j2(mirroring upstream's own.env.example), andlibrechat_env_extrais the escape hatch for whatever you actually need to turn on.- Admin panel is always its own origin. It gets its own
_domain/_portpair rather than sharinglibrechat_domain, since it's a separate container with separate OAuth/SSO redirect handling (ADMIN_PANEL_URL). - MongoDB runs
--noauth. It's only reachable on the internal Docker network (no host port published), matching upstream's own default; no credential is needed or configurable. - The Langfuse fanout gateway is bespoke, not upstream Langfuse. It's a small Go proxy LibreChat's own maintainers wrote to solve "route traces to a tenant's Langfuse project AND a central one" — Langfuse itself has no such concept, and there's no published image for it anywhere. This role vendors its source under
files/otel/langfuse-fanout/and builds it locally on the Docker host (deploy.ymlpasses--buildwhenever the fanout is enabled, so the image stays in sync with the vendored source on every run). Seefiles/otel/langfuse-fanout/README.mdfor the full design and its limitations. - RAG API is not optional.
vectordb+rag_apiare always deployed, matching upstream's default compose stack. librechat_versionpins theapicontainer's image (registry.librechat.ai/danny-avila/librechat-dev), defaulting tolatest. That image only publisheslatestand opaque per-commit git-sha tags - no semver/RC tags exist on it at all (those exist as git tags in the source repo, and as real published tags only on the separate, much-further-behind stablelibrechatimage, not the-devone this role uses).latestitself isn't safe to rely on for anything reproducible - confirmed live, it had already moved past a deployment's actual running build within weeks. Setlibrechat_versiontosha256:<digest>(docker image inspect <image> --format '{{index .RepoDigests 0}}'on a host already running the build you want to pin to) to pin an exact one; the template switches from:to@automatically for asha256:value.librechat_custom_endpoint_enabled'slibrechat.yamlis not a full LibreChat config surface. It renders exactly what upstream callsendpoints.custom(one endpoint) plus thefileConfig/webSearch/speechsections needed to support it - not a general-purposelibrechat.yamltemplating layer.librechat_websearch_enabled/librechat_stt_enabledassume a SearXNG+scraper / speaches instance already reachable on the same Docker network under fixed hostnames (searxng:8080,fastcrw:3000,whisper:8000) - this role deploys none of them; wire your own alongside this one under the samelibrechat_instanceproject name (matching container/network naming keeps them visually grouped indocker ps, though Compose will still warn about "orphan containers" since they're not in thiscompose.yml- harmless).