cbf5200
commit cbf5200
1 file changed
+525 -0
Showing 1 changed file+525-0
βΌdocs/06-docker-self-hosting.md
+525-0
| @@ -0,0 +1,525 @@ | ||
1 | +# π³ Docker Self-Hosting Guide | |
2 | + | |
3 | +Run OpenGrammar locally with Docker and optional local LLM support (Ollama). | |
4 | + | |
5 | +--- | |
6 | + | |
7 | +## π― Why Self-Host with Docker? | |
8 | + | |
9 | +| Benefit | Description | | |
10 | +|---------|-------------| | |
11 | +| **Complete Privacy** | All data stays on your machine | | |
12 | +| **Free** | No API costs (with local LLM) | | |
13 | +| **Offline** | Works without internet | | |
14 | +| **Full Control** | Customize everything | | |
15 | +| **No Rate Limits** | Use as much as you want | | |
16 | + | |
17 | +--- | |
18 | + | |
19 | +## π Prerequisites | |
20 | + | |
21 | +- Docker (v20.10+) | |
22 | +- Docker Compose (usually included with Docker) | |
23 | +- 4GB+ RAM (for local LLM) | |
24 | +- NVIDIA GPU (optional, for faster LLM inference) | |
25 | + | |
26 | +--- | |
27 | + | |
28 | +## π Quick Start | |
29 | + | |
30 | +### Option 1: Backend Only (Use Cloud APIs) | |
31 | + | |
32 | +```bash | |
33 | +cd opengrammar/opengrammar | |
34 | + | |
35 | +# Create environment file | |
36 | +cat > .env << EOF | |
37 | +PORT=8787 | |
38 | +NODE_ENV=production | |
39 | +GROQ_API_KEY=your_groq_key | |
40 | +OPENAI_API_KEY=your_openai_key | |
41 | +EOF | |
42 | + | |
43 | +# Start backend | |
44 | +docker-compose up -d opengrammar-backend | |
45 | + | |
46 | +# Check status | |
47 | +docker-compose ps | |
48 | + | |
49 | +# View logs | |
50 | +docker-compose logs -f opengrammar-backend | |
51 | +``` | |
52 | + | |
53 | +### Option 2: Backend + Ollama (Local LLM) | |
54 | + | |
55 | +```bash | |
56 | +cd opengrammar/opengrammar | |
57 | + | |
58 | +# Start everything (requires NVIDIA GPU) | |
59 | +docker-compose --profile local-llm up -d | |
60 | + | |
61 | +# Check status | |
62 | +docker-compose ps | |
63 | + | |
64 | +# View all logs | |
65 | +docker-compose logs -f | |
66 | +``` | |
67 | + | |
68 | +--- | |
69 | + | |
70 | +## π§ Docker Compose Configuration | |
71 | + | |
72 | +### Complete docker-compose.yml | |
73 | + | |
74 | +```yaml | |
75 | +version: '3.8' | |
76 | + | |
77 | +services: | |
78 | + # OpenGrammar Backend | |
79 | + opengrammar-backend: | |
80 | + build: | |
81 | + context: ./backend | |
82 | + dockerfile: Dockerfile | |
83 | + container_name: opengrammar-backend | |
84 | + restart: unless-stopped | |
85 | + ports: | |
86 | + - "8787:8787" | |
87 | + environment: | |
88 | + - NODE_ENV=production | |
89 | + - PORT=8787 | |
90 | + - GROQ_API_KEY=${GROQ_API_KEY:-} | |
91 | + - OPENAI_API_KEY=${OPENAI_API_KEY:-} | |
92 | + - OPENROUTER_API_KEY=${OPENROUTER_API_KEY:-} | |
93 | + - TOGETHER_API_KEY=${TOGETHER_API_KEY:-} | |
94 | + - OLLAMA_BASE_URL=${OLLAMA_BASE_URL:-http://ollama:11434/v1} | |
95 | + - DEBUG=${DEBUG:-false} | |
96 | + healthcheck: | |
97 | + test: ["CMD", "curl", "-f", "http://localhost:8787/health"] | |
98 | + interval: 30s | |
99 | + timeout: 10s | |
100 | + retries: 3 | |
101 | + start_period: 40s | |
102 | + networks: | |
103 | + - opengrammar-network | |
104 | + depends_on: | |
105 | + - ollama | |
106 | + volumes: | |
107 | + - ./backend/logs:/app/logs | |
108 | + | |
109 | + # Ollama (Local LLM) | |
110 | + ollama: | |
111 | + image: ollama/ollama:latest | |
112 | + container_name: opengrammar-ollama | |
113 | + restart: unless-stopped | |
114 | + profiles: | |
115 | + - local-llm | |
116 | + ports: | |
117 | + - "11434:11434" | |
118 | + volumes: | |
119 | + - ollama_data:/root/.ollama | |
120 | + networks: | |
121 | + - opengrammar-network | |
122 | + deploy: | |
123 | + resources: | |
124 | + reservations: | |
125 | + devices: | |
126 | + - driver: nvidia | |
127 | + count: all | |
128 | + capabilities: [gpu] | |
129 | + | |
130 | + # Open WebUI (Optional - for testing Ollama) | |
131 | + open-webui: | |
132 | + image: ghcr.io/open-webui/open-webui:main | |
133 | + container_name: opengrammar-webui | |
134 | + restart: unless-stopped | |
135 | + profiles: | |
136 | + - local-llm | |
137 | + ports: | |
138 | + - "3000:8080" | |
139 | + environment: | |
140 | + - OLLAMA_BASE_URL=http://ollama:11434 | |
141 | + networks: | |
142 | + - opengrammar-network | |
143 | + depends_on: | |
144 | + - ollama | |
145 | + volumes: | |
146 | + - open-webui_data:/app/backend/data | |
147 | + | |
148 | +networks: | |
149 | + opengrammar-network: | |
150 | + driver: bridge | |
151 | + | |
152 | +volumes: | |
153 | + ollama_data: | |
154 | + open-webui_data: | |
155 | +``` | |
156 | + | |
157 | +--- | |
158 | + | |
159 | +## π€ Local LLM Setup with Ollama | |
160 | + | |
161 | +### Step 1: Start Ollama Container | |
162 | + | |
163 | +```bash | |
164 | +docker-compose --profile local-llm up -d ollama | |
165 | +``` | |
166 | + | |
167 | +### Step 2: Pull Grammar-Focused Models | |
168 | + | |
169 | +```bash | |
170 | +# Enter Ollama container | |
171 | +docker exec -it opengrammar-ollama bash | |
172 | + | |
173 | +# Pull models (inside container) | |
174 | +ollama pull qwen2.5:0.5b # Ultra fast, 400MB | |
175 | +ollama pull qwen2.5:1.5b # Balanced, 1GB | |
176 | +ollama pull phi4-mini:3.8b # Great quality, 2.5GB | |
177 | +ollama pull llama3.2:3b # Good all-rounder, 2GB | |
178 | + | |
179 | +# Exit container | |
180 | +exit | |
181 | +``` | |
182 | + | |
183 | +### Step 3: Test Ollama | |
184 | + | |
185 | +```bash | |
186 | +# Test from host | |
187 | +curl http://localhost:11434/api/tags | |
188 | + | |
189 | +# Test model | |
190 | +curl http://localhost:11434/api/generate -d '{ | |
191 | + "model": "qwen2.5:1.5b", | |
192 | + "prompt": "Fix this grammar: me and him went to store" | |
193 | +}' | |
194 | +``` | |
195 | + | |
196 | +### Step 4: Configure OpenGrammar | |
197 | + | |
198 | +1. Click extension icon β Settings | |
199 | +2. Provider: **Ollama (Local)** | |
200 | +3. Base URL: `http://localhost:11434/v1` | |
201 | +4. Model: `qwen2.5:1.5b` | |
202 | +5. API Key: (leave empty) | |
203 | +6. Backend URL: `http://localhost:8787` | |
204 | + | |
205 | +--- | |
206 | + | |
207 | +## π― Model Recommendations | |
208 | + | |
209 | +### For Grammar Checking | |
210 | + | |
211 | +| Model | Size | RAM | Speed | Quality | Best For | | |
212 | +|-------|------|-----|-------|---------|----------| | |
213 | +| **qwen2.5:0.5b** | 400MB | 1GB | β‘β‘β‘β‘β‘ | βββ | Fast basic checks | | |
214 | +| **qwen2.5:1.5b** | 1GB | 2GB | β‘β‘β‘β‘ | ββββ | Balanced | | |
215 | +| **phi4-mini:3.8b** | 2.5GB | 4GB | β‘β‘β‘ | βββββ | Best quality | | |
216 | +| **llama3.2:3b** | 2GB | 3GB | β‘β‘β‘β‘ | ββββ | Good balance | | |
217 | + | |
218 | +### For GPU Acceleration | |
219 | + | |
220 | +If you have an NVIDIA GPU: | |
221 | + | |
222 | +```bash | |
223 | +# High quality with GPU | |
224 | +ollama pull llama3.2:7b # 4GB, requires 8GB+ GPU | |
225 | +ollama pull mistral:7b # 4GB, requires 8GB+ GPU | |
226 | +ollama pull mixtral:8x7b # 26GB, requires 24GB+ GPU | |
227 | +``` | |
228 | + | |
229 | +--- | |
230 | + | |
231 | +## π§ Advanced Configuration | |
232 | + | |
233 | +### Custom Backend Port | |
234 | + | |
235 | +```yaml | |
236 | +# docker-compose.yml | |
237 | +ports: | |
238 | + - "9000:8787" # Change 8787 to 9000 | |
239 | +``` | |
240 | + | |
241 | +### Enable GPU Support | |
242 | + | |
243 | +```yaml | |
244 | +# For NVIDIA GPUs | |
245 | +ollama: | |
246 | + deploy: | |
247 | + resources: | |
248 | + reservations: | |
249 | + devices: | |
250 | + - driver: nvidia | |
251 | + count: all | |
252 | + capabilities: [gpu] | |
253 | +``` | |
254 | + | |
255 | +### Persistent Logs | |
256 | + | |
257 | +```yaml | |
258 | +opengrammar-backend: | |
259 | + volumes: | |
260 | + - ./logs:/app/logs | |
261 | +``` | |
262 | + | |
263 | +### Network Isolation | |
264 | + | |
265 | +```yaml | |
266 | +networks: | |
267 | + opengrammar-network: | |
268 | + driver: bridge | |
269 | + ipam: | |
270 | + config: | |
271 | + - subnet: 172.28.0.0/16 | |
272 | +``` | |
273 | + | |
274 | +--- | |
275 | + | |
276 | +## π Performance Benchmarks | |
277 | + | |
278 | +### Local LLM (RTX 4090) | |
279 | + | |
280 | +| Model | Tokens/sec | Grammar Accuracy | RAM | VRAM | | |
281 | +|-------|------------|------------------|-----|------| | |
282 | +| qwen2.5:0.5b | ~100 | 75% | 1GB | 1GB | | |
283 | +| qwen2.5:1.5b | ~80 | 82% | 2GB | 2GB | | |
284 | +| phi4-mini:3.8b | ~50 | 88% | 4GB | 4GB | | |
285 | +| llama3.2:7b | ~30 | 90% | 8GB | 8GB | | |
286 | + | |
287 | +### Cloud APIs (via Docker) | |
288 | + | |
289 | +| Model | Latency | Grammar Accuracy | Cost/1K requests | | |
290 | +|-------|---------|------------------|------------------| | |
291 | +| gpt-4o-mini | ~1s | 95% | $0.15 | | |
292 | +| llama-3.1-70b (Groq) | ~200ms | 92% | Free (tier) | | |
293 | +| claude-3.5-sonnet | ~2s | 96% | $3.00 | | |
294 | + | |
295 | +--- | |
296 | + | |
297 | +## π‘οΈ Security Considerations | |
298 | + | |
299 | +### 1. Network Isolation | |
300 | +```yaml | |
301 | +networks: | |
302 | + opengrammar-network: | |
303 | + internal: true # No external access | |
304 | +``` | |
305 | + | |
306 | +### 2. Environment Variables | |
307 | +Never commit `.env` file: | |
308 | +```bash | |
309 | +echo ".env" >> .gitignore | |
310 | +``` | |
311 | + | |
312 | +### 3. API Key Rotation | |
313 | +```bash | |
314 | +# Generate new keys periodically | |
315 | +openssl rand -hex 32 | |
316 | +``` | |
317 | + | |
318 | +### 4. Container Security | |
319 | +```yaml | |
320 | +security_opt: | |
321 | + - no-new-privileges:true | |
322 | +read_only: true | |
323 | +tmpfs: | |
324 | + - /tmp | |
325 | +``` | |
326 | + | |
327 | +--- | |
328 | + | |
329 | +## π Monitoring & Maintenance | |
330 | + | |
331 | +### View Logs | |
332 | +```bash | |
333 | +# All services | |
334 | +docker-compose logs -f | |
335 | + | |
336 | +# Specific service | |
337 | +docker-compose logs -f opengrammar-backend | |
338 | + | |
339 | +# Last 100 lines | |
340 | +docker-compose logs --tail=100 opengrammar-backend | |
341 | +``` | |
342 | + | |
343 | +### Check Health | |
344 | +```bash | |
345 | +# Backend health | |
346 | +curl http://localhost:8787/health | |
347 | + | |
348 | +# Ollama status | |
349 | +curl http://localhost:11434/api/tags | |
350 | + | |
351 | +# Container status | |
352 | +docker-compose ps | |
353 | +``` | |
354 | + | |
355 | +### Update Containers | |
356 | +```bash | |
357 | +# Pull latest images | |
358 | +docker-compose pull | |
359 | + | |
360 | +# Recreate containers | |
361 | +docker-compose up -d --force-recreate | |
362 | + | |
363 | +# Clean up old images | |
364 | +docker image prune -f | |
365 | +``` | |
366 | + | |
367 | +### Backup Data | |
368 | +```bash | |
369 | +# Backup Ollama models | |
370 | +docker run --rm \ | |
371 | + -v opengrammar_ollama_data:/data \ | |
372 | + -v $(pwd)/backup:/backup \ | |
373 | + alpine tar czf /backup/ollama-backup.tar.gz /data | |
374 | + | |
375 | +# Backup settings | |
376 | +docker-compose exec opengrammar-backend \ | |
377 | + cat /app/data/settings.json > backup-settings.json | |
378 | +``` | |
379 | + | |
380 | +--- | |
381 | + | |
382 | +## π Troubleshooting | |
383 | + | |
384 | +### Container Won't Start | |
385 | +```bash | |
386 | +# Check logs | |
387 | +docker-compose logs opengrammar-backend | |
388 | + | |
389 | +# Test configuration | |
390 | +docker-compose config | |
391 | + | |
392 | +# Check port conflict | |
393 | +lsof -i :8787 | |
394 | +lsof -i :11434 | |
395 | +``` | |
396 | + | |
397 | +### Ollama Connection Failed | |
398 | +```bash | |
399 | +# Check Ollama is running | |
400 | +docker-compose ps ollama | |
401 | + | |
402 | +# Test connection | |
403 | +docker-compose exec opengrammar-backend curl http://ollama:11434/api/tags | |
404 | + | |
405 | +# Restart Ollama | |
406 | +docker-compose restart ollama | |
407 | +``` | |
408 | + | |
409 | +### GPU Not Working | |
410 | +```bash | |
411 | +# Check NVIDIA Container Toolkit | |
412 | +nvidia-container-cli info | |
413 | + | |
414 | +# Verify GPU access | |
415 | +docker exec -it opengrammar-ollama nvidia-smi | |
416 | + | |
417 | +# Update Docker Compose | |
418 | +docker-compose version | |
419 | +``` | |
420 | + | |
421 | +### High Memory Usage | |
422 | +```bash | |
423 | +# Check container memory | |
424 | +docker stats | |
425 | + | |
426 | +# Limit Ollama memory | |
427 | +ollama: | |
428 | + deploy: | |
429 | + resources: | |
430 | + limits: | |
431 | + memory: 4G | |
432 | +``` | |
433 | + | |
434 | +### Slow Performance | |
435 | +```bash | |
436 | +# Check CPU usage | |
437 | +docker stats | |
438 | + | |
439 | +# Use smaller model | |
440 | +ollama pull qwen2.5:0.5b | |
441 | + | |
442 | +# Enable GPU (if available) | |
443 | +# See GPU configuration above | |
444 | +``` | |
445 | + | |
446 | +--- | |
447 | + | |
448 | +## π Production Deployment | |
449 | + | |
450 | +### Docker Swarm | |
451 | + | |
452 | +```yaml | |
453 | +# docker-stack.yml | |
454 | +version: '3.8' | |
455 | + | |
456 | +services: | |
457 | + opengrammar-backend: | |
458 | + image: opengrammar-backend:latest | |
459 | + ports: | |
460 | + - "8787:8787" | |
461 | + environment: | |
462 | + - NODE_ENV=production | |
463 | + deploy: | |
464 | + replicas: 3 | |
465 | + resources: | |
466 | + limits: | |
467 | + cpus: '1' | |
468 | + memory: 512M | |
469 | + healthcheck: | |
470 | + test: ["CMD", "curl", "-f", "http://localhost:8787/health"] | |
471 | + interval: 30s | |
472 | + timeout: 10s | |
473 | + retries: 3 | |
474 | +``` | |
475 | + | |
476 | +Deploy: | |
477 | +```bash | |
478 | +docker stack deploy -c docker-stack.yml opengrammar | |
479 | +``` | |
480 | + | |
481 | +### Kubernetes | |
482 | + | |
483 | +```yaml | |
484 | +# k8s/deployment.yaml | |
485 | +apiVersion: apps/v1 | |
486 | +kind: Deployment | |
487 | +metadata: | |
488 | + name: opengrammar-backend | |
489 | +spec: | |
490 | + replicas: 3 | |
491 | + selector: | |
492 | + matchLabels: | |
493 | + app: opengrammar-backend | |
494 | + template: | |
495 | + metadata: | |
496 | + labels: | |
497 | + app: opengrammar-backend | |
498 | + spec: | |
499 | + containers: | |
500 | + - name: backend | |
501 | + image: opengrammar-backend:latest | |
502 | + ports: | |
503 | + - containerPort: 8787 | |
504 | + env: | |
505 | + - name: NODE_ENV | |
506 | + value: "production" | |
507 | + livenessProbe: | |
508 | + httpGet: | |
509 | + path: /health | |
510 | + port: 8787 | |
511 | + initialDelaySeconds: 30 | |
512 | + periodSeconds: 10 | |
513 | +``` | |
514 | + | |
515 | +--- | |
516 | + | |
517 | +## π Related Documentation | |
518 | + | |
519 | +- [Backend Deployment](05-backend-deployment.md) - Cloud deployment options | |
520 | +- [AI Provider Setup](07-ai-providers.md) - Configure AI providers | |
521 | +- [Troubleshooting](18-troubleshooting.md) - Common issues | |
522 | + | |
523 | +--- | |
524 | + | |
525 | +**Your self-hosted OpenGrammar instance is ready! Happy writing! β¨** | |
0 | 526 | |