first
This commit is contained in:
32
infra/.env.example
Normal file
32
infra/.env.example
Normal file
@@ -0,0 +1,32 @@
|
||||
# Created by: Claude
|
||||
# Date: 2026-01-01
|
||||
# Purpose: Environment variables template for Mesh infrastructure
|
||||
# Refs: deployment.md
|
||||
|
||||
# Mesh Server
|
||||
MESH_PUBLIC_URL=http://localhost:8000
|
||||
MESH_JWT_SECRET=your-secret-key-change-this-in-production-min-32-chars
|
||||
|
||||
# Gotify (serveur externe sur le réseau)
|
||||
# Remplacer par l'URL de votre serveur Gotify
|
||||
GOTIFY_URL=http://gotify.local:8080
|
||||
GOTIFY_TOKEN=your-gotify-token-get-from-gotify-ui
|
||||
# GOTIFY_DEFAULTUSER_NAME=admin # Non utilisé si Gotify externe
|
||||
# GOTIFY_DEFAULTUSER_PASS=adminadmin # Non utilisé si Gotify externe
|
||||
|
||||
# TURN Server
|
||||
TURN_EXTERNAL_IP=127.0.0.1
|
||||
TURN_REALM=mesh.local
|
||||
TURN_HOST=coturn
|
||||
TURN_PORT=3478
|
||||
TURN_USER=mesh
|
||||
TURN_PASS=changeThis123
|
||||
|
||||
# STUN
|
||||
STUN_URL=stun:stun.l.google.com:19302
|
||||
|
||||
# Database
|
||||
DATABASE_URL=sqlite:///./mesh.db
|
||||
|
||||
# Logging
|
||||
LOG_LEVEL=INFO
|
||||
389
infra/CLAUDE.md
Normal file
389
infra/CLAUDE.md
Normal file
@@ -0,0 +1,389 @@
|
||||
# CLAUDE.md — Mesh Infrastructure
|
||||
|
||||
This file provides infrastructure-specific guidance for Mesh deployment and operations.
|
||||
|
||||
## Infrastructure Role
|
||||
|
||||
The infrastructure layer provides:
|
||||
- **Docker containers** for all services
|
||||
- **Reverse proxy** with TLS termination
|
||||
- **TURN server** for NAT traversal fallback
|
||||
- **Gotify** for notifications
|
||||
- **Monitoring** and logging (optional)
|
||||
|
||||
## Components
|
||||
|
||||
### Mesh Server
|
||||
- FastAPI application
|
||||
- WebSocket support
|
||||
- Database (SQLite or PostgreSQL)
|
||||
- Health check endpoint
|
||||
|
||||
### Coturn (TURN Server)
|
||||
- NAT traversal fallback for WebRTC
|
||||
- Temporary credentials
|
||||
- Rate limiting and quotas
|
||||
- Ports: 3478 (UDP/TCP), 49160-49200 (UDP range)
|
||||
|
||||
### Gotify
|
||||
- Push notification server
|
||||
- Web UI on port 80/443
|
||||
- Volume for persistent data
|
||||
|
||||
### Reverse Proxy (Caddy or Nginx)
|
||||
- TLS termination
|
||||
- HTTP to HTTPS redirect
|
||||
- WebSocket upgrade support
|
||||
- Static file serving for client
|
||||
|
||||
## Directory Structure
|
||||
|
||||
```
|
||||
infra/
|
||||
├── docker-compose.yml # Production compose file
|
||||
├── docker-compose.dev.yml # Development compose file
|
||||
├── .env.example # Environment variables template
|
||||
├── nginx/
|
||||
│ ├── nginx.conf # Nginx configuration
|
||||
│ └── ssl/ # SSL certificates
|
||||
├── caddy/
|
||||
│ └── Caddyfile # Caddy configuration
|
||||
└── CLAUDE.md
|
||||
```
|
||||
|
||||
## Environment Variables
|
||||
|
||||
Create `.env` file in `infra/` directory:
|
||||
|
||||
```bash
|
||||
# Mesh Server
|
||||
MESH_PUBLIC_URL=https://mesh.example.com
|
||||
MESH_JWT_SECRET=your-secret-key-change-this
|
||||
MESH_JWT_ALGORITHM=HS256
|
||||
MESH_JWT_ACCESS_TOKEN_EXPIRE_MINUTES=120
|
||||
|
||||
# Gotify
|
||||
GOTIFY_URL=https://gotify.example.com
|
||||
GOTIFY_TOKEN=your-gotify-token
|
||||
GOTIFY_DEFAULTUSER_NAME=admin
|
||||
GOTIFY_DEFAULTUSER_PASS=change-this-password
|
||||
|
||||
# TURN Server
|
||||
TURN_HOST=turn.example.com
|
||||
TURN_PORT=3478
|
||||
TURN_EXTERNAL_IP=your-server-public-ip
|
||||
TURN_REALM=mesh.example.com
|
||||
TURN_USER=mesh
|
||||
TURN_PASS=change-this-password
|
||||
|
||||
# STUN
|
||||
STUN_URL=stun:stun.l.google.com:19302
|
||||
|
||||
# Database
|
||||
DATABASE_URL=sqlite:///./mesh.db
|
||||
# Or for PostgreSQL:
|
||||
# DATABASE_URL=postgresql://user:pass@postgres:5432/mesh
|
||||
|
||||
# Logging
|
||||
LOG_LEVEL=INFO
|
||||
```
|
||||
|
||||
## Docker Compose
|
||||
|
||||
### Development
|
||||
|
||||
```bash
|
||||
cd infra
|
||||
cp .env.example .env
|
||||
# Edit .env
|
||||
docker-compose -f docker-compose.dev.yml up -d
|
||||
```
|
||||
|
||||
### Production
|
||||
|
||||
```bash
|
||||
cd infra
|
||||
cp .env.example .env
|
||||
# Edit .env with production values
|
||||
docker-compose up -d
|
||||
```
|
||||
|
||||
## Network Ports
|
||||
|
||||
**Required open ports**:
|
||||
- 80/tcp - HTTP (redirect to HTTPS)
|
||||
- 443/tcp - HTTPS (web client + API)
|
||||
- 3478/tcp - TURN (TCP mode)
|
||||
- 3478/udp - TURN (UDP mode)
|
||||
- 49160-49200/udp - TURN relay range
|
||||
|
||||
**Optional**:
|
||||
- 8080/tcp - Gotify web UI (if exposed separately)
|
||||
|
||||
## Reverse Proxy Configuration
|
||||
|
||||
### Caddy (Recommended)
|
||||
|
||||
```
|
||||
mesh.example.com {
|
||||
reverse_proxy /api/* mesh-server:8000
|
||||
reverse_proxy /ws mesh-server:8000
|
||||
reverse_proxy /health mesh-server:8000
|
||||
|
||||
root * /var/www/mesh-client
|
||||
file_server
|
||||
try_files {path} /index.html
|
||||
}
|
||||
|
||||
gotify.example.com {
|
||||
reverse_proxy gotify:80
|
||||
}
|
||||
```
|
||||
|
||||
### Nginx
|
||||
|
||||
```nginx
|
||||
server {
|
||||
listen 443 ssl http2;
|
||||
server_name mesh.example.com;
|
||||
|
||||
ssl_certificate /etc/nginx/ssl/cert.pem;
|
||||
ssl_certificate_key /etc/nginx/ssl/key.pem;
|
||||
|
||||
# API endpoints
|
||||
location /api/ {
|
||||
proxy_pass http://mesh-server:8000;
|
||||
proxy_http_version 1.1;
|
||||
proxy_set_header Upgrade $http_upgrade;
|
||||
proxy_set_header Connection 'upgrade';
|
||||
proxy_set_header Host $host;
|
||||
proxy_cache_bypass $http_upgrade;
|
||||
}
|
||||
|
||||
# WebSocket
|
||||
location /ws {
|
||||
proxy_pass http://mesh-server:8000;
|
||||
proxy_http_version 1.1;
|
||||
proxy_set_header Upgrade $http_upgrade;
|
||||
proxy_set_header Connection 'upgrade';
|
||||
proxy_set_header Host $host;
|
||||
proxy_cache_bypass $http_upgrade;
|
||||
}
|
||||
|
||||
# Client static files
|
||||
location / {
|
||||
root /var/www/mesh-client;
|
||||
try_files $uri /index.html;
|
||||
}
|
||||
}
|
||||
```
|
||||
|
||||
## SSL/TLS Certificates
|
||||
|
||||
### Let's Encrypt (Recommended)
|
||||
|
||||
**With Caddy**: Automatic
|
||||
|
||||
**With Nginx + Certbot**:
|
||||
```bash
|
||||
certbot --nginx -d mesh.example.com -d gotify.example.com
|
||||
```
|
||||
|
||||
### Self-Signed (Development Only)
|
||||
|
||||
```bash
|
||||
openssl req -x509 -nodes -days 365 -newkey rsa:2048 \
|
||||
-keyout infra/nginx/ssl/key.pem \
|
||||
-out infra/nginx/ssl/cert.pem
|
||||
```
|
||||
|
||||
## TURN Server Configuration
|
||||
|
||||
Coturn configuration for NAT traversal:
|
||||
|
||||
```bash
|
||||
# In docker-compose.yml, coturn command:
|
||||
-n # Use config from CLI
|
||||
--log-file=stdout # Log to stdout
|
||||
--external-ip=${TURN_EXTERNAL_IP}
|
||||
--realm=${TURN_REALM}
|
||||
--user=${TURN_USER}:${TURN_PASS}
|
||||
--listening-port=3478
|
||||
--min-port=49160
|
||||
--max-port=49200
|
||||
--fingerprint
|
||||
--lt-cred-mech
|
||||
--no-multicast-peers
|
||||
--no-cli
|
||||
```
|
||||
|
||||
**Important**:
|
||||
- Monitor TURN bandwidth usage
|
||||
- Implement rate limiting
|
||||
- Use temporary credentials (V1+)
|
||||
- TURN should be fallback only, not primary
|
||||
|
||||
## Database
|
||||
|
||||
### SQLite (Development)
|
||||
|
||||
Default option, file-based:
|
||||
```
|
||||
DATABASE_URL=sqlite:///./mesh.db
|
||||
```
|
||||
|
||||
Data persists in volume: `mesh_db`
|
||||
|
||||
### PostgreSQL (Production Recommended)
|
||||
|
||||
Add to docker-compose.yml:
|
||||
```yaml
|
||||
postgres:
|
||||
image: postgres:16
|
||||
environment:
|
||||
POSTGRES_USER: mesh
|
||||
POSTGRES_PASSWORD: ${POSTGRES_PASSWORD}
|
||||
POSTGRES_DB: mesh
|
||||
volumes:
|
||||
- postgres_data:/var/lib/postgresql/data
|
||||
restart: unless-stopped
|
||||
|
||||
volumes:
|
||||
postgres_data:
|
||||
```
|
||||
|
||||
Update DATABASE_URL:
|
||||
```
|
||||
DATABASE_URL=postgresql://mesh:${POSTGRES_PASSWORD}@postgres:5432/mesh
|
||||
```
|
||||
|
||||
## Monitoring & Logging
|
||||
|
||||
### Logs
|
||||
|
||||
View service logs:
|
||||
```bash
|
||||
docker-compose logs -f mesh-server
|
||||
docker-compose logs -f coturn
|
||||
docker-compose logs -f gotify
|
||||
```
|
||||
|
||||
### Health Checks
|
||||
|
||||
Mesh Server health:
|
||||
```bash
|
||||
curl https://mesh.example.com/health
|
||||
```
|
||||
|
||||
Expected response:
|
||||
```json
|
||||
{"status": "healthy"}
|
||||
```
|
||||
|
||||
### Metrics (V2)
|
||||
|
||||
Consider adding:
|
||||
- Prometheus for metrics collection
|
||||
- Grafana for visualization
|
||||
- Alert manager for notifications
|
||||
|
||||
## Backup Strategy
|
||||
|
||||
### Database Backup
|
||||
|
||||
**SQLite**:
|
||||
```bash
|
||||
docker exec mesh-server sqlite3 /app/mesh.db ".backup /app/backup.db"
|
||||
docker cp mesh-server:/app/backup.db ./backup-$(date +%Y%m%d).db
|
||||
```
|
||||
|
||||
**PostgreSQL**:
|
||||
```bash
|
||||
docker exec postgres pg_dump -U mesh mesh > backup-$(date +%Y%m%d).sql
|
||||
```
|
||||
|
||||
### Gotify Data
|
||||
|
||||
```bash
|
||||
docker cp gotify:/app/data ./gotify-backup-$(date +%Y%m%d)
|
||||
```
|
||||
|
||||
### Backup Schedule
|
||||
|
||||
Recommended:
|
||||
- Daily database backups
|
||||
- Weekly full backups
|
||||
- 30-day retention
|
||||
|
||||
## Security Checklist
|
||||
|
||||
- [ ] HTTPS with valid certificates
|
||||
- [ ] Strong JWT secret (32+ characters)
|
||||
- [ ] Firewall rules configured (only required ports open)
|
||||
- [ ] TURN credentials changed from defaults
|
||||
- [ ] Gotify admin password changed
|
||||
- [ ] Database credentials secured
|
||||
- [ ] Regular security updates (container images)
|
||||
- [ ] Logs rotated and retained appropriately
|
||||
- [ ] Rate limiting on auth endpoints
|
||||
- [ ] TURN bandwidth monitoring
|
||||
|
||||
## Scaling Considerations
|
||||
|
||||
**Current architecture**: Single server, 2-4 users
|
||||
|
||||
**If scaling needed**:
|
||||
- Load balancer for multiple server instances
|
||||
- Shared session store (Redis)
|
||||
- Separate database server
|
||||
- Multiple TURN servers (geographic distribution)
|
||||
|
||||
## Troubleshooting
|
||||
|
||||
### WebSocket Connection Failed
|
||||
|
||||
Check:
|
||||
1. Reverse proxy WebSocket upgrade headers
|
||||
2. Firewall allows WebSocket traffic
|
||||
3. Server logs for connection errors
|
||||
|
||||
### TURN Not Working
|
||||
|
||||
Check:
|
||||
1. UDP ports 3478 and 49160-49200 open
|
||||
2. External IP correctly configured
|
||||
3. Credentials valid
|
||||
4. Check coturn logs: `docker-compose logs coturn`
|
||||
|
||||
### File Upload/Download Slow
|
||||
|
||||
Agent QUIC connections bypass server. Check:
|
||||
1. Agent logs on both machines
|
||||
2. Firewall rules for UDP traffic
|
||||
3. NAT configuration
|
||||
4. Network latency between peers
|
||||
|
||||
### Database Connection Error
|
||||
|
||||
Check:
|
||||
1. DATABASE_URL format correct
|
||||
2. Database container running
|
||||
3. Database initialized (migrations run)
|
||||
4. Credentials valid
|
||||
|
||||
## Deployment Workflow
|
||||
|
||||
1. **Setup server** with Docker and docker-compose
|
||||
2. **Clone repository** to server
|
||||
3. **Configure environment** (copy and edit `.env`)
|
||||
4. **Build client** (`cd client && npm run build`)
|
||||
5. **Copy client dist** to reverse proxy volume
|
||||
6. **Start services** (`docker-compose up -d`)
|
||||
7. **Check health** endpoints
|
||||
8. **Configure DNS** (point domain to server)
|
||||
9. **Setup SSL** (Let's Encrypt or custom)
|
||||
10. **Test end-to-end** (login, join room, send message, call)
|
||||
|
||||
---
|
||||
|
||||
**Remember**: The infrastructure should be minimal. The server is control plane only - it never handles media or large data transfers.
|
||||
70
infra/docker-compose.dev.yml
Normal file
70
infra/docker-compose.dev.yml
Normal file
@@ -0,0 +1,70 @@
|
||||
# Created by: Claude
|
||||
# Date: 2026-01-01
|
||||
# Purpose: Docker Compose for Mesh development environment
|
||||
# Refs: deployment.md, infra/CLAUDE.md
|
||||
|
||||
#version: '3.8'
|
||||
|
||||
services:
|
||||
mesh-server:
|
||||
build:
|
||||
context: ../server
|
||||
dockerfile: Dockerfile
|
||||
environment:
|
||||
- MESH_PUBLIC_URL=${MESH_PUBLIC_URL:-http://localhost:8000}
|
||||
- MESH_HOST=0.0.0.0
|
||||
- MESH_PORT=8000
|
||||
- MESH_JWT_SECRET=${MESH_JWT_SECRET}
|
||||
- MESH_JWT_ALGORITHM=HS256
|
||||
- MESH_JWT_ACCESS_TOKEN_EXPIRE_MINUTES=120
|
||||
- GOTIFY_URL=${GOTIFY_URL}
|
||||
- GOTIFY_TOKEN=${GOTIFY_TOKEN}
|
||||
- STUN_URL=${STUN_URL:-stun:stun.l.google.com:19302}
|
||||
- TURN_HOST=${TURN_HOST:-coturn}
|
||||
- TURN_PORT=${TURN_PORT:-3478}
|
||||
- TURN_USER=${TURN_USER}
|
||||
- TURN_PASS=${TURN_PASS}
|
||||
- DATABASE_URL=${DATABASE_URL:-sqlite:////app/data/mesh.db}
|
||||
- LOG_LEVEL=${LOG_LEVEL:-INFO}
|
||||
ports:
|
||||
- "8000:8000"
|
||||
volumes:
|
||||
- mesh_db:/app/data
|
||||
restart: unless-stopped
|
||||
# depends_on:
|
||||
# - gotify # Gotify externe sur le réseau
|
||||
|
||||
coturn:
|
||||
image: coturn/coturn:latest
|
||||
command: >
|
||||
-n
|
||||
--log-file=stdout
|
||||
--external-ip=${TURN_EXTERNAL_IP:-127.0.0.1}
|
||||
--realm=${TURN_REALM:-mesh.local}
|
||||
--user=${TURN_USER:-mesh}:${TURN_PASS:-changeThis123}
|
||||
--listening-port=3478
|
||||
--min-port=49160
|
||||
--max-port=49200
|
||||
--fingerprint
|
||||
--lt-cred-mech
|
||||
--no-multicast-peers
|
||||
--no-cli
|
||||
network_mode: "host"
|
||||
restart: unless-stopped
|
||||
|
||||
# gotify:
|
||||
# # Service commenté - Gotify déjà disponible sur le réseau
|
||||
# # Configurer GOTIFY_URL et GOTIFY_TOKEN dans .env
|
||||
# image: gotify/server:latest
|
||||
# environment:
|
||||
# - GOTIFY_DEFAULTUSER_NAME=${GOTIFY_DEFAULTUSER_NAME:-admin}
|
||||
# - GOTIFY_DEFAULTUSER_PASS=${GOTIFY_DEFAULTUSER_PASS:-adminadmin}
|
||||
# ports:
|
||||
# - "8080:80"
|
||||
# volumes:
|
||||
# - gotify_data:/app/data
|
||||
# restart: unless-stopped
|
||||
|
||||
volumes:
|
||||
mesh_db:
|
||||
# gotify_data: # Non nécessaire si Gotify externe
|
||||
Reference in New Issue
Block a user