reorg: split into infra/ services/ history/ ideas/
This commit is contained in:
@@ -0,0 +1,341 @@
|
||||
# Traefik Migration Guide Using Docker Labels
|
||||
|
||||
## Overview
|
||||
Migrate from Zoraxy reverse proxy to Traefik using Docker labels for zero-touch service discovery.
|
||||
|
||||
---
|
||||
|
||||
## Phase 1: Install Traefik
|
||||
|
||||
### Step 1: Create Directory Structure
|
||||
```bash
|
||||
mkdir -p /opt/stacks/proxy/traefik/{config,dynamic,letsencrypt}
|
||||
```
|
||||
|
||||
### Step 2: Create docker-compose.yml
|
||||
```yaml
|
||||
version: "3.8"
|
||||
|
||||
services:
|
||||
traefik:
|
||||
image: traefik:v3.2
|
||||
container_name: traefik
|
||||
restart: always
|
||||
network_mode: host
|
||||
security_opt:
|
||||
- no-new-privileges=true
|
||||
ports:
|
||||
- "80:80"
|
||||
- "443:443"
|
||||
volumes:
|
||||
- /var/run/docker.sock:/var/run/docker.sock:ro
|
||||
- /opt/stacks/proxy/traefik/config:/etc/traefik
|
||||
- /opt/stacks/proxy/traefik/dynamic:/etc/traefik/dynamic
|
||||
- /opt/stacks/proxy/traefik/letsencrypt:/etc/letsencrypt
|
||||
command:
|
||||
- "--api.insecure=true"
|
||||
- "--providers.docker=true"
|
||||
- "--providers.docker.exposedbydefault=false"
|
||||
- "--providers.docker.network=ai-internal"
|
||||
- "--providers.docker.network=shared_backend"
|
||||
- "--providers.docker.defaultRule=Host(`{{ .Name }}.nuclide.systems`)"
|
||||
- "--entrypoints.web.address=:80"
|
||||
- "--entrypoints.websecure.address=:443"
|
||||
- "--certificatesresolvers.letsencrypt.acme.httpChallenge=true"
|
||||
- "--certificatesresolvers.letsencrypt.acme.email=admin@nuclide.systems"
|
||||
- "--certificatesresolvers.letsencrypt.acme.storage=/etc/letsencrypt/acme.json"
|
||||
```
|
||||
|
||||
### Step 3: Start Traefik
|
||||
```bash
|
||||
cd /opt/stacks/proxy/traefik
|
||||
docker compose up -d
|
||||
|
||||
# Verify
|
||||
docker compose ps
|
||||
```
|
||||
|
||||
---
|
||||
|
||||
## Phase 2: Migrate AI Services
|
||||
|
||||
### AI Service Labels (Add to litellm, chat, mcp-compose.yml)
|
||||
|
||||
```yaml
|
||||
services:
|
||||
litellm:
|
||||
image: litellm
|
||||
labels:
|
||||
- "traefik.enable=true"
|
||||
- "traefik.http.routers.litellm.rule=Host(`litellm.nuclide.systems`)"
|
||||
- "traefik.http.routers.litellm.entrypoints=websecure"
|
||||
- "traefik.http.routers.litellm.tls=true"
|
||||
- "traefik.http.routers.litellm.tls.certresolver=letsencrypt"
|
||||
- "traefik.http.routers.litellm.priority=10"
|
||||
- "traefik.http.services.litellm.loadbalancer.server.port=14000"
|
||||
|
||||
chat:
|
||||
image: lobehub
|
||||
labels:
|
||||
- "traefik.enable=true"
|
||||
- "traefik.http.routers.chat.rule=Host(`chat.nuclide.systems`)"
|
||||
- "traefik.http.routers.chat.entrypoints=websecure"
|
||||
- "traefik.http.routers.chat.tls=true"
|
||||
- "traefik.http.routers.chat.tls.certresolver=letsencrypt"
|
||||
- "traefik.http.routers.chat.priority=10"
|
||||
- "traefik.http.services.chat.loadbalancer.server.port=14001"
|
||||
|
||||
mcp:
|
||||
image: mcp-gateway
|
||||
labels:
|
||||
- "traefik.enable=true"
|
||||
- "traefik.http.routers.mcp.rule=Host(`mcp.nuclide.systems`)"
|
||||
- "traefik.http.routers.mcp.entrypoints=websecure"
|
||||
- "traefik.http.routers.mcp.tls=true"
|
||||
- "traefik.http.routers.mcp.tls.certresolver=letsencrypt"
|
||||
- "traefik.http.routers.mcp.priority=10"
|
||||
- "traefik.http.services.mcp.loadbalancer.server.port=8080"
|
||||
```
|
||||
|
||||
---
|
||||
|
||||
## Phase 3: Migrate Garage S3
|
||||
|
||||
### Option A: Use Traefik Proxy
|
||||
```yaml
|
||||
services:
|
||||
garage-proxy:
|
||||
image: nginx:alpine
|
||||
labels:
|
||||
- "traefik.enable=true"
|
||||
- "traefik.http.routers.s3.rule=Host(`s3.nuclide.systems`)"
|
||||
- "traefik.http.routers.s3.entrypoints=websecure"
|
||||
- "traefik.http.routers.s3.tls=true"
|
||||
- "traefik.http.routers.s3.tls.certresolver=letsencrypt"
|
||||
- "traefik.http.services.s3.loadbalancer.server.port=10004"
|
||||
volumes:
|
||||
- garage-data:/data
|
||||
networks:
|
||||
- shared_backend
|
||||
```
|
||||
|
||||
### Option B: Keep Internal Garage Access
|
||||
```yaml
|
||||
services:
|
||||
# No proxy needed - access Garage via internal IP:10004
|
||||
garage:
|
||||
image: garageio/garage
|
||||
ports:
|
||||
- "3900:3900" # Internal only
|
||||
- "10004:10004" # Public via Traefik
|
||||
```
|
||||
|
||||
---
|
||||
|
||||
## Phase 4: Create Helper Scripts
|
||||
|
||||
### script 1: Add Service to Traefik
|
||||
```bash
|
||||
#!/bin/bash
|
||||
# /opt/stacks/scripts/add-traefik-service.sh
|
||||
|
||||
NAME=$1
|
||||
DOMAIN=$2
|
||||
PORT=$3
|
||||
|
||||
cat > /opt/stacks/proxy/traefik/dynamic/${NAME}.yml << EOF
|
||||
http:
|
||||
routers:
|
||||
${NAME}-router:
|
||||
rule: "Host(\`${DOMAIN}\`)"
|
||||
service: ${NAME}-service
|
||||
entrypoints:
|
||||
- websecure
|
||||
tls:
|
||||
certresolver: letsencrypt
|
||||
|
||||
services:
|
||||
${NAME}-service:
|
||||
loadBalancer:
|
||||
servers:
|
||||
- url: "http://192.168.1.40:${PORT}"
|
||||
EOF
|
||||
|
||||
# Reload Traefik docker automatically (no manual step needed)
|
||||
echo "✅ Service ${NAME} added via labels"
|
||||
```
|
||||
|
||||
Usage:
|
||||
```bash
|
||||
/opt/stacks/scripts/add-traefik-service.sh myservice myservice.nuclide.systems 8000
|
||||
```
|
||||
|
||||
### Script 2: Generate Labels for Existing Services
|
||||
```bash
|
||||
#!/bin/bash
|
||||
# /opt/stacks/scripts/traefik-labels-gen.sh
|
||||
|
||||
cat > /opt/stacks/proxy/traefik/labels.yaml << 'EOF'
|
||||
# Add these labels to service docker-compose.yml files
|
||||
|
||||
# LiteLLM
|
||||
services:
|
||||
litellm:
|
||||
labels:
|
||||
- "traefik.enable=true"
|
||||
- "traefik.http.routers.litellm.rule=Host(`litellm.nuclide.systems`)"
|
||||
- "traefik.http.routers.litellm.entrypoints=websecure"
|
||||
- "traefik.http.routers.litellm.tls=true"
|
||||
- "traefik.http.routers.litellm.tls.certresolver=letsencrypt"
|
||||
- "traefik.http.services.litellm.loadbalancer.server.port=14000"
|
||||
|
||||
# LobeHub Chat
|
||||
services:
|
||||
chat:
|
||||
labels:
|
||||
- "traefik.enable=true"
|
||||
- "traefik.http.routers.chat.rule=Host(`chat.nuclide.systems`)"
|
||||
- "traefik.http.routers.chat.entrypoints=websecure"
|
||||
- "traefik.http.routers.chat.tls=true"
|
||||
- "traefik.http.routers.chat.tls.certresolver=letsencrypt"
|
||||
- "traefik.http.services.chat.loadbalancer.server.port=14001"
|
||||
|
||||
# MCP Gateway
|
||||
services:
|
||||
mcp-gateway:
|
||||
labels:
|
||||
- "traefik.enable=true"
|
||||
- "traefik.http.routers.mcp.rule=Host(`mcp.nuclide.systems`)"
|
||||
- "traefik.http.routers.mcp.entrypoints=websecure"
|
||||
- "traefik.http.routers.mcp.tls=true"
|
||||
- "traefik.http.routers.mcp.tls.certresolver=letsencrypt"
|
||||
- "traefik.http.services.mcp.loadbalancer.server.port=8080"
|
||||
EOF
|
||||
|
||||
echo "✅ Labels saved to /opt/stacks/proxy/traefik/labels.yaml"
|
||||
```
|
||||
|
||||
Usage:
|
||||
```bash
|
||||
/opt/stacks/scripts/traefik-labels-gen.sh
|
||||
```
|
||||
|
||||
---
|
||||
|
||||
## Phase 5: Update Service Configs
|
||||
|
||||
### Update `/opt/stacks/ai/.env`
|
||||
```bash
|
||||
# OLD (Zoraxy):
|
||||
LITELLM_BASE_URL=https://litellm.nuclide.systems
|
||||
PROXY_BASE_URL=https://mcp.nuclide.systems
|
||||
|
||||
# NEW (Traefik) - same URLs, different backend:
|
||||
LITELLM_BASE_URL=https://litellm.nuclide.systems
|
||||
PROXY_BASE_URL=https://mcp.nuclide.systems
|
||||
CHATAI_BASE_URL=https://chat.nuclide.systems
|
||||
```
|
||||
|
||||
### Update `/opt/stacks/ai/litellm-config/config.yaml`
|
||||
```yaml
|
||||
general_settings:
|
||||
proxy_base_url: https://litellm.nuclide.systems
|
||||
control_plane_url: https://litellm.nuclide.systems
|
||||
```
|
||||
|
||||
---
|
||||
|
||||
## Phase 6: Verify SSL
|
||||
|
||||
### Step 1: Generate Let's Encrypt Certificates
|
||||
```bash
|
||||
# Verify Traefik is running
|
||||
docker compose ps traefik
|
||||
|
||||
# Create ACME cert file
|
||||
touch /opt/stacks/proxy/traefik/letsencrypt/acme.json
|
||||
chmod 600 /opt/stacks/proxy/traefik/letsencrypt/acme.json
|
||||
|
||||
# Trigger certificate generation (will happen automatically)
|
||||
# Check status:
|
||||
curl -s https://acme-v02.api.letsencrypt.org/directory | head
|
||||
```
|
||||
|
||||
### Step 2: Test HTTPS
|
||||
```bash
|
||||
# Test endpoints
|
||||
curl -k https://litellm.nuclide.systems/health
|
||||
curl -k https://chat.nuclide.systems/health
|
||||
curl -k https://mcp.nuclide.systems/health
|
||||
|
||||
# Verify cert
|
||||
curl -v https://litellm.nuclide.systems 2>&1 | grep -A 5 "SSL certificate"
|
||||
```
|
||||
|
||||
---
|
||||
|
||||
## Phase 7: Remove Zoraxy
|
||||
|
||||
### Backup first
|
||||
```bash
|
||||
# Backup Zoraxy configs
|
||||
docker cp zoraxy:/data/configs /backup/zoraxy-backup/
|
||||
|
||||
# Optional: Stop Zoraxy
|
||||
docker stop zoraxy
|
||||
docker rm zoraxy
|
||||
```
|
||||
|
||||
---
|
||||
|
||||
## Quick Migration Checklist
|
||||
|
||||
- [ ] Install Traefik (Phase 1)
|
||||
- [ ] Add labels to AI services (Phase 2)
|
||||
- [ ] Add Garage S3 proxy (Phase 3)
|
||||
- [ ] Run label generation script (Phase 4)
|
||||
- [ ] Update `.env` and config files (Phase 5)
|
||||
- [ ] Wait for SSL certificates (auto 24-48h)
|
||||
- [ ] Test all HTTPS endpoints
|
||||
- [ ] Remove Zoraxy (Phase 7)
|
||||
- [ ] Update AdGuard DNS if needed (optional)
|
||||
|
||||
---
|
||||
|
||||
## Monitoring & Troubleshooting
|
||||
|
||||
### Check Traefik Dashboard
|
||||
```bash
|
||||
# Access web UI (unsecured - use only on trusted network)
|
||||
open http://192.168.1.40:8080/dashboard
|
||||
|
||||
# View all routers
|
||||
curl http://localhost:8080/api/http/routers | jq '.[] | {name: .rule, status: .entryPoints}'
|
||||
|
||||
# View all services
|
||||
curl http://localhost:8080/api/http/services | jq '.[] | {name: .name, servers: .servers}'
|
||||
```
|
||||
|
||||
### Common Issues
|
||||
|
||||
| Issue | Solution |
|
||||
|-------|----------|
|
||||
| 404 errors | Check router labels match domain exactly |
|
||||
| SSL expired | Wait for auto-renew or trigger manually |
|
||||
| Port mismatch | Verify `loadbalancer.server.port` matches service |
|
||||
| No SSL cert | Check email in `acme.json` config |
|
||||
|
||||
---
|
||||
|
||||
## Rollback Plan (If Needed)
|
||||
|
||||
```bash
|
||||
# Stop Traefik
|
||||
docker compose -f /opt/stacks/proxy/traefik/docker-compose.yml down
|
||||
|
||||
# Restore Zoraxy configs
|
||||
docker cp /backup/zoraxy-backup/ configs/
|
||||
|
||||
# Restart Zoraxy (if you kept backup)
|
||||
docker start zoraxy || true
|
||||
```
|
||||
Reference in New Issue
Block a user