RAGFlow with Docker: RAG over PDFs and scanned documents (Linux, Windows, Mac)
Before you start
- 21 min read
Boxes marked Run in terminal are what you type; plain text explains why. Check what you need first

What you get in one minute#
RAGFlow is an open-source RAG engine that reads your PDFs, Word files and scanned pages with its own layout and OCR models, cuts them into chunks, and answers questions with citations that point back to the source page.
Logo: the official RAGFlow project (github.com/infiniflow/ragflow)
It is the tool to pick when your documents are messy: scans, tables, two-column papers, manuals. You run one Docker Compose stack, add a chat model and an embedding model, and keep everything on your own machine if the models are local. This guide pins the last stable release, adds a local Ollama, and spends extra time on what trips people up: the vm.max_map_count setting and RAM.
- Reads scans. The default PDF parser, DeepDoc, does OCR, table recognition and layout analysis. The "Naive" parser skips all of that.
- Shows its work. You can open and edit every chunk, test retrieval, and see which chunks an answer used.
- Private if you want it. With Ollama, documents, chunks and questions never leave the host.
| At a glance | Detail |
|---|---|
| Version used here | v0.27.3 (stable, October 2026). The newest tag is v1.0.0-rc3, a release candidate created the day this page was checked (see "The 1.0 line" below) |
| Licence | Apache-2.0 |
| Download size | Docs: about 2 GB compressed, about 7 GB unpacked. Docker Hub lists 3.6 GB for this tag. |
| RAM | Official starting point 16 GB. We did not measure; see "How much RAM it really needs". |
| Ports | 80 (web), 9380 (API), 9381 (admin API); dependency ports 1200, 3306, 9000, 9001, 6379 |
| Official docs | ragflow.io/docs and the GitHub repository |
How it fits together#
You upload a file, RAGFlow parses it, an embedding model turns each chunk into a vector, Elasticsearch stores them, and at question time the best chunks go to a chat model that writes the answer.
Diagram: one document and one question in v0.27.3, October 2026. MySQL (accounts, settings) and Valkey (task queue) also run and are left out.
Before you start#
| System | What you need |
|---|---|
| Linux | An x86-64 machine, Docker Engine with Compose v2.26.1 or newer, git, 4 cores, 16 GB RAM, 50 GB free disk |
| Windows | Docker Desktop with the WSL 2 backend, git, and enough memory for WSL 2 (default: 50% of your RAM, so a 16 GB PC gives Docker only 8 GB) |
| Mac | Docker Desktop and git. An Intel Mac matches the official x86 images; Apple Silicon has no arm64 image for v0.27.3 (below). |
Check the tools first:
docker --version docker compose version git --version
Docker must be 24.0.0 or newer, Compose v2.26.1 or newer.
- [ ] Docker is running with 16 GB of RAM to use and 50 GB of free disk
- [ ] ports 80 and 443 are free (or you plan to change them, see the HTTPS section)
- [ ] your CPU is x86-64 (the official image is amd64 only)
- [ ] a safe place for
.env, which will hold the passwords - [ ] for public HTTPS only: a domain, DNS pointing at the host, ports 80 and 443 open
Apple Silicon. The v0.27.3 quickstart says RAGFlow does not maintain ARM images. Docker Desktop can emulate amd64, but RAGFlow does not document it and we did not try it. Use an Intel or Linux machine, or read "The 1.0 line".
Tested on October 2026: not test-run by DIY Lab Hub. Every command comes from the official quickstart, README, FAQ and compose files at tag v0.27.3. Parts that are ours are marked "our own".
Step 1: Set vm.max_map_count#
Elasticsearch refuses to run when the kernel allows too few memory maps per process. The default is 65530; RAGFlow needs at least 262144. Forgetting it gives Can't connect to ES cluster. Infinity, the other engine, does not need it.
Tip: The value resets on reboot (Linux) and when Docker restarts (Windows, Mac). If RAGFlow worked yesterday and Elasticsearch loops today, check this first.
Linux#
sysctl vm.max_map_count sudo sysctl -w vm.max_map_count=262144 echo 'vm.max_map_count=262144' | sudo tee -a /etc/sysctl.d/99-ragflow.conf
The first line shows the value, the second applies it, the third keeps it after a reboot (the docs say /etc/sysctl.conf; a file in /etc/sysctl.d does the same).
Windows (PowerShell)#
Docker Desktop keeps the setting in its docker-desktop WSL instance. The quickstart gives:
wsl -d docker-desktop -u root sysctl -w vm.max_map_count=262144 exit
This resets when Docker restarts. To keep it, put this in %USERPROFILE%\.wslconfig, run wsl --shutdown, and start Docker Desktop again:
[wsl2] kernelCommandLine = "sysctl.vm.max_map_count=262144"
In the same file, add memory=16GB under [wsl2] if your PC has the RAM; the default is 50% of it (Microsoft's .wslconfig documentation).
Mac (Terminal)#
Docker Desktop on a Mac runs Linux in a VM. The quickstart sets the value there:
docker run --rm --privileged --pid=host alpine sysctl -w vm.max_map_count=262144
This resets when Docker Desktop restarts; the quickstart also describes a permanent LaunchDaemon route. Give Docker Desktop at least 16 GB under Settings, Resources.
Check it worked#
sysctl vm.max_map_count prints vm.max_map_count = 262144. On Windows run wsl -d docker-desktop -u root sysctl vm.max_map_count; on a Mac use the docker run line above without -w and the value.
Step 2: Download RAGFlow and pin the version#
The repository holds the Compose files. Check out the release tag so the files match the image (the README says this keeps entrypoint.sh in step). Everything lives under ~/docker_volumes/ragflow/: the repository in app/, backups in backups/.
Linux#
mkdir -p ~/docker_volumes/ragflow/backups git clone https://github.com/infiniflow/ragflow.git ~/docker_volumes/ragflow/app cd ~/docker_volumes/ragflow/app/docker git checkout -f v0.27.3
Windows (PowerShell)#
-c core.autocrlf=false keeps Linux line endings in the scripts Compose mounts into the container (our own precaution; issue 266 shows exec ./entrypoint.sh: no such file or directory on Windows, cause not named).
New-Item -ItemType Directory -Force "$HOME\docker_volumes\ragflow\backups" | Out-Null git clone -c core.autocrlf=false https://github.com/infiniflow/ragflow.git "$HOME\docker_volumes\ragflow\app" cd "$HOME\docker_volumes\ragflow\app\docker" git checkout -f v0.27.3
Mac (Terminal)#
Same commands as Linux:
mkdir -p ~/docker_volumes/ragflow/backups git clone https://github.com/infiniflow/ragflow.git ~/docker_volumes/ragflow/app cd ~/docker_volumes/ragflow/app/docker git checkout -f v0.27.3
Check it worked#
git describe --tags prints v0.27.3, and grep RAGFLOW_IMAGE .env shows RAGFLOW_IMAGE=infiniflow/ragflow:v0.27.3 first (the other lines are commented mirrors).
Step 3: Change the passwords before the first start#
The .env file warns: do not deploy with default passwords. All four defaults are infini_rag_flow. The databases take their password when their data folder is first created, so set new ones before the first start. We also set COMPOSE_PROJECT_NAME=ragflow (our own) so volumes are named ragflow_... instead of after the folder docker, which other projects may share.
Linux#
cd ~/docker_volumes/ragflow/app/docker for k in ELASTIC_PASSWORD MYSQL_PASSWORD MINIO_PASSWORD REDIS_PASSWORD; do sed -i.bak "s/^$k=.*/$k=$(openssl rand -hex 24)/" .env done printf '\nCOMPOSE_PROJECT_NAME=ragflow\n' >> .env rm .env.bak chmod 600 .env
Windows (PowerShell)#
cd "$HOME\docker_volumes\ragflow\app\docker"
$f = Join-Path (Get-Location) '.env'
$t = [System.IO.File]::ReadAllText($f)
foreach ($k in 'ELASTIC_PASSWORD','MYSQL_PASSWORD','MINIO_PASSWORD','REDIS_PASSWORD') {
$b = [byte[]]::new(24)
[System.Security.Cryptography.RandomNumberGenerator]::Fill($b)
$v = -join ($b | ForEach-Object { $_.ToString('x2') })
$t = $t -replace "(?m)^$k=.*", "$k=$v"
}
$t += "`nCOMPOSE_PROJECT_NAME=ragflow`n"
[System.IO.File]::WriteAllText($f, $t)
Mac (Terminal)#
Same commands as Linux (sed -i.bak works on both GNU and macOS sed):
cd ~/docker_volumes/ragflow/app/docker for k in ELASTIC_PASSWORD MYSQL_PASSWORD MINIO_PASSWORD REDIS_PASSWORD; do sed -i.bak "s/^$k=.*/$k=$(openssl rand -hex 24)/" .env done printf '\nCOMPOSE_PROJECT_NAME=ragflow\n' >> .env rm .env.bak chmod 600 .env
Copy .env to your password manager now.
Tip:
.envis a tracked file. Upgrading withgit checkout -fthrows your edits and passwords away; the update section shows the safe way.
Check it worked#
grep -E "^(ELASTIC|MYSQL|MINIO|REDIS)_PASSWORD" .env (PowerShell: Select-String "_PASSWORD=" .env) shows four random strings, none infini_rag_flow.
Step 4: Start the stack and wait for it#
The default profile is CPU. The first run downloads the images.
Linux#
docker compose -f docker-compose.yml up -d docker compose -f docker-compose.yml logs -f ragflow-cpu
Windows (PowerShell)#
docker compose -f docker-compose.yml up -d docker compose -f docker-compose.yml logs -f ragflow-cpu
Mac (Terminal)#
Same commands as Linux:
docker compose -f docker-compose.yml up -d docker compose -f docker-compose.yml logs -f ragflow-cpu
Ctrl+C leaves the log view; the stack keeps running.
Check it worked#
Wait for the banner the quickstart shows as its success sign (official expected output):
____ ___ ______ ______ __
/ __ \ / | / ____// ____// /____ _ __
/ /_/ // /| | / / __ / /_ / // __ \| | /| / /
/ _, _// ___ |/ /_/ // __/ / // /_/ /| |/ |/ /
/_/ |_|/_/ |_|\____//_/ /_/ \____/ |__/|__/
* Running on all addresses (0.0.0.0)
Then open http://localhost (port 80, so no port number) and register the first account. Opening the page before the banner can show network anomaly; wait and reload.
Then close the door: set REGISTER_ENABLED=0 and ENABLE_REGISTER=0 in .env and run docker compose -f docker-compose.yml up -d again. Registration ships switched on, so anyone who can open the page can create an account.
Step 5: Run Ollama and pull two models#
The official docs use Ollama as the local example, with llama3.2 (3B chat model, 2.0 GB) and bge-m3 (567M multilingual embedding model, 1.2 GB). We run Ollama as a second Compose project on RAGFlow's network, so nothing is published to your host. This layout is our own; the official route is below.
Linux#
mkdir -p ~/docker_volumes/ollama/data
cd ~/docker_volumes/ollama
cat > compose.yaml <<'EOF'
services:
ollama:
image: ollama/ollama:0.40.13
container_name: ollama
restart: unless-stopped
volumes:
- ./data:/root/.ollama
networks:
- ragflow
networks:
ragflow:
external: true
name: ragflow_ragflow
EOF
docker compose up -d
docker exec ollama ollama pull llama3.2
docker exec ollama ollama pull bge-m3
Windows (PowerShell)#
New-Item -ItemType Directory -Force "$HOME\docker_volumes\ollama\data" | Out-Null
cd "$HOME\docker_volumes\ollama"
@'
services:
ollama:
image: ollama/ollama:0.40.13
container_name: ollama
restart: unless-stopped
volumes:
- ./data:/root/.ollama
networks:
- ragflow
networks:
ragflow:
external: true
name: ragflow_ragflow
'@ | Set-Content -Encoding utf8 compose.yaml
docker compose up -d
docker exec ollama ollama pull llama3.2
docker exec ollama ollama pull bge-m3
Mac (Terminal)#
Same commands as Linux.
Docker on Windows and Mac gives the container no GPU; for a GPU use the native Ollama app (below).
Check it worked#
docker exec ollama ollama list docker compose -f ~/docker_volumes/ragflow/app/docker/docker-compose.yml exec ragflow-cpu curl -s http://ollama:11434/
The list shows both models. The second command tests the connection from inside the RAGFlow container and should answer Ollama is running (the official check, with our service name). In PowerShell write the path as "$HOME\docker_volumes\ragflow\app\docker\docker-compose.yml".
Using an Ollama that is already on your host#
A native Ollama suits a GPU. RAGFlow's docs then use http://host.docker.internal:11434, which the Compose file maps to the host. On Linux, native Ollama listens on 127.0.0.1 only: set OLLAMA_HOST=0.0.0.0:11434 (systemctl edit ollama.service, per the Ollama FAQ) and firewall port 11434, as the RAGFlow docs warn.
Step 6: Connect the models and parse a scanned PDF#
Linux#
In the browser, open your avatar at the top right, then Model providers, and choose Ollama. Add two models:
| Model name | Model type | Base URL |
|---|---|---|
llama3.2 | chat | http://ollama:11434 |
bge-m3 | embedding | http://ollama:11434 |
Then open System Model Settings and set llama3.2 as Chat model and bge-m3 as Embedding model.
Windows (PowerShell)#
Same screens and values as Linux.
Mac (Terminal)#
Same screens and values as Linux.
Tip: The model name and type must match Ollama's, letter for letter. Copy the name from
docker exec ollama ollama list.
Now the documents:
- Open Dataset, then Create dataset. Name it, choose
bge-m3as embedding model and the General chunking method. - In the dataset configuration, check the PDF parser: DeepDoc (the default) does the OCR, table and layout work. Keep it for scans.
- Add file, upload a PDF, then press the play button to parse. A scan takes longer than a text PDF, because OCR runs on every page.
- Open the parsed file to see the chunks. Double-click one to fix a recognition error or add keywords.
- In Retrieval testing, ask something whose answer you know is on a given page, and check the right chunk comes back before you build a chat.
- In Chat, create an assistant, pick the dataset and
llama3.2, and ask the same question. The answer shows the chunks it used.
Tip: Choose the embedding model before you parse anything. Once a file is parsed, the v0.27.3 docs say it cannot be changed: every chunk must live in the same vector space.
Check it worked#
The file shows a finished parse, the chunks hold readable text from your scan, and retrieval testing returns the page you expected.
Put it behind HTTPS (with or without Traefik)#
This is for a server with a domain. If RAGFlow only runs at home on http://localhost, skip it.
RAGFlow publishes ports 80 and 443 itself, and a proxy on the same host needs them. Move RAGFlow to 8080 and 8443 in .env (the README's "change the serving port" knob), then run docker compose -f docker-compose.yml up -d again:
SVR_WEB_HTTP_PORT=8080 SVR_WEB_HTTPS_PORT=8443
Tip: Anything that proxies to RAGFlow must use the new port. A Caddyfile that still says
localhost:80ends at your proxy itself.
With Traefik#
Our own override file puts the RAGFlow container on the external proxy network. Save it as docker-compose.traefik.yml next to docker-compose.yml:
services:
ragflow-cpu:
networks:
- proxy
labels:
- "traefik.enable=true"
- "traefik.docker.network=proxy"
- "traefik.http.routers.ragflow.rule=Host(`<your-domain>`)"
- "traefik.http.routers.ragflow.entrypoints=https"
- "traefik.http.routers.ragflow.tls=true"
- "traefik.http.services.ragflow.loadbalancer.server.port=80"
networks:
proxy:
external: true
Naming the first file with -f switches off Compose's automatic docker-compose.override.yml, so pass both files:
docker network create proxy docker compose -f docker-compose.yml -f docker-compose.traefik.yml up -d
Without Traefik: Caddy#
Choose this if you have no Traefik yet and run one small server. Caddy gets and renews certificates by itself.
| Your case | What Caddy does | What you do |
|---|---|---|
| Public domain | Automatic Let's Encrypt certificate | Point a DNS A record at the server; open ports 80 and 443 |
| Home only, no domain | tls internal: Caddy's own local certificate | Trust Caddy's root certificate on each device (below) |
Caddyfile (RAGFlow listens on 8080 after the change above):
ragflow.example.com {
reverse_proxy localhost:8080
}
Home-only variant (point ragflow.home.arpa at the server in your router or hosts file):
ragflow.home.arpa {
tls internal
reverse_proxy localhost:8080
}
- Linux: install from the official apt repository (caddyserver.com/docs/install), save the Caddyfile as
/etc/caddy/Caddyfile, thensudo systemctl reload caddy. - Windows (PowerShell):
winget install CaddyServer.Caddy, thencaddy run --config Caddyfile. - Mac:
brew install caddy, thencaddy run --config Caddyfile. - Docker: put the Caddyfile in
~/docker_volumes/caddy/, join RAGFlow's network, and usereverse_proxy ragflow-cpu:80:
services:
caddy:
image: caddy:2.11.7
restart: unless-stopped
ports:
- "80:80"
- "443:443"
volumes:
- ~/docker_volumes/caddy/Caddyfile:/etc/caddy/Caddyfile:ro
- ~/docker_volumes/caddy/data:/data
networks:
- ragflow
networks:
ragflow:
external: true
name: ragflow_ragflow
Home-only: trust Caddy's root certificate (pki/authorities/local/root.crt in Caddy's data folder).
- Linux:
sudo caddy truston the Caddy machine; on other devices copyroot.crtto/usr/local/share/ca-certificates/and runsudo update-ca-certificates. - Windows:
caddy trustin an administrator PowerShell; on other devices installroot.crtinto "Trusted Root Certification Authorities". - Mac:
caddy trust; on other Macs addroot.crtin Keychain Access as "Always Trust".
Streamed chat answers work: Caddy's docs say text/event-stream responses are flushed immediately. Check it worked: curl -I https://ragflow.example.com answers over HTTP/2.
Security and testing#
- Passwords and registration. New passwords in Step 3, registration off after your account (Step 4);
chmod 600 .envon Linux and Mac. - Published ports. The official Compose file publishes Elasticsearch (1200), MySQL (3306), MinIO (9000, 9001) and Valkey (6379) on every interface, although RAGFlow reaches them over the Docker network. On a server, block them with the firewall and expose only 80 and 443. Binding them to loopback with
ES_PORT=127.0.0.1:1200is valid Compose syntax (our own idea, not tested). - Ollama. In this guide it is not published at all. Never publish 11434 to the internet.
- What leaves the machine. Image pulls, the repository clone, Ollama model pulls, and possibly DeepDoc model files from Hugging Face on first parse (FAQ). A cloud chat or embedding provider would receive your chunks and questions. We found no telemetry setting in the
.env, README or docs; we did not capture traffic. - Test.
docker compose -f docker-compose.yml psshows all services up, the log shows the banner, retrieval testing returns the right chunk, and a chat answer cites it.
How much RAM it really needs#
There is no official measured number. The docs give a starting point and the compose files show where memory goes. We did not run the stack, so this table is what the official files say plus our reading.
| Piece | What the official files say | Our reading |
|---|---|---|
| Whole stack | 16 GB RAM or more, 4 cores, 50 GB disk | A starting point for the stack alone, not stack plus models |
| Elasticsearch | Capped by MEM_LIMIT=8073741824 bytes (7.5 GiB); heap sized automatically from the cap (Elastic docs) | The biggest single user |
| MySQL and Valkey | InnoDB buffer pool 1 GiB; Valkey --maxmemory 1gb | About 2 GB together |
| RAGFlow container | No cap; "some parsers ... require significant memory" (FAQ) | Grows with parsing; scans cost more than text PDFs |
| Ollama models | llama3.2 2.0 GB, bge-m3 1.2 GB downloads | At least that much RAM while loaded |
The caps alone add up to about 9.5 GiB before parsing and models. On 16 GB that is possible but tight; 32 GB is comfortable (our estimate). On Windows the real ceiling is WSL 2's share, 50% of the PC's RAM by default.
Tip: If parsing stops near the end or the log shows
Killed, suspect RAM. The FAQ's first fix is a biggerMEM_LIMITin.env.
Elasticsearch or Infinity#
Elasticsearch 8.11.3 is the default and needs the vm.max_map_count step. Infinity (infiniflow/infinity:v0.7.4-x64-v3) does not, but its README asks for an x86-64 CPU with AVX2. The docs list no RAM saving for Infinity, so do not switch to save memory unless you test it. Choose before you parse anything: the official switch is docker compose -f docker/docker-compose.yml down -v plus DOC_ENGINE=infinity, and -v deletes every volume.
Common mistakes#
| Mistake | Why it happens | Do this instead |
|---|---|---|
Skipping vm.max_map_count, or setting it once | It resets on reboot (Linux) and Docker restart (Windows, Mac); Elasticsearch loops and you see Can't connect to ES cluster | Make it permanent (/etc/sysctl.d, .wslconfig) and check it first when RAGFlow stops |
localhost or 127.0.0.1 as the Ollama address | Inside the RAGFlow container that is the container itself (issue 19287, the FAQ) | http://ollama:11434 here, or http://host.docker.internal:11434 for an Ollama on the host |
| Starting RAGFlow without checking out the tag | Compose files and image drift apart; an answer in issue 14029 says to clone the tagged version, as the README does | git checkout -f v0.27.3 and keep RAGFLOW_IMAGE on the same tag |
| Default passwords, open registration, published database ports | The stack starts fine, so nothing forces you | New passwords before the first start, REGISTER_ENABLED=0, a firewall |
| Changing passwords after the first start | Elasticsearch and MySQL read the password when their data folder is created, so stack and data disagree | Set them before the first start |
docker compose down -v "to clean up" | -v deletes the volumes; the upgrade page warns about it | docker compose down without -v, after a backup |
| Parsing a scan with the "Naive" PDF parser | It is faster; the docs say it skips OCR, tables and layout and is not recommended for scans | Keep DeepDoc (default) |
| Too little memory for Docker | WSL 2 gets 50% of your RAM by default; parsing is then killed (issue 7580, Killed ... task_executor.py) | Raise memory= in .wslconfig or Docker Desktop, then MEM_LIMIT |
AI assistant: writes infiniflow/ragflow:v0.21.1-slim or another -slim tag | Old tutorials had two editions; the README says only one ships since v0.22.0 and the suffix is gone | The plain tag from docker/.env (v0.27.3) |
AI assistant: says to open http://localhost:9380 | 9380 is the API; the README says the page is on port 80 | Open http://localhost; use 9380 for API calls |
Tip: Before you paste any RAGFlow command from an AI answer, open
docker/.envat your tag. It is the truth for image names, ports and variables.
Troubleshooting#
| Problem | Solution |
|---|---|
| Elasticsearch restarts in a loop | Check vm.max_map_count (Step 1), then docker compose -f docker-compose.yml logs es01 --tail 100 |
Browser says network anomaly | RAGFlow is still starting. Wait for the banner in docker compose -f docker-compose.yml logs ragflow-cpu, then reload |
Fail to access model(Ollama/...) | Ollama is down, the model is not pulled, the name differs, or the URL is unreachable from the RAGFlow container (below) |
| Parsing stuck below 1%, or stops near the end with no error | Click the red cross and parse again; read logs ragflow-cpu --tail 100. Usually RAM: more Docker memory, bigger MEM_LIMIT, fewer files at once |
| Garbled or empty chunks from a scan | Confirm the PDF parser is DeepDoc, inspect the chunks, try a cleaner scan or the Docling or vision-model parser in the dataset settings |
Index failure | RAGFlow could not write chunks to the engine: check Elasticsearch health and disk space |
Can't connect to ES cluster#
The quickstart ties this to vm.max_map_count being below 262144 after a reboot. Set it again (Step 1) and run docker compose -f docker-compose.yml up -d.
Max retries exceeded with url: /api/chat ... Connection refused#
The official Ollama page shows this for a wrong base URL. Test from inside the RAGFlow container: docker compose -f docker-compose.yml exec ragflow-cpu curl -s http://ollama:11434/ must print Ollama is running. Fix that before touching RAGFlow settings.
Known bugs#
- Chat hangs with an Ollama model (issue 20065, open): the reporter saw no reply on v0.27.2 and the then-current main, while v0.26.4 worked. No fix is recorded. Try a smaller chat model and watch
docker exec ollama ollama ps. - On the 1.0 candidate line, upload temp files fill
/tmp(issue 21159) and Docling Serve on a private address is blocked (issue 21425). Both are open.
Diagnostics: docker compose -f docker-compose.yml ps, docker stats --no-stream, docker volume ls --filter name=ragflow_.
Updates and backups#
Update#
The upgrade page says to change both code and image: stop, update the code, check out the new tag, set RAGFLOW_IMAGE, pull, start. Its example uses git checkout -f, which overwrites your edited .env. Use git stash instead (our own change):
cd ~/docker_volumes/ragflow/app/docker cp .env ~/docker_volumes/ragflow/backups/env-before-update docker compose -f docker-compose.yml down git fetch --tags git stash git checkout <new-tag> git stash pop grep RAGFLOW_IMAGE .env docker compose -f docker-compose.yml pull docker compose -f docker-compose.yml up -d
In PowerShell the same commands work; the copy is Copy-Item .env "$HOME\docker_volumes\ragflow\backups\env-before-update". Read the release notes and take a backup first. Never add -v to down.
Backup#
The data lives in named volumes (ragflow_esdata01, ragflow_mysql_data, ragflow_minio_data, ragflow_redis_data). Our own script stops the stack for a consistent copy, tars each volume, copies .env, and starts again:
#!/usr/bin/env bash
set -euo pipefail
B=~/docker_volumes/ragflow/backups; D=$(date +%F)
cd ~/docker_volumes/ragflow/app/docker
docker compose -f docker-compose.yml stop
for v in esdata01 mysql_data minio_data redis_data; do
docker run --rm -v "ragflow_$v":/data:ro -v "$B":/backup alpine:3.22 \
tar czf "/backup/$v-$D.tar.gz" -C /data .
done
cp .env "$B/env-$D" && chmod 600 "$B/env-$D"
docker compose -f docker-compose.yml start
Save it as ~/docker_volumes/ragflow/backup.sh, chmod +x it, and add 0 3 * * * ~/docker_volumes/ragflow/backup.sh with crontab -e (Linux and Mac). On Windows use this PowerShell version (backup.ps1 in the same folder) and a Task Scheduler entry at 03:00:
$B = "$HOME\docker_volumes\ragflow\backups"; $D = Get-Date -Format yyyy-MM-dd
Set-Location "$HOME\docker_volumes\ragflow\app\docker"
docker compose -f docker-compose.yml stop
foreach ($v in 'esdata01','mysql_data','minio_data','redis_data') {
docker run --rm -v "ragflow_${v}:/data:ro" -v "${B}:/backup" alpine:3.22 tar czf "/backup/$v-$D.tar.gz" -C /data .
}
Copy-Item .env "$B\env-$D"
docker compose -f docker-compose.yml start
schtasks /Create /SC DAILY /ST 03:00 /TN "RAGFlow backup" /TR "powershell -NoProfile -File $HOME\docker_volumes\ragflow\backup.ps1"
Restore test#
Test once with a throwaway volume: docker volume create restore_test, extract a tarball into it with docker run --rm -v restore_test:/data -v ~/docker_volumes/ragflow/backups:/backup alpine:3.22 tar xzf /backup/mysql_data-<date>.tar.gz -C /data, list it with docker run --rm -v restore_test:/data alpine:3.22 ls /data, then docker volume rm restore_test. A real restore is docker compose down, extracting each tarball into its empty volume, and up -d. We did not run this.
Performance and resources#
- Watch it.
docker stats --no-streamshows memory per container; run it while a big PDF parses. - Knobs in
.env.MEM_LIMITcaps the engine containers;DOC_BULK_SIZE(default 4) andEMBEDDING_BATCH_SIZE(default 16) set how much is parsed and embedded at once, and larger values use more memory (FAQ). - GPU. The default is CPU. For DeepDoc on an Nvidia GPU the README says
sed -i '1i DEVICE=gpu' .envbefore starting; we did not test it.
The 1.0 line#
The live docs today tell new users to check out v1.0.0-rc3. This guide stays on v0.27.3 on purpose: rc3 is a release candidate with no release notes yet, and the first 1.0 candidate says its data upgrade from v0.27.2 cannot be rolled back.
| v0.27.3 (this guide) | v1.0.0-rc3 | |
|---|---|---|
| Status | Stable release, October 2026 | Release candidate, October 2026 |
| Backend | Python | Go rewrite; queue moved to NATS, cache to Kvrocks |
| Image | amd64 only, 3.6 GB on Docker Hub | amd64 and arm64, about 360 MB on Docker Hub |
| DeepDoc | CPU or GPU | CPU only |
| macOS | No arm64 image | arm64 image, but the docs say the Go backend does not support macOS for source builds |
For an Apple Silicon image the 1.0 line is the only official arm64 choice. Read its release notes, back up, and follow its own quickstart, not this page's commands.
FAQ#
Is RAGFlow free? The code is Apache-2.0 and the images cost nothing. Cloud models cost money per use; the hosted cloud.ragflow.io has its own plans.
Does it work fully offline? After the images and Ollama models are pulled, questions and answers do. The FAQ says some parsers download DeepDoc model files from Hugging Face if not cached, so do your first parse while online.
Sources#
- RAGFlow repository: README, releases, licence, live docs
- At tag v0.27.3: quickstart, .env, docker-compose-base.yml, FAQ, local models, dataset configuration, upgrading
- v1.0.0-rc1 release notes, rc3 README, Docker Hub tags
- Issues: 19287, 14029, 7580, 20065, 266, 21159, 21425
- Ollama and its FAQ; Elasticsearch in Docker; WSL configuration; Caddy install and reverse_proxy
Checked against the official docs on 2026-10-30.