deer-flow/.env.example
Hyeonsang Cho 9c159ef880
fix(auth): key the compose login lockout by client, not by nginx (#6519)
* fix(auth): key the compose login lockout by client, not by nginx

Failed logins are counted per client IP, and the Gateway honors X-Real-IP
only from a peer listed in AUTH_TRUSTED_PROXIES. The compose files never
set it, and every browser request reaches the Gateway from the nginx
container, so all logins shared nginx's address: five wrong passwords
from anyone locked every user out for five minutes.

AUTH_TRUSTED_PROXIES now also accepts hostnames, resolved off the event
loop and cached for 10 seconds (failed lookups included, and only when
X-Real-IP is present), and both compose files default it to the bundled
nginx service, whose address Docker assigns. nginx overwrites X-Real-IP
with $remote_addr on every Gateway route; a test pins that for the three
maintained configs.

* docs(changelog): reference #6519

* fix(auth): share one trusted-proxy lookup across concurrent cache misses

A burst of setup-status / login requests on an expired hostname entry
started one getaddrinfo per request while DNS was slow, occupying the
default executor that password verification also uses. The cache check
and an in-flight task registration now happen without a yield between
them; later callers join that task through asyncio.shield, so a cancelled
request cannot cancel the lookup the others joined, and the task caches
its own result.

The compose default keeps `:-` on purpose: every browser request arrives
through nginx, so an empty AUTH_TRUSTED_PROXIES would only bring back the
shared lockout. The compose comment and .env.example say so, and the
rendered-compose test now covers the explicitly empty value.

* fix(docker): keep a .env AUTH_TRUSTED_PROXIES under make docker-start

docker.sh start runs Compose from docker/ without --env-file, so the dev
compose file's ${AUTH_TRUSTED_PROXIES:-nginx} interpolated from the shell
only, and the resolved environment entry outranked the operator's value
loaded through env_file. Export it from .env alongside the proxy variables
(a shell export still wins), and strip a CRLF before the quotes.

---------

Co-authored-by: Willem Jiang <willem.jiang@gmail.com>
2026-10-09 17:22:45 +08:00

135 lines
6.5 KiB
Plaintext

# Serper API Key (Google Search) - https://serper.dev
SERPER_API_KEY=your-serper-api-key
# Optional operator-controlled Serper-compatible API base URL, without /search or /images.
# The configured API key is sent in X-API-KEY to this host; use a trusted provider.
SERPER_BASE_URL=https://google.serper.dev
# Serply API Key (Google Search, News and Scholar) - https://serply.io
SERPLY_API_KEY=your-serply-api-key
# TAVILY API Key
TAVILY_API_KEY=your-tavily-api-key
# Jina API Key
JINA_API_KEY=your-jina-api-key
# InfoQuest API Key
INFOQUEST_API_KEY=your-infoquest-api-key
# Sofya API Key (web search and fetch) - https://sofya.co
SOFYA_API_KEY=your-sofya-api-key
# Unbrowse API Key (web fetch) - https://unbrowse.ai/app
UNBROWSE_API_KEY=your-unbrowse-api-key
# Browser CORS allowlist for split-origin or port-forwarded deployments (comma-separated exact origins).
# Leave unset when using the unified nginx endpoint, e.g. http://localhost:2026.
# GATEWAY_CORS_ORIGINS=http://localhost:3000,http://127.0.0.1:3000
# Host interface the Docker stack publishes its entry port on. Defaults to
# 127.0.0.1 (loopback only), matching the local-trusted-environment deployment
# model documented in README.md -- the agent can execute commands.
# Set 0.0.0.0 only when the host is protected by your own TLS/auth front door
# or firewall, and complete first-run setup before it becomes reachable.
# BIND_HOST=0.0.0.0
# PORT=2026
# Proxies whose X-Real-IP the Gateway trusts when it counts failed logins per
# client (comma-separated IPs, CIDRs or hostnames; a hostname is re-resolved
# every 10s). The Docker stack defaults to its bundled `nginx` service; without
# it every browser login shares nginx's address, so five wrong passwords from
# anyone lock everyone out. Behind your own front door, nginx sees that proxy's
# address instead: configure nginx's real_ip module for it as well.
# Outside Docker, unset or empty is direct mode: X-Real-IP is ignored. In the
# Docker stack an empty value also falls back to `nginx`, since every browser
# request arrives through it.
# AUTH_TRUSTED_PROXIES=nginx
# Optional:
# FIRECRAWL_API_KEY=your-firecrawl-api-key
# VOLCENGINE_API_KEY=your-volcengine-api-key
# OPENAI_API_KEY=your-openai-api-key
# OPENVIKING_API_KEY=your-openviking-user-api-key
# GEMINI_API_KEY=your-gemini-api-key
# DEEPSEEK_API_KEY=your-deepseek-api-key
# NOVITA_API_KEY=your-novita-api-key # OpenAI-compatible, see https://novita.ai
# MINIMAX_API_KEY=your-minimax-api-key # OpenAI-compatible, see https://platform.minimax.io
# OPPER_API_KEY=your-opper-api-key # OpenAI-compatible, see https://opper.ai
# OpenAI-compatible Images API (used by the image-generation skill)
# IMAGE_GENERATION_PROVIDER=openai # openai-compatible is also accepted
# IMAGE_GENERATION_API_KEY=your-image-generation-api-key
# IMAGE_GENERATION_BASE_URL=https://api.openai.com/v1
# IMAGE_GENERATION_MODEL=gpt-image-2.5-flare
# IMAGE_GENERATION_SIZE=1536x1024
# STEPFUN_API_KEY=your-stepfun-api-key # OpenAI-compatible, see https://platform.stepfun.com
# VLLM_API_KEY=your-vllm-api-key # OpenAI-compatible
# E2B cloud sandbox API key — required only when using E2BSandboxProvider.
# Sign up at https://e2b.dev/dashboard
# E2B_API_KEY=your-e2b-api-key
# FEISHU_APP_ID=your-feishu-app-id
# FEISHU_APP_SECRET=your-feishu-app-secret
# SLACK_BOT_TOKEN=your-slack-bot-token
# SLACK_APP_TOKEN=your-slack-app-token
# TELEGRAM_BOT_TOKEN=your-telegram-bot-token
# DISCORD_BOT_TOKEN=your-discord-bot-token
# Enable LangSmith to monitor and debug your LLM calls, agent runs, and tool executions.
# LANGSMITH_TRACING=true
# LANGSMITH_ENDPOINT=https://api.smith.langchain.com
# LANGSMITH_API_KEY=your-langsmith-api-key
# LANGSMITH_PROJECT=your-langsmith-project
# GitHub API Token
# GITHUB_TOKEN=your-github-token
# Database (only needed when config.yaml has database.backend: postgres)
# DATABASE_URL=postgresql://deerflow:password@localhost:5432/deerflow
#
# WECOM_BOT_ID=your-wecom-bot-id
# WECOM_BOT_SECRET=your-wecom-bot-secret
# DINGTALK_CLIENT_ID=your-dingtalk-client-id
# DINGTALK_CLIENT_SECRET=your-dingtalk-client-secret
# Set to "false" to disable Swagger UI, ReDoc, and OpenAPI schema in production
# GATEWAY_ENABLE_DOCS=false
# Shared internal Gateway auth token for multi-worker deployments.
# `make up` honors a value set here (as it does for BETTER_AUTH_SECRET) and
# otherwise generates one and persists it under DEER_FLOW_HOME; set it
# manually when Gateway workers also run outside the bundled deploy script.
# DEER_FLOW_INTERNAL_AUTH_TOKEN=your-shared-internal-token
# Provisioner API key for sandbox authentication (required when using provisioner/K8s sandbox mode).
# The same value must be set on the provisioner container and in config.yaml sandbox.provisioner_api_key.
# Generate: openssl rand -hex 32
# PROVISIONER_API_KEY=your-provisioner-api-key
# ── Frontend SSR → Gateway wiring ─────────────────────────────────────────────
# The Next.js server uses these to reach the Gateway during SSR (auth checks,
# /api/* rewrites). They default to localhost values that match `make dev` and
# `make start`, so most local users do not need to set them.
#
# Override only when the Gateway is not on localhost:8001 (e.g. when the
# frontend and gateway run on different hosts, in containers with a service
# alias, or behind a different port). docker-compose already sets these.
# DEER_FLOW_INTERNAL_GATEWAY_BASE_URL=http://localhost:8001
# DEER_FLOW_TRUSTED_ORIGINS=http://localhost:3000,http://localhost:2026
# ── Claude Code / Codex CLI subscription as a model provider (optional) ───────
# If you configure a ClaudeChatModel / Codex model provider (or an ACP agent)
# that reuses your CLI subscription login, prefer passing a token via env over
# bind-mounting your whole ~/.claude / ~/.codex into the container. The Gateway
# credential loader reads these first, so no directory mount is needed.
# CLAUDE_CODE_CREDENTIALS_PATH points at a single .credentials.json (Claude)
# rather than the whole dir. docker-compose.cli-auth.yaml is the opt-in
# directory-mount fallback for adapters that need the full CLI config.
# ACP adapters often take their own env API key (e.g. ANTHROPIC_API_KEY) and
# need no mount at all — check the adapter's docs. See SECURITY.md.
# CLAUDE_CODE_OAUTH_TOKEN=your-claude-code-oauth-token
# ANTHROPIC_AUTH_TOKEN=your-anthropic-auth-token
# CLAUDE_CODE_CREDENTIALS_PATH=/path/to/.claude/.credentials.json
# CODEX_AUTH_PATH=/path/to/codex/auth.json