Automated deployment of RAGFlow using Ansible and Docker Compose.
Create deploy-ragflow.yml:
---
- name: Deploy RAGFlow
hosts: ragflow_servers
become: true
vars:
app_root: /opt/ragflow
app_port: 80
ragflow_repo_url: https://github.com/infiniflow/ragflow.git
mysql_password: "{{ vault_mysql_password }}"
minio_password: "{{ vault_minio_password }}"
vm_max_map_count: 262144
tasks:
- name: Configure system memory mapping
sysctl:
name: vm.max_map_count
value: "{{ vm_max_map_count }}"
state: present
reload: true
notify: Restart sysctl
- name: Install Docker on Debian/Ubuntu
apt:
name:
- docker.io
- docker-compose-plugin
- git
state: present
update_cache: true
when: ansible_os_family == "Debian"
- name: Install Docker on RHEL family
dnf:
name:
- docker
- docker-compose-plugin
- git
state: present
when: ansible_os_family == "RedHat"
- name: Enable and start Docker
service:
name: docker
state: started
enabled: true
- name: Clone RAGFlow repository
git:
repo: "{{ ragflow_repo_url }}"
dest: "{{ app_root }}"
depth: 1
version: main
- name: Create environment configuration
template:
src: templates/env.j2
dest: "{{ app_root }}/docker/.env"
owner: root
group: root
mode: '0600'
vars:
mysql_pwd: "{{ mysql_password }}"
minio_pwd: "{{ minio_password }}"
http_port: "{{ app_port }}"
- name: Start RAGFlow with Docker Compose
command: >
docker compose -f docker-compose.yml up -d
args:
chdir: "{{ app_root }}/docker"
- name: Wait for RAGFlow to be ready
wait_for:
port: "{{ app_port }}"
delay: 10
timeout: 300
state: started
- name: Display access information
debug:
msg: |
RAGFlow has been deployed successfully!
Access URL: http://{{ ansible_host }}:{{ app_port }}
IMPORTANT:
- Change default passwords after first login
- Configure LLM API keys in the web UI
- Review security settings for production use
Repository: https://github.com/infiniflow/ragflow
Documentation: https://docs.ragflow.io
Create templates/env.j2:
# RAGFlow Configuration
RAGFLOW_IMAGE=infiniflow/ragflow:v0.24.0
# Device (cpu or gpu)
DEVICE=cpu
# HTTP Port
SVR_HTTP_PORT={{ http_port }}
# Database
MYSQL_HOST=mysql
MYSQL_PORT=3306
MYSQL_USER=root
MYSQL_PASSWORD={{ mysql_pwd }}
# Redis
REDIS_HOST=redis
REDIS_PORT=6379
# MinIO Storage
MINIO_HOST=minio
MINIO_PORT=9000
MINIO_USER=minioadmin
MINIO_PASSWORD={{ minio_pwd }}
# Document Engine (elasticsearch or infinity)
DOC_ENGINE=elasticsearch
Create inventory.ini:
[ragflow_servers]
ragflow-prod-01 ansible_host=192.168.1.100
ragflow-prod-02 ansible_host=192.168.1.101
[ragflow_servers:vars]
ansible_user=ubuntu
ansible_python_interpreter=/usr/bin/python3
Create secrets file:
ansible-vault create group_vars/all/vault.yml
Add your secrets:
vault_mysql_password: "your-secure-mysql-password-32chars"
vault_minio_password: "your-secure-minio-password-32chars"
Add to playbook:
handlers:
- name: Restart sysctl
command: sysctl -p
- name: Restart Docker
service:
name: docker
state: restarted
# Basic run
ansible-playbook -i inventory.ini deploy-ragflow.yml
# With vault secrets
ansible-playbook -i inventory.ini deploy-ragflow.yml --ask-vault-pass
# Limit to specific host
ansible-playbook -i inventory.ini deploy-ragflow.yml --limit ragflow-prod-01
# Dry run (check mode)
ansible-playbook -i inventory.ini deploy-ragflow.yml --check
Access RAGFlow:
http://your-server-ip:{{ app_port }}
Configure LLM API Keys:
Review Security Settings:
Add GPU support to playbook:
- name: Install NVIDIA Container Toolkit
apt:
name: nvidia-container-toolkit
state: present
when: enable_gpu | default(false)
- name: Configure GPU in .env
lineinfile:
path: "{{ app_root }}/docker/.env"
line: "DEVICE=gpu"
insertafter: "^#DEVICE="
when: enable_gpu | default(false)
Run with GPU:
ansible-playbook -i inventory.ini deploy-ragflow.yml -e "enable_gpu=true"
Create upgrade-ragflow.yml:
---
- name: Upgrade RAGFlow
hosts: ragflow_servers
become: true
vars:
app_root: /opt/ragflow
tasks:
- name: Pull latest changes
git:
repo: https://github.com/infiniflow/ragflow.git
dest: "{{ app_root }}"
version: main
force: true
- name: Rebuild and restart
command: >
docker compose -f docker-compose.yml up -d --build --pull always
args:
chdir: "{{ app_root }}/docker"
- name: Wait for RAGFlow to be ready
wait_for:
port: 80
delay: 10
timeout: 300
Run upgrade:
ansible-playbook -i inventory.ini upgrade-ragflow.yml
Create backup-ragflow.yml:
---
- name: Backup RAGFlow
hosts: ragflow_servers
become: true
vars:
app_root: /opt/ragflow
backup_dir: /backup/ragflow
tasks:
- name: Create backup directory
file:
path: "{{ backup_dir }}"
state: directory
mode: '0755'
- name: Stop RAGFlow
command: >
docker compose -f docker-compose.yml down
args:
chdir: "{{ app_root }}/docker"
- name: Backup MySQL volume
command: >
docker run --rm
-v ragflow_mysql_data:/source
-v {{ backup_dir }}:/backup
alpine tar czf /backup/mysql-backup.tar.gz -C /source .
- name: Backup MinIO volume
command: >
docker run --rm
-v ragflow_minio_data:/source
-v {{ backup_dir }}:/backup
alpine tar czf /backup/minio-backup.tar.gz -C /source .
- name: Backup configuration
copy:
src: "{{ app_root }}/docker/.env"
dest: "{{ backup_dir }}/env.backup"
remote_src: true
- name: Start RAGFlow
command: >
docker compose -f docker-compose.yml up -d
args:
chdir: "{{ app_root }}/docker"
Run backup:
ansible-playbook -i inventory.ini backup-ragflow.yml
| Variable | Description | Default |
|---|---|---|
app_root |
Installation directory | /opt/ragflow |
app_port |
HTTP port | 80 |
ragflow_repo_url |
Repository URL | GitHub URL |
mysql_password |
MySQL root password | Vault |
minio_password |
MinIO root password | Vault |
vm_max_map_count |
Memory mapping value | 262144 |
enable_gpu |
Enable GPU acceleration | false |
For production deployments:
See Security Guide for details.
ansible -i inventory.ini ragflow_servers \
-m shell -a "docker compose -f /opt/ragflow/docker/docker-compose.yml ps"
ansible -i inventory.ini ragflow_servers \
-m shell -a "docker compose -f /opt/ragflow/docker/docker-compose.yml logs -f"
ansible -i inventory.ini ragflow_servers \
-m shell -a "docker compose -f /opt/ragflow/docker/docker-compose.yml restart"
Any questions?
Feel free to contact us. Find all contact information on our contact page.