somratpro Claude Sonnet 4.6 commited on
Commit
534b16f
Β·
1 Parent(s): 1e9ba78

feat: dynamic dashboard at / + rewrite README following HuggingClip style

Browse files

- health-server.js: serve live dashboard at / (not just /dashboard); hero β†’ /workspace; probe /api/health + /workspace
- nginx.conf: remove static location = / block (health-server handles root now)
- README.md: full rewrite β€” badges, ToC, Features, Quick Start, LLM Providers, Search, Cloudflare, Backup, Keep Alive, Architecture, Troubleshooting, More Projects

Co-Authored-By: Claude Sonnet 4.6 <noreply@anthropic.com>

Files changed (3) hide show
  1. README.md +295 -51
  2. health-server.js +6 -6
  3. nginx.conf +0 -8
README.md CHANGED
@@ -8,78 +8,322 @@ app_port: 7860
8
  pinned: false
9
  ---
10
 
 
 
11
  # 🦌 HuggingFlow
12
 
13
- **DeerFlow** research agent running as a self-hosted [Hugging Face Space](https://huggingface.co/spaces) (Docker).
14
 
15
- Single-container deployment β€” frontend (Next.js) + backend (FastAPI) + nginx all in one image. No Docker-in-Docker, no Kubernetes.
 
 
 
16
 
17
- ## Required Secrets
18
 
19
- Set these in **Settings β†’ Variables and Secrets** on your HF Space:
20
 
21
- | Secret | Required | Description |
22
- |--------|----------|-------------|
23
- | `LLM_MODEL` | βœ… | Model in `provider/name` format (see below) |
24
- | `LLM_API_KEY` | βœ… | API key for the chosen provider |
25
- | `SERPER_API_KEY` | recommended | Google Search via Serper (better than DuckDuckGo) |
26
- | `TAVILY_API_KEY` | optional | Alternative web search |
27
- | `JINA_API_KEY` | optional | Better web page fetching |
28
- | `AUTH_JWT_SECRET` | optional | JWT signing secret β€” auto-generated if not set (sessions reset on restart) |
29
- | `HF_TOKEN` | optional | Your HF token β€” enables dataset backup/restore of threads |
30
- | `BACKUP_DATASET_NAME` | optional | HF dataset repo for backup (default: `huggingflow-backup`) |
31
 
32
- ## LLM_MODEL format
33
 
34
- ```
35
- provider/model-name
36
- ```
 
 
 
 
 
 
 
 
 
 
 
 
 
 
37
 
38
- Examples:
39
 
40
- ```
41
- openai/gpt-4o
42
- openai/gpt-4o-mini
43
- anthropic/claude-sonnet-4-5
44
- anthropic/claude-opus-4-5
45
- google/gemini-2.5-flash
46
- deepseek/deepseek-chat
47
- deepseek/deepseek-reasoner
48
- openrouter/anthropic/claude-3-5-sonnet
49
- mistral/mistral-large-latest
50
- groq/llama-3.3-70b-versatile
51
- ```
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
52
 
53
- ## Deploy to HF Spaces
54
 
55
- 1. Duplicate this repo to your HF account as a **Docker Space**
56
- 2. Add required secrets
57
- 3. Space builds and starts (~5-10 min on first build)
58
 
59
- ## Optional env vars
 
 
 
 
 
 
 
 
 
 
 
60
 
61
  | Variable | Default | Description |
62
  |----------|---------|-------------|
63
- | `CUSTOM_BASE_URL` | β€” | OpenAI-compatible API base URL (for custom providers) |
64
- | `SYNC_INTERVAL` | `600` | Seconds between HF Dataset backups |
 
 
 
 
 
 
65
  | `BACKEND_READY_TIMEOUT` | `120` | Seconds to wait for backend startup |
66
  | `FRONTEND_READY_TIMEOUT` | `120` | Seconds to wait for frontend startup |
67
- | `SPACE_HOST` | auto | Set by HF Spaces automatically |
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
68
 
69
- ## What runs inside
70
 
71
- | Process | Port | Role |
72
- |---------|------|------|
73
- | nginx | 7860 | Public reverse proxy (routes `/api/*` β†’ backend, `/*` β†’ frontend) |
74
- | uvicorn (FastAPI) | 8001 | DeerFlow gateway β€” agents, threads, auth |
75
- | Next.js | 3000 | DeerFlow UI |
76
 
77
- ## Caveats
 
 
78
 
79
- - **No Docker sandbox**: DeerFlow's `bash` / code execution tool is disabled by default (`allow_host_bash: false`). File read/write and web search work fine.
80
- - **Ephemeral storage**: container resets on restart. Enable `HF_TOKEN` + `BACKUP_DATASET_NAME` to persist threads.
81
- - **Single worker**: backend runs 2 uvicorn workers. For heavy use, consider a dedicated server.
82
 
83
- ## Source
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
84
 
85
- DeerFlow: https://github.com/bytedance/deer-flow
 
 
 
8
  pinned: false
9
  ---
10
 
11
+ <div align="center">
12
+
13
  # 🦌 HuggingFlow
14
 
15
+ **[DeerFlow](https://github.com/bytedance/deer-flow) research agent β€” one-click deploy on Hugging Face Spaces**
16
 
17
+ [![HF Space](https://img.shields.io/badge/πŸ€—%20Hugging%20Face-Space-yellow)](https://huggingface.co/spaces/somratpro/HuggingFlow)
18
+ [![GitHub](https://img.shields.io/badge/GitHub-somratpro%2FHuggingFlow-181717?logo=github)](https://github.com/somratpro/HuggingFlow)
19
+ [![License](https://img.shields.io/badge/license-MIT-blue)](LICENSE)
20
+ [![Docker](https://img.shields.io/badge/docker-single--container-2496ED?logo=docker)](Dockerfile)
21
 
22
+ *Self-hosted deep-research AI Β· multi-provider LLM Β· streaming SSE Β· dataset backup*
23
 
24
+ </div>
25
 
26
+ ---
 
 
 
 
 
 
 
 
 
27
 
28
+ ## Table of Contents
29
 
30
+ - [What is HuggingFlow?](#what-is-huggingflow)
31
+ - [Features](#features)
32
+ - [Quick Start](#quick-start)
33
+ - [Configuration](#configuration)
34
+ - [Required Secrets](#required-secrets)
35
+ - [Optional Variables](#optional-variables)
36
+ - [LLM Providers](#llm-providers)
37
+ - [Search Tools](#search-tools)
38
+ - [Cloudflare Proxy](#cloudflare-proxy)
39
+ - [Data Backup](#data-backup)
40
+ - [Stay Alive (Keep-Awake)](#stay-alive-keep-awake)
41
+ - [Architecture](#architecture)
42
+ - [Local Development](#local-development)
43
+ - [Troubleshooting](#troubleshooting)
44
+ - [More Projects](#more-projects)
45
+ - [Contributing](#contributing)
46
+ - [License](#license)
47
 
48
+ ---
49
 
50
+ ## What is HuggingFlow?
51
+
52
+ HuggingFlow wraps [DeerFlow](https://github.com/bytedance/deer-flow) (ByteDance's open-source deep-research agent) into a single Docker container that runs natively on [Hugging Face Spaces](https://huggingface.co/spaces).
53
+
54
+ **Zero infra.** Duplicate the Space, add your API keys, done β€” your own private research agent is live.
55
+
56
+ DeerFlow conducts multi-step research: it queries search engines, fetches web pages, synthesises findings across sources, and produces structured reports β€” all driven by the LLM you choose.
57
+
58
+ ---
59
+
60
+ ## Features
61
+
62
+ - πŸš€ **One-click deploy** β€” duplicate the HF Space, add secrets, done
63
+ - 🧠 **Multi-provider LLM** β€” OpenAI, Anthropic, Google Gemini, DeepSeek, Groq, Mistral, xAI, OpenRouter, Qwen, Moonshot, any OpenAI-compatible endpoint
64
+ - πŸ” **Pluggable search** β€” Serper (Google), Tavily, or DuckDuckGo (no key needed)
65
+ - πŸ’Ύ **Dataset backup** β€” threads auto-sync to a private HF Dataset; restored on restart
66
+ - 🌐 **Cloudflare outbound proxy** β€” route backend traffic through a Cloudflare Worker (beats HF Spaces IP blocks on some APIs)
67
+ - ⏰ **Keep-Awake cron** β€” Cloudflare Worker pings `/health` on a schedule to prevent cold starts
68
+ - πŸ“Š **Live dashboard** β€” status page at `/` with service health, model, search, backup and keep-awake tiles
69
+ - πŸ”’ **Auth built-in** β€” DeerFlow v2 JWT auth; create admin at `/setup` on first boot
70
+ - ⚑ **Pre-built images** β€” no source compilation; pulls official GHCR images for sub-5-minute builds
71
+ - πŸ“‘ **Streaming SSE** β€” real-time agent output streamed to the browser
72
+
73
+ ---
74
+
75
+ ## Quick Start
76
+
77
+ ### Deploy on Hugging Face Spaces
78
+
79
+ 1. **Duplicate this Space**
80
+
81
+ Go to [somratpro/HuggingFlow](https://huggingface.co/spaces/somratpro/HuggingFlow) β†’ **β‹― β†’ Duplicate Space**
82
+
83
+ 2. **Add required secrets**
84
+
85
+ Settings β†’ **Variables and Secrets** β†’ add `LLM_MODEL` and `LLM_API_KEY` (see [below](#required-secrets))
86
+
87
+ 3. **Wait for build**
88
+
89
+ First build pulls pre-built images β€” takes ~5 minutes. Subsequent restarts are instant.
90
+
91
+ 4. **Create your admin account**
92
+
93
+ Visit `https://<your-space>.hf.space/setup` β†’ create username + password
94
 
95
+ 5. **Start researching**
96
 
97
+ Open `/workspace` β€” you're live πŸŽ‰
 
 
98
 
99
+ ---
100
+
101
+ ## Configuration
102
+
103
+ ### Required Secrets
104
+
105
+ | Secret | Description |
106
+ |--------|-------------|
107
+ | `LLM_MODEL` | Model in `provider/model-name` format β€” see [LLM Providers](#llm-providers) |
108
+ | `LLM_API_KEY` | API key for the chosen provider |
109
+
110
+ ### Optional Variables
111
 
112
  | Variable | Default | Description |
113
  |----------|---------|-------------|
114
+ | `SERPER_API_KEY` | β€” | Google Search via Serper β€” strongly recommended over DuckDuckGo |
115
+ | `TAVILY_API_KEY` | β€” | Alternative web search (used if Serper not set) |
116
+ | `JINA_API_KEY` | β€” | Better web page fetching via Jina AI |
117
+ | `AUTH_JWT_SECRET` | auto-generated | JWT signing secret β€” set this to keep sessions alive across restarts |
118
+ | `HF_TOKEN` | β€” | Your HF token β€” enables dataset backup/restore |
119
+ | `BACKUP_DATASET_NAME` | `huggingflow-backup` | HF dataset repo name for backups (created automatically) |
120
+ | `CUSTOM_BASE_URL` | β€” | OpenAI-compatible API base URL for any custom/self-hosted provider |
121
+ | `SYNC_INTERVAL` | `600` | Seconds between HF Dataset backup syncs |
122
  | `BACKEND_READY_TIMEOUT` | `120` | Seconds to wait for backend startup |
123
  | `FRONTEND_READY_TIMEOUT` | `120` | Seconds to wait for frontend startup |
124
+ | `CLOUDFLARE_WORKERS_TOKEN` | β€” | Cloudflare API token β€” enables outbound proxy + keep-awake cron |
125
+ | `CLOUDFLARE_PROXY_URL` | β€” | Existing Cloudflare Worker URL (skip auto-setup) |
126
+
127
+ ---
128
+
129
+ ## LLM Providers
130
+
131
+ Set `LLM_MODEL` to `provider/model-name`:
132
+
133
+ | Provider | Example `LLM_MODEL` | Notes |
134
+ |----------|---------------------|-------|
135
+ | **OpenAI** | `openai/gpt-4o` | Default provider |
136
+ | **Anthropic** | `anthropic/claude-sonnet-4-5` | Extended thinking supported |
137
+ | **Google Gemini** | `google/gemini-2.5-flash` | Extended thinking supported |
138
+ | **DeepSeek** | `deepseek/deepseek-chat` | Extended thinking supported |
139
+ | **Groq** | `groq/llama-3.3-70b-versatile` | Fast inference |
140
+ | **Mistral** | `mistral/mistral-large-latest` | |
141
+ | **xAI / Grok** | `xai/grok-3-beta` | |
142
+ | **OpenRouter** | `openrouter/anthropic/claude-3-5-sonnet` | Access 200+ models |
143
+ | **Qwen / Alibaba** | `qwen/qwen-max` | DashScope compatible |
144
+ | **Moonshot / Kimi** | `moonshot/moonshot-v1-128k` | |
145
+ | **Custom OpenAI-compat** | `openai/your-model` + `CUSTOM_BASE_URL` | Any self-hosted endpoint |
146
+
147
+ > **Tip:** Models with extended thinking (Anthropic, Gemini, DeepSeek) produce higher-quality research plans but use more tokens.
148
+
149
+ ---
150
+
151
+ ## Search Tools
152
+
153
+ DeerFlow uses web search as its primary information source. Configure in priority order:
154
+
155
+ | Tool | Key | Quality | Cost |
156
+ |------|-----|---------|------|
157
+ | **Serper** | `SERPER_API_KEY` | ⭐⭐⭐ (real Google) | ~$0.001/query |
158
+ | **Tavily** | `TAVILY_API_KEY` | ⭐⭐ | free tier available |
159
+ | **DuckDuckGo** | none needed | ⭐ | free, rate-limited |
160
+
161
+ Serper is strongly recommended for research quality. Sign up at [serper.dev](https://serper.dev) β€” 2,500 free queries/month.
162
+
163
+ ---
164
+
165
+ ## Cloudflare Proxy
166
+
167
+ HF Spaces shares IPs that some APIs block. The Cloudflare outbound proxy routes backend HTTP requests through a Cloudflare Worker, giving you a clean egress IP.
168
+
169
+ **Setup:**
170
+ 1. Get a Cloudflare API token with **Workers Edit** permission
171
+ 2. Set `CLOUDFLARE_WORKERS_TOKEN` in your Space secrets
172
+ 3. On next start, `cloudflare-proxy-setup.py` auto-creates the Worker and sets `CLOUDFLARE_PROXY_URL`
173
+
174
+ Or manually provide `CLOUDFLARE_PROXY_URL` if you have an existing Worker.
175
+
176
+ ---
177
+
178
+ ## Data Backup
179
 
180
+ By default threads are stored in SQLite inside the container β€” **lost on restart**.
181
 
182
+ Enable persistent backup with HF Datasets:
 
 
 
 
183
 
184
+ 1. Set `HF_TOKEN` to a token with **Write** access to your profile
185
+ 2. Optionally set `BACKUP_DATASET_NAME` (default: `huggingflow-backup`)
186
+ 3. The dataset is created automatically (private) on first sync
187
 
188
+ **What's backed up:** SQLite database (threads, messages, uploads index), workspace files.
 
 
189
 
190
+ **Sync schedule:** every `SYNC_INTERVAL` seconds (default 10 min) + on graceful shutdown + on startup (restore).
191
+
192
+ ---
193
+
194
+ ## Stay Alive (Keep-Awake)
195
+
196
+ Free HF Spaces pause after ~15 minutes of inactivity. Fix it with a Cloudflare Worker cron:
197
+
198
+ 1. Set `CLOUDFLARE_WORKERS_TOKEN` (same token as proxy setup)
199
+ 2. `cloudflare-keepalive-setup.py` creates a Worker that pings `/health` every 10 minutes
200
+ 3. Status shown in the dashboard **Keep Awake** tile
201
+
202
+ Check `KEEPALIVE_STATUS_FILE` (`/tmp/huggingflow-cloudflare-keepalive-status.json`) for current state.
203
+
204
+ ---
205
+
206
+ ## Architecture
207
+
208
+ ```
209
+ Browser
210
+ β”‚
211
+ β–Ό :7860
212
+ health-server.js ──── / β†’ status dashboard (HTML)
213
+ β”‚ ──── /health β†’ JSON health check
214
+ β”‚ ──── /status β†’ JSON full status
215
+ β”‚ ──── /* β†’ proxy to nginx
216
+ β”‚
217
+ β–Ό :7861
218
+ nginx
219
+ β”‚ /api/langgraph/* β†’ rewrite β†’ /api/* β†’ backend :8001
220
+ β”‚ /api/* β†’ β†’ backend :8001
221
+ β”‚ /health β†’ β†’ backend :8001/health
222
+ β”‚ /docs /redoc β†’ β†’ backend :8001
223
+ β”‚ /* β†’ β†’ frontend :3000
224
+ β”‚
225
+ β”œβ”€β–Ά :8001 FastAPI (uvicorn) β€” DeerFlow gateway, agents, auth, SQLite
226
+ └─▢ :3000 Next.js β€” DeerFlow UI (server-side rendered)
227
+ ```
228
+
229
+ **Port map:**
230
+
231
+ | Port | Service | Exposed |
232
+ |------|---------|---------|
233
+ | 7860 | health-server.js | βœ… public (HF Spaces) |
234
+ | 7861 | nginx | internal only |
235
+ | 8001 | FastAPI backend | internal only |
236
+ | 3000 | Next.js frontend | internal only |
237
+
238
+ **Images used:**
239
+ - `ghcr.io/bytedance/deer-flow-backend:latest` β€” pre-built Python backend + `.venv`
240
+ - `ghcr.io/bytedance/deer-flow-frontend:latest` β€” pre-built Next.js + `node_modules`
241
+ - No source compilation β€” build time ~5 min instead of 30+ min
242
+
243
+ ---
244
+
245
+ ## Local Development
246
+
247
+ ```bash
248
+ git clone https://github.com/somratpro/HuggingFlow
249
+ cd HuggingFlow
250
+
251
+ # Build
252
+ docker build -t huggingflow .
253
+
254
+ # Run (set your own keys)
255
+ docker run -p 7860:7860 \
256
+ -e LLM_MODEL=openai/gpt-4o \
257
+ -e LLM_API_KEY=sk-... \
258
+ -e SERPER_API_KEY=... \
259
+ huggingflow
260
+ ```
261
+
262
+ Open `http://localhost:7860` for the dashboard, `http://localhost:7860/setup` to create your admin account, then `http://localhost:7860/workspace`.
263
+
264
+ **Useful routes:**
265
+
266
+ | Route | Description |
267
+ |-------|-------------|
268
+ | `/` | Status dashboard |
269
+ | `/workspace` | DeerFlow research UI |
270
+ | `/setup` | Admin account creation (first boot only) |
271
+ | `/api/health` | Backend health (JSON) |
272
+ | `/docs` | Swagger API reference |
273
+ | `/redoc` | ReDoc API reference |
274
+
275
+ ---
276
+
277
+ ## Troubleshooting
278
+
279
+ **"Application error" on `/workspace` or `/setup`**
280
+ > The pre-built frontend requires `DEER_FLOW_TRUSTED_ORIGINS` to be set explicitly. `start.sh` handles this automatically. If you see this error in a custom setup, ensure the env var is set before starting Next.js.
281
+
282
+ **Build takes 30+ minutes / OOMKilled**
283
+ > Ensure Docker has β‰₯4 GB RAM. HuggingFlow uses pre-built images specifically to avoid compilation. If you're rebuilding from source, add `NODE_OPTIONS=--max-old-space-size=3072`.
284
+
285
+ **DuckDuckGo returning no results**
286
+ > DuckDuckGo rate-limits aggressively from shared IPs. Set `SERPER_API_KEY` or `TAVILY_API_KEY`.
287
+
288
+ **Threads lost after restart**
289
+ > Set `HF_TOKEN` and `BACKUP_DATASET_NAME` to enable dataset sync. Without it, storage is ephemeral.
290
+
291
+ **Space goes to sleep**
292
+ > Set `CLOUDFLARE_WORKERS_TOKEN` to enable the keep-awake cron. Alternatively, upgrade to a paid HF Space tier.
293
+
294
+ **Backend health shows `not_authenticated`**
295
+ > Normal β€” DeerFlow v2 protects all `/api/*` routes. The public health endpoint is `/health` (no auth). nginx routes `/health` β†’ `backend:8001/health`.
296
+
297
+ ---
298
+
299
+ ## More Projects
300
+
301
+ | Project | Description |
302
+ |---------|-------------|
303
+ | [HuggingFlow](https://github.com/somratpro/HuggingFlow) | This project β€” DeerFlow on HF Spaces |
304
+ | [HuggingClip](https://github.com/somratpro/HuggingClip) | Open-source Clipper running on HF Spaces |
305
+ | [DeerFlow](https://github.com/bytedance/deer-flow) | Upstream deep-research agent by ByteDance |
306
+
307
+ ---
308
+
309
+ ## Contributing
310
+
311
+ Issues and PRs welcome. Please open an issue first for large changes.
312
+
313
+ ```
314
+ Fork β†’ branch β†’ commit β†’ PR
315
+ ```
316
+
317
+ ---
318
+
319
+ ## License
320
+
321
+ MIT β€” see [LICENSE](LICENSE).
322
+
323
+ DeerFlow is Β© ByteDance, licensed under MIT.
324
+
325
+ ---
326
 
327
+ <div align="center">
328
+ <sub>Built with ❀️ by <a href="https://github.com/somratpro">somratpro</a> · Powered by <a href="https://github.com/bytedance/deer-flow">DeerFlow</a></sub>
329
+ </div>
health-server.js CHANGED
@@ -182,8 +182,8 @@ function renderDashboard({ backendUp, frontendUp, uptimeHuman, sync, keepalive }
182
  <h1>🦌 HuggingFlow</h1>
183
  <div class="subtitle">DeerFlow Research Agent Β· Status Dashboard</div>
184
  </header>
185
- <a class="hero-action${appOnline ? "" : " disabled"}" href="/" target="_blank" rel="noopener noreferrer">
186
- ${appOnline ? "Open DeerFlow β†’" : "DeerFlow is starting…"}
187
  </a>
188
  <section class="grid">${tiles}</section>
189
  <footer>
@@ -241,11 +241,11 @@ const server = http.createServer(async (req, res) => {
241
  }));
242
  }
243
 
244
- // Dashboard β€” HTML status page
245
- if (pathname === "/dashboard") {
246
  const [backendUp, frontendUp] = await Promise.all([
247
- probe(NGINX_HOST, NGINX_PORT, "/health"),
248
- probe(NGINX_HOST, NGINX_PORT, "/"),
249
  ]);
250
  res.writeHead(200, { "Content-Type": "text/html; charset=utf-8" });
251
  return res.end(renderDashboard({
 
182
  <h1>🦌 HuggingFlow</h1>
183
  <div class="subtitle">DeerFlow Research Agent Β· Status Dashboard</div>
184
  </header>
185
+ <a class="hero-action${appOnline ? "" : " disabled"}" href="/workspace" target="_blank" rel="noopener noreferrer">
186
+ ${appOnline ? "Open DeerFlow Workspace β†’" : "DeerFlow is starting…"}
187
  </a>
188
  <section class="grid">${tiles}</section>
189
  <footer>
 
241
  }));
242
  }
243
 
244
+ // Dashboard β€” HTML status page (served at / and /dashboard)
245
+ if (pathname === "/" || pathname === "/dashboard") {
246
  const [backendUp, frontendUp] = await Promise.all([
247
+ probe(NGINX_HOST, NGINX_PORT, "/api/health"),
248
+ probe(NGINX_HOST, NGINX_PORT, "/workspace"),
249
  ]);
250
  res.writeHead(200, { "Content-Type": "text/html; charset=utf-8" });
251
  return res.end(renderDashboard({
nginx.conf CHANGED
@@ -120,14 +120,6 @@ http {
120
  proxy_read_timeout 600s;
121
  }
122
 
123
- # ── Custom dashboard at root ──────────────────────────
124
- location = / {
125
- root /app;
126
- try_files /dashboard.html =404;
127
- default_type text/html;
128
- add_header Cache-Control "no-cache";
129
- }
130
-
131
  # ── /app β†’ DeerFlow workspace (convenience alias) ─────
132
  location = /app {
133
  return 302 /workspace;
 
120
  proxy_read_timeout 600s;
121
  }
122
 
 
 
 
 
 
 
 
 
123
  # ── /app β†’ DeerFlow workspace (convenience alias) ─────
124
  location = /app {
125
  return 302 /workspace;