This commit is contained in:
Gilles Soulier
2026-01-05 13:13:08 +01:00
parent 8e14adafc6
commit 1d177e96a6
149 changed files with 29541 additions and 1 deletions

32
infra/.env.example Normal file
View 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
View 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.

View 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