# 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.