ragflow: add RAGFlow v0.26.4 RAG platform (ES engine, models via ollama)
This commit is contained in:
@@ -0,0 +1,69 @@
|
||||
{
|
||||
"$schema": "../app-info-schema.json",
|
||||
"name": "RAGFlow",
|
||||
"id": "ragflow",
|
||||
"available": true,
|
||||
"short_desc": "Open-source RAG engine with deep document understanding",
|
||||
"author": "alexz",
|
||||
"port": 9380,
|
||||
"categories": ["ai"],
|
||||
"tipi_version": 1,
|
||||
"version": "0.26.4",
|
||||
"source": "https://github.com/infiniflow/ragflow",
|
||||
"website": "https://ragflow.io",
|
||||
"exposable": true,
|
||||
"dynamic_config": true,
|
||||
"supported_architectures": ["amd64"],
|
||||
"min_tipi_version": "4.0.0",
|
||||
"form_fields": [
|
||||
{
|
||||
"type": "random",
|
||||
"label": "MySQL Root Password",
|
||||
"hint": "Root password for the bundled MySQL 8.0 database that stores RAGFlow's metadata",
|
||||
"env_variable": "RAGFLOW_MYSQL_ROOT_PASSWORD",
|
||||
"min": 24,
|
||||
"encoding": "hex"
|
||||
},
|
||||
{
|
||||
"type": "random",
|
||||
"label": "Elasticsearch Password",
|
||||
"hint": "Password for the built-in 'elastic' user on the Elasticsearch 8.11.3 document engine",
|
||||
"env_variable": "RAGFLOW_ELASTIC_PASSWORD",
|
||||
"min": 24,
|
||||
"encoding": "hex"
|
||||
},
|
||||
{
|
||||
"type": "random",
|
||||
"label": "MinIO Root Password",
|
||||
"hint": "Root password for the bundled MinIO object storage service (file/blob storage)",
|
||||
"env_variable": "RAGFLOW_MINIO_ROOT_PASSWORD",
|
||||
"min": 24,
|
||||
"encoding": "hex"
|
||||
},
|
||||
{
|
||||
"type": "random",
|
||||
"label": "Redis Password",
|
||||
"hint": "Password (requirepass) for the bundled Valkey/Redis cache and task queue",
|
||||
"env_variable": "RAGFLOW_REDIS_PASSWORD",
|
||||
"min": 24,
|
||||
"encoding": "hex"
|
||||
},
|
||||
{
|
||||
"type": "random",
|
||||
"label": "Session/JWT Signing Secret",
|
||||
"hint": "Signs RAGFlow's session cookies and API JWTs (RAGFLOW_SECRET_KEY). Without this, the image auto-generates and persists a secret in Redis on first boot, but a per-install random value here is stronger and survives a Redis data wipe.",
|
||||
"env_variable": "RAGFLOW_SECRET_KEY",
|
||||
"min": 32,
|
||||
"encoding": "hex"
|
||||
},
|
||||
{
|
||||
"type": "boolean",
|
||||
"label": "Enable Self-Registration",
|
||||
"hint": "Leave ON while this app is LAN-only so you can create the first admin account. Once the admin account exists, turn this OFF (re-save this form) BEFORE exposing the app on a public domain — see description for the full bootstrap sequence.",
|
||||
"env_variable": "RAGFLOW_REGISTER_ENABLED",
|
||||
"default": true
|
||||
}
|
||||
],
|
||||
"created_at": 1784530800000,
|
||||
"updated_at": 1784553280814
|
||||
}
|
||||
@@ -0,0 +1,196 @@
|
||||
{
|
||||
"schemaVersion": 2,
|
||||
"$schema": "https://schemas.runtipi.io/v2/dynamic-compose.json",
|
||||
"services": [
|
||||
{
|
||||
"name": "ragflow-es-init",
|
||||
"image": "busybox:1.36",
|
||||
"isMain": false,
|
||||
"restart": "no",
|
||||
"user": "root",
|
||||
"command": ["chown", "-R", "1000:0", "/usr/share/elasticsearch/data"],
|
||||
"volumes": [
|
||||
{
|
||||
"hostPath": "${APP_DATA_DIR}/data/es",
|
||||
"containerPath": "/usr/share/elasticsearch/data",
|
||||
"readOnly": false
|
||||
}
|
||||
]
|
||||
},
|
||||
{
|
||||
"name": "ragflow-es01",
|
||||
"image": "elasticsearch:8.11.3",
|
||||
"environment": [
|
||||
{ "key": "node.name", "value": "es01" },
|
||||
{ "key": "ELASTIC_PASSWORD", "value": "${RAGFLOW_ELASTIC_PASSWORD}" },
|
||||
{ "key": "bootstrap.memory_lock", "value": "false" },
|
||||
{ "key": "discovery.type", "value": "single-node" },
|
||||
{ "key": "xpack.security.enabled", "value": "true" },
|
||||
{ "key": "xpack.security.http.ssl.enabled", "value": "false" },
|
||||
{ "key": "xpack.security.transport.ssl.enabled", "value": "false" },
|
||||
{ "key": "cluster.routing.allocation.disk.watermark.low", "value": "5gb" },
|
||||
{ "key": "cluster.routing.allocation.disk.watermark.high", "value": "3gb" },
|
||||
{ "key": "cluster.routing.allocation.disk.watermark.flood_stage", "value": "2gb" },
|
||||
{ "key": "ES_JAVA_OPTS", "value": "-Xms2g -Xmx4g" }
|
||||
],
|
||||
"volumes": [
|
||||
{
|
||||
"hostPath": "${APP_DATA_DIR}/data/es",
|
||||
"containerPath": "/usr/share/elasticsearch/data",
|
||||
"readOnly": false
|
||||
}
|
||||
],
|
||||
"ulimits": {
|
||||
"memlock": { "soft": -1, "hard": -1 }
|
||||
},
|
||||
"deploy": {
|
||||
"resources": {
|
||||
"limits": {
|
||||
"memory": "8000M"
|
||||
}
|
||||
}
|
||||
},
|
||||
"dependsOn": {
|
||||
"ragflow-es-init": { "condition": "service_completed_successfully" }
|
||||
},
|
||||
"healthCheck": {
|
||||
"test": "curl http://127.0.0.1:9200 || exit 1",
|
||||
"interval": "10s",
|
||||
"timeout": "10s",
|
||||
"retries": 120,
|
||||
"startPeriod": "120s"
|
||||
}
|
||||
},
|
||||
{
|
||||
"name": "ragflow-mysql",
|
||||
"image": "mysql:8.0.39",
|
||||
"environment": [
|
||||
{ "key": "MYSQL_ROOT_PASSWORD", "value": "${RAGFLOW_MYSQL_ROOT_PASSWORD}" },
|
||||
{ "key": "MYSQL_DATABASE", "value": "rag_flow" }
|
||||
],
|
||||
"command": [
|
||||
"mysqld",
|
||||
"--max_connections=1000",
|
||||
"--character-set-server=utf8mb4",
|
||||
"--collation-server=utf8mb4_unicode_ci",
|
||||
"--default-authentication-plugin=mysql_native_password",
|
||||
"--tls_version=TLSv1.2,TLSv1.3",
|
||||
"--binlog_expire_logs_seconds=604800"
|
||||
],
|
||||
"volumes": [
|
||||
{
|
||||
"hostPath": "${APP_DATA_DIR}/data/mysql",
|
||||
"containerPath": "/var/lib/mysql",
|
||||
"readOnly": false
|
||||
}
|
||||
],
|
||||
"healthCheck": {
|
||||
"test": "mysqladmin ping -uroot -p${RAGFLOW_MYSQL_ROOT_PASSWORD}",
|
||||
"interval": "10s",
|
||||
"timeout": "10s",
|
||||
"retries": 60,
|
||||
"startPeriod": "30s"
|
||||
}
|
||||
},
|
||||
{
|
||||
"name": "ragflow-minio",
|
||||
"image": "pgsty/minio:RELEASE.2026-03-25T00-00-00Z",
|
||||
"command": ["server", "--console-address", ":9001", "/data"],
|
||||
"environment": [
|
||||
{ "key": "MINIO_ROOT_USER", "value": "rag_flow" },
|
||||
{ "key": "MINIO_ROOT_PASSWORD", "value": "${RAGFLOW_MINIO_ROOT_PASSWORD}" }
|
||||
],
|
||||
"volumes": [
|
||||
{
|
||||
"hostPath": "${APP_DATA_DIR}/data/minio",
|
||||
"containerPath": "/data",
|
||||
"readOnly": false
|
||||
}
|
||||
],
|
||||
"healthCheck": {
|
||||
"test": "curl -f http://127.0.0.1:9000/minio/health/live || exit 1",
|
||||
"interval": "10s",
|
||||
"timeout": "10s",
|
||||
"retries": 60,
|
||||
"startPeriod": "30s"
|
||||
}
|
||||
},
|
||||
{
|
||||
"name": "ragflow-redis",
|
||||
"image": "valkey/valkey:8.0.2",
|
||||
"command": [
|
||||
"redis-server",
|
||||
"--requirepass", "${RAGFLOW_REDIS_PASSWORD}",
|
||||
"--maxmemory", "128mb",
|
||||
"--maxmemory-policy", "allkeys-lru"
|
||||
],
|
||||
"volumes": [
|
||||
{
|
||||
"hostPath": "${APP_DATA_DIR}/data/redis",
|
||||
"containerPath": "/data",
|
||||
"readOnly": false
|
||||
}
|
||||
],
|
||||
"healthCheck": {
|
||||
"test": "redis-cli -a ${RAGFLOW_REDIS_PASSWORD} ping",
|
||||
"interval": "10s",
|
||||
"timeout": "10s",
|
||||
"retries": 30,
|
||||
"startPeriod": "15s"
|
||||
}
|
||||
},
|
||||
{
|
||||
"name": "ragflow-server",
|
||||
"image": "infiniflow/ragflow:v0.26.4",
|
||||
"isMain": true,
|
||||
"internalPort": 80,
|
||||
"entrypoint": [
|
||||
"/bin/bash",
|
||||
"-c",
|
||||
"if [ \"$RAGFLOW_REGISTER_ENABLED\" = \"false\" ]; then export REGISTER_ENABLED=0; else export REGISTER_ENABLED=1; fi; exec ./entrypoint.sh \"$@\"",
|
||||
"bash"
|
||||
],
|
||||
"command": ["--enable-adminserver", "--init-model-provider-tables"],
|
||||
"environment": [
|
||||
{ "key": "TZ", "value": "${TZ}" },
|
||||
{ "key": "DOC_ENGINE", "value": "elasticsearch" },
|
||||
{ "key": "ES_HOST", "value": "ragflow-es01" },
|
||||
{ "key": "ELASTIC_PASSWORD", "value": "${RAGFLOW_ELASTIC_PASSWORD}" },
|
||||
{ "key": "MYSQL_HOST", "value": "ragflow-mysql" },
|
||||
{ "key": "MYSQL_PORT", "value": "3306" },
|
||||
{ "key": "MYSQL_DBNAME", "value": "rag_flow" },
|
||||
{ "key": "MYSQL_PASSWORD", "value": "${RAGFLOW_MYSQL_ROOT_PASSWORD}" },
|
||||
{ "key": "MINIO_HOST", "value": "ragflow-minio" },
|
||||
{ "key": "MINIO_USER", "value": "rag_flow" },
|
||||
{ "key": "MINIO_PASSWORD", "value": "${RAGFLOW_MINIO_ROOT_PASSWORD}" },
|
||||
{ "key": "REDIS_HOST", "value": "ragflow-redis" },
|
||||
{ "key": "REDIS_PASSWORD", "value": "${RAGFLOW_REDIS_PASSWORD}" },
|
||||
{ "key": "RAGFLOW_SECRET_KEY", "value": "${RAGFLOW_SECRET_KEY}" },
|
||||
{ "key": "RAGFLOW_REGISTER_ENABLED", "value": "${RAGFLOW_REGISTER_ENABLED}" },
|
||||
{ "key": "API_PROXY_SCHEME", "value": "python" },
|
||||
{ "key": "USE_DOCLING", "value": "false" },
|
||||
{ "key": "DOTNET_SYSTEM_GLOBALIZATION_INVARIANT", "value": "1" }
|
||||
],
|
||||
"volumes": [
|
||||
{
|
||||
"hostPath": "${APP_DATA_DIR}/data/logs",
|
||||
"containerPath": "/ragflow/logs",
|
||||
"readOnly": false
|
||||
}
|
||||
],
|
||||
"dependsOn": {
|
||||
"ragflow-es01": { "condition": "service_healthy" },
|
||||
"ragflow-mysql": { "condition": "service_healthy" },
|
||||
"ragflow-minio": { "condition": "service_healthy" },
|
||||
"ragflow-redis": { "condition": "service_healthy" }
|
||||
},
|
||||
"healthCheck": {
|
||||
"test": "curl -f http://127.0.0.1:80/ || exit 1",
|
||||
"interval": "30s",
|
||||
"timeout": "10s",
|
||||
"retries": 10,
|
||||
"startPeriod": "180s"
|
||||
}
|
||||
}
|
||||
]
|
||||
}
|
||||
@@ -0,0 +1,80 @@
|
||||
# RAGFlow
|
||||
|
||||
RAGFlow is an open-source Retrieval-Augmented Generation (RAG) engine built on
|
||||
deep document understanding. It combines robust document layout parsing (PDF,
|
||||
Word, spreadsheets, slides, images, and more) with a configurable retrieval
|
||||
pipeline so you can ground LLM answers in your own knowledge base with
|
||||
traceable citations.
|
||||
|
||||
## What's included
|
||||
|
||||
This app deploys the full self-hosted RAGFlow stack in one shot:
|
||||
|
||||
- **RAGFlow server** (`infiniflow/ragflow:v0.26.4`) — the web UI, HTTP API,
|
||||
admin server, and task executor. This is the version-pinned image RAGFlow
|
||||
ships as the lightweight variant since v0.22 (no bundled embedding models).
|
||||
- **Elasticsearch 8.11.3** — the document/vector engine used for full-text and
|
||||
hybrid search over parsed document chunks. A one-shot `ragflow-es-init`
|
||||
helper container runs before it to fix ownership of the data directory
|
||||
(Elasticsearch's image runs as uid 1000, but Docker auto-creates bind-mount
|
||||
directories as root; without this step Elasticsearch crash-loops on first
|
||||
install and the whole stack never comes up).
|
||||
- **MySQL 8.0** — relational metadata store (users, datasets, chat sessions,
|
||||
configuration). The `rag_flow` database is created automatically via
|
||||
`MYSQL_DATABASE` on first boot.
|
||||
- **MinIO** — S3-compatible object storage for uploaded documents and
|
||||
generated artifacts.
|
||||
- **Valkey (Redis-compatible) 8.0.2** — cache and task queue for the ingestion
|
||||
pipeline.
|
||||
|
||||
## Models
|
||||
|
||||
No LLM or embedding model is bundled or hard-coded into this deployment.
|
||||
After installing, open **Settings → Model Providers** in the RAGFlow UI and
|
||||
add an **Ollama** provider pointing at your existing Ollama server on this
|
||||
instance:
|
||||
|
||||
- Base URL: `http://ollama-nvidia:11434`
|
||||
- Fallback (if the container-name route doesn't resolve): `http://172.18.0.1:11434`
|
||||
|
||||
## Admin bootstrap and public-exposure sequence (read before exposing)
|
||||
|
||||
This app installs with **self-registration ON** by default so you can create
|
||||
the first (admin) account. Follow this sequence exactly:
|
||||
|
||||
1. Install and wait for `ragflow-server` to report healthy.
|
||||
2. Visit the app on the LAN (`http://<tipi-local-domain-or-ip>`), register the
|
||||
first account — this becomes the admin account — and confirm you can sign
|
||||
in and reach the dashboard.
|
||||
3. Open this app's settings in the Runtipi dashboard and turn **Enable
|
||||
Self-Registration** OFF, then save. This re-applies the app config with
|
||||
`RAGFLOW_REGISTER_ENABLED=false`, which is translated internally to
|
||||
RAGFlow's `REGISTER_ENABLED=0`.
|
||||
4. Only after step 3 is confirmed, assign a public domain
|
||||
(`ragflow.alexzaw.dev`) and enable Traefik exposure from the dashboard.
|
||||
|
||||
Do not skip step 3 before going public — leaving self-registration on for an
|
||||
internet-facing instance lets anyone create an account.
|
||||
|
||||
## Session/JWT signing secret
|
||||
|
||||
A random 32-byte hex value is generated at install time and passed as
|
||||
`RAGFLOW_SECRET_KEY`, which RAGFlow uses directly (`common/settings.py:
|
||||
init_secret_key()`) to sign session cookies and JWTs, as long as it's at
|
||||
least 32 characters — ours is 64 hex characters. If this field were ever
|
||||
left empty, RAGFlow's own fallback still applies: it auto-generates a secret
|
||||
and persists it in Redis (`ragflow:system:secret_key`), so sessions survive
|
||||
container restarts either way. The explicit field is stronger because it
|
||||
doesn't depend on Redis data surviving a wipe/reset.
|
||||
|
||||
## Residual public-exposure risk
|
||||
|
||||
RAGFlow has no built-in 2FA and its own auth surface has not been
|
||||
independently audited by this deployment. Before assigning the public
|
||||
domain, put this app behind Cloudflare Access or an authentik forward-auth
|
||||
gate at the network layer, in addition to the registration lockdown above.
|
||||
|
||||
## Links
|
||||
|
||||
- Source: https://github.com/infiniflow/ragflow
|
||||
- Docs: https://ragflow.io/docs
|
||||
Binary file not shown.
|
After Width: | Height: | Size: 22 KiB |
Reference in New Issue
Block a user