Skip to content
Open
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension


Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
5 changes: 5 additions & 0 deletions .env.example
Original file line number Diff line number Diff line change
Expand Up @@ -58,6 +58,11 @@ OPENSEARCH_PASSWORD=
# Default: ./opensearch-data
OPENSEARCH_DATA_PATH=./opensearch-data

# Path to persist Langflow database and state (flows, credentials, settings)
# Without this volume, flow edits will be lost on container restart
# Default: ./langflow-data
LANGFLOW_DATA_PATH=./langflow-data

# OpenSearch Connection
OPENSEARCH_HOST=opensearch
OPENSEARCH_PORT=9200
Expand Down
4 changes: 2 additions & 2 deletions .github/workflows/test-e2e.yml
Original file line number Diff line number Diff line change
Expand Up @@ -37,10 +37,10 @@ jobs:
docker builder prune -af || true
docker compose -f docker-compose.yml down -v --remove-orphans || true

- name: Cleanup root-owned files (OpenSearch data, config)
- name: Cleanup root-owned files (OpenSearch data, config, Langflow data)
run: |
for i in 1 2 3; do
docker run --rm -v $(pwd):/work alpine sh -c "rm -rf /work/opensearch-data /work/config" && break
docker run --rm -v $(pwd):/work alpine sh -c "rm -rf /work/opensearch-data /work/config /work/langflow-data" && break
echo "Attempt $i failed, retrying in 5s..."
sleep 5
done || true
Expand Down
4 changes: 2 additions & 2 deletions .github/workflows/test-integration.yml
Original file line number Diff line number Diff line change
Expand Up @@ -42,10 +42,10 @@ jobs:
docker builder prune -af || true
docker compose -f docker-compose.yml down -v --remove-orphans || true

- name: Cleanup root-owned files (OpenSearch data, config)
- name: Cleanup root-owned files (OpenSearch data, config, Langflow data)
run: |
for i in 1 2 3; do
docker run --rm -v $(pwd):/work alpine sh -c "rm -rf /work/opensearch-data /work/config" && break
docker run --rm -v $(pwd):/work alpine sh -c "rm -rf /work/opensearch-data /work/config /work/langflow-data" && break
echo "Attempt $i failed, retrying in 5s..."
sleep 5
done || true
Expand Down
3 changes: 3 additions & 0 deletions .gitignore
Original file line number Diff line number Diff line change
Expand Up @@ -32,6 +32,9 @@ wheels/

# OpenSearch data directory
opensearch-data/
# Langflow data directory (ignore contents, keep directory via .gitkeep)
/langflow-data/*
!/langflow-data/.gitkeep

node_modules

Expand Down
10 changes: 8 additions & 2 deletions Dockerfile.langflow
Original file line number Diff line number Diff line change
@@ -1,7 +1,13 @@
FROM langflowai/langflow:1.8.0

RUN pip install uv
# (+) Install uv
# (+) Pre-create the Langflow data directory with correct ownership.
# - This ensures named Docker volumes are initialised with uid=1000 so
# the non-root container user can write to the mounted path.
RUN set -ex \
&& pip install uv \
&& mkdir -p /app/langflow-data

EXPOSE 7860

CMD ["langflow", "run", "--host", "0.0.0.0", "--port", "7860"]
CMD ["langflow", "run", "--host", "0.0.0.0", "--port", "7860"]
6 changes: 6 additions & 0 deletions Makefile
Original file line number Diff line number Diff line change
Expand Up @@ -502,6 +502,7 @@ factory-reset: ## Complete reset (stop, remove volumes, clear data, remove image
echo " - Stop all containers"; \
echo " - Remove all volumes"; \
echo " - Delete opensearch-data directory"; \
echo " - Delete langflow-data directory"; \
echo " - Delete config directory"; \
echo " - Delete JWT keys (private_key.pem, public_key.pem)"; \
echo " - Remove OpenRAG images"; \
Expand All @@ -525,6 +526,11 @@ factory-reset: ## Complete reset (stop, remove volumes, clear data, remove image
rm -rf opensearch-data/* 2>/dev/null || true; \
echo "$(PURPLE)opensearch-data removed$(NC)"; \
fi; \
if [ -d "langflow-data" ]; then \
echo "Removing langflow-data..."; \
rm -rf langflow-data/* 2>/dev/null || true; \
echo "$(PURPLE)langflow-data removed$(NC)"; \
fi; \
if [ -d "config" ]; then \
echo "Removing config..."; \
rm -rf config; \
Expand Down
4 changes: 3 additions & 1 deletion docker-compose.yml
Original file line number Diff line number Diff line change
Expand Up @@ -127,6 +127,7 @@ services:
langflow:
volumes:
- ${OPENRAG_FLOWS_PATH:-./flows}:/app/flows:U,z
- ${LANGFLOW_DATA_PATH:-./langflow-data}:/app/langflow-data:U,z
image: langflowai/openrag-langflow:${OPENRAG_VERSION:-latest}
build:
context: .
Expand All @@ -145,7 +146,8 @@ services:
- WATSONX_URL=${WATSONX_URL:-${WATSONX_ENDPOINT}}
- WATSONX_PROJECT_ID=${WATSONX_PROJECT_ID}
- OLLAMA_BASE_URL=${OLLAMA_ENDPOINT}
- LANGFLOW_LOAD_FLOWS_PATH=/app/flows
- LANGFLOW_CONFIG_DIR=/app/langflow-data
- LANGFLOW_DATABASE_URL=sqlite:////app/langflow-data/langflow.db
- LANGFLOW_SECRET_KEY=${LANGFLOW_SECRET_KEY}
- JWT=None
- OWNER=None
Expand Down
1 change: 1 addition & 0 deletions docs/docs/reference/configuration.mdx
Original file line number Diff line number Diff line change
Expand Up @@ -94,6 +94,7 @@ For better security, it is recommended to set `LANGFLOW_SUPERUSER_PASSWORD` so t

| Variable | Default | Description |
|----------|---------|-------------|
| `LANGFLOW_DATA_PATH` | `./langflow-data` | The path where OpenRAG persists the Langflow database (flows, credentials, settings) across container restarts. |
| `LANGFLOW_AUTO_LOGIN` | Determined by `LANGFLOW_SUPERUSER_PASSWORD` | Whether to enable [auto-login mode](https://docs.langflow.org/api-keys-and-authentication#langflow-auto-login) for the Langflow visual editor and CLI. If `LANGFLOW_SUPERUSER_PASSWORD` isn't set, then `LANGFLOW_AUTO_LOGIN` is `True` and auto-login mode is enabled. If `LANGFLOW_SUPERUSER_PASSWORD` is set, then `LANGFLOW_AUTO_LOGIN` is `False` and auto-login mode is disabled. Langflow API calls always require authentication with a Langflow API key regardless of the auto-login setting. |
| `LANGFLOW_ENABLE_SUPERUSER_CLI` | Determined by `LANGFLOW_SUPERUSER_PASSWORD` | Whether to enable the [Langflow CLI `langflow superuser` command](https://docs.langflow.org/api-keys-and-authentication#langflow-enable-superuser-cli). If `LANGFLOW_SUPERUSER_PASSWORD` isn't set, then `LANGFLOW_ENABLE_SUPERUSER_CLI` is `True` and superuser accounts can be created with the Langflow CLI. If `LANGFLOW_SUPERUSER_PASSWORD` is set, then `LANGFLOW_ENABLE_SUPERUSER_CLI` is `False` and the `langflow superuser` command is disabled. |
| `LANGFLOW_NEW_USER_IS_ACTIVE` | Determined by `LANGFLOW_SUPERUSER_PASSWORD` | Whether new [Langflow user accounts are active by default](https://docs.langflow.org/api-keys-and-authentication#langflow-new-user-is-active). If `LANGFLOW_SUPERUSER_PASSWORD` isn't set, then `LANGFLOW_NEW_USER_IS_ACTIVE` is `True` and new user accounts are active by default. If `LANGFLOW_SUPERUSER_PASSWORD` is set, then `LANGFLOW_NEW_USER_IS_ACTIVE` is `False` and new user accounts are inactive by default. |
Expand Down
1 change: 1 addition & 0 deletions frontend/.env.test.example
Original file line number Diff line number Diff line change
Expand Up @@ -7,6 +7,7 @@ OPENSEARCH_PASSWORD=

# Paths
OPENSEARCH_DATA_PATH=./opensearch-data
LANGFLOW_DATA_PATH=./langflow-data
OPENSEARCH_INDEX_NAME=documents

# Model Providers
Expand Down
Empty file added langflow-data/.gitkeep
Empty file.
9 changes: 9 additions & 0 deletions src/main.py
Original file line number Diff line number Diff line change
Expand Up @@ -1198,6 +1198,15 @@ async def startup_tasks(services):
# Update MCP servers with provider credentials (especially important for no-auth mode)
await _update_mcp_servers_with_provider_credentials(services)

# Ensure all configured flows exist in Langflow (create-only, never overwrites).
# This replaces LANGFLOW_LOAD_FLOWS_PATH, which performed a blind upsert on
# every container start and discarded any user edits made in the Langflow UI.
try:
flows_service = services["flows_service"]
await flows_service.ensure_flows_exist()
except Exception as e:
logger.warning("Failed to ensure Langflow flows exist at startup", error=str(e))

# Check if flows were reset and reapply settings if config is edited
try:
config = get_openrag_config()
Expand Down
Loading
Loading