~95% on SimpleQA (e.g. Qwen3.6-27B on a 3090). Supports all local and cloud LLMs (llama.cpp, Ollama, Google, ...). 10+ search engines - arXiv, PubMed, your...
docker pull learningcircuit/local-deep-research
docker run -d --name local-deep-research --restart always learningcircuit/local-deep-research:latest
podman run -d --name local-deep-research --restart always learningcircuit/local-deep-research:latest
skopeo inspect docker://docker.io/learningcircuit/local-deep-research:latest
oras pull learningcircuit/local-deep-research:latest
docker compose up -d
services:
local-deep-research:
{%- if cookiecutter.build %}
build:
context: .
dockerfile: Dockerfile
target: ldr
{% else %}
image: localdeepresearch/local-deep-research
{% endif %}
{%- if cookiecutter.host_network %}
network_mode: host # Best option for connecting to locally running Ollama
{% else %}
networks:
- ldr-network
{% endif %}
ports:
- "{{cookiecutter.host_port}}:{{cookiecutter.host_port}}"
environment:
# Web Interface Settings
- LDR_WEB_PORT={{cookiecutter.host_port}}
- LDR_WEB_HOST={{cookiecutter.host_ip}}
{%- if cookiecutter._enable_ollama %}
- LDR_LLM_PROVIDER=ollama
- LDR_LLM_OLLAMA_URL=http://ollama:11434
{% endif %}
{%- if cookiecutter.enable_searxng %}
- LDR_SEARCH_ENGINE_WEB_SEARXNG_DEFAULT_PARAMS_INSTANCE_URL=http://searxng:8080
{% endif %}
# Data directory configuration
- LDR_DATA_DIR=/data
volumes:
- ldr_data:/data
- ldr_scripts:/scripts
# Local document collections are managed via the Collections UI,
# not via Docker volume mounts. Do not add local_collections mounts here.
# Security: drop all capabilities, add back only what the entrypoint needs
security_opt:
- "no-new-privileges:true"
cap_drop:
- ALL
cap_add:
- CHOWN # chown -R ldruser:ldruser /data
- FOWNER # chmod on files not owned by root
- DAC_OVERRIDE # mkdir in /home/ldruser (.config dir)
- SETUID # setpriv setuid() to switch to ldruser
- SETGID # setpriv setgid() to switch group
restart: unless-stopped
{%- if cookiecutter._enable_ollama or cookiecutter.enable_searxng %}
depends_on:
{%- if cookiecutter._enable_ollama %}
ollama:
condition: service_healthy
{% endif %}
{%- if cookiecutter.enable_searxng %}
searxng:
condition: service_started
{% endif %}
{% endif %}
{%- if cookiecutter._enable_ollama %}
ollama:
{%- if cookiecutter.enable_gpu and cookiecutter._amd_gpu %}
image: ollama/ollama:rocm
{% else %}
image: ollama/ollama:latest
{% endif %}
container_name: ollama_service
entrypoint: "/scripts/ollama_entrypoint.sh ${MODEL:-{{ cookiecutter._ollama_model }}}"
healthcheck:
test: [ "CMD", "ollama", "show", "${MODEL:-{{ cookiecutter._ollama_model }}}" ]
interval: 10s
timeout: 5s
start_period: 10m
retries: 2
environment:
OLLAMA_KEEP_ALIVE: '30m'
volumes:
- ollama_data:/root/.ollama
- ldr_scripts:/scripts
{%- if not cookiecutter.host_network %}
networks:
- ldr-network
{% endif %}
{%- if cookiecutter.enable_gpu %}
{%- if cookiecutter._nvidia_gpu %}
deploy:
resources:
reservations:
devices:
- driver: nvidia
count: all
capabilities: [gpu]
{% elif cookiecutter._amd_gpu %}
devices:
- "/dev/kfd:/dev/kfd"
- "/dev/dri:/dev/dri"
{% endif %}
{% endif %}
security_opt:
- "no-new-privileges:true"
restart: unless-stopped
{% endif %}
{%- if cookiecutter.enable_searxng %}
searxng:
image: searxng/searxng:latest
container_name: searxng
{%- if not cookiecutter.host_network %}
networks:
- ldr-network
{% endif %}
volumes:
- searxng_data:/etc/searxng
restart: unless-stopped
{% endif %}
volumes:
ldr_data:
ldr_scripts:
ollama_data:
searxng_data:
{%- if not cookiecutter.host_network %}
networks:
ldr-network:
{% endif %}