From 1ca195607ec6aa72534154db1b070bf390b8c1b6 Mon Sep 17 00:00:00 2001 From: Ryan Malloy Date: Wed, 17 Sep 2025 07:21:53 -0600 Subject: [PATCH] Add comprehensive caddy-docker-proxy integration with auto-labeling - Reference caddy-docker-proxy GitHub project for automatic HTTPS - Provide complete production-ready docker-compose.yml with Cloudflare DNS - Add environment configuration (.env) and deployment instructions - Document --transport http-streamable auto-labeling feature - Show how auto-labeling eliminates manual caddy configuration - Include simplified deployment with environment-based detection - Add benefits of streaming mode: SSE, real-time monitoring, zero config - Provide step-by-step production deployment example --- README.md | 261 +++++++++++++++++++++++++++++++++++++++++++++--------- 1 file changed, 219 insertions(+), 42 deletions(-) diff --git a/README.md b/README.md index 39869a1..0789a04 100644 --- a/README.md +++ b/README.md @@ -1153,71 +1153,248 @@ mqtt-{subdomain}.yourdomain.com { # Devices get automatic HTTPS, load balancing, DDoS protection ``` -### 🔧 Docker Compose Integration +### 🔧 Docker Compose Integration with caddy-docker-proxy -**Complete Stack with caddy-docker-proxy:** +**Using [caddy-docker-proxy](https://github.com/lucaslorentz/caddy-docker-proxy)** for automatic HTTPS and container discovery. + +> **caddy-docker-proxy** automatically generates Caddyfile configurations from Docker container labels, eliminating manual reverse proxy setup. Perfect for dynamic broker spawning! + +**Complete Production Stack:** ```yaml # docker-compose.yml +version: "3.8" + services: - mcmqtt: - image: python:3.11-slim - command: uvx mcmqtt --transport http --port 3000 + caddy: + image: lucaslorentz/caddy-docker-proxy:ci-alpine + ports: + - "80:80" + - "443:443" + environment: + # Enable Docker provider for automatic container discovery + CADDY_INGRESS_NETWORKS: caddy + # Cloudflare API token for DNS challenge (wildcard certificates) + CLOUDFLARE_API_TOKEN: ${CLOUDFLARE_API_TOKEN} + networks: + - caddy volumes: - /var/run/docker.sock:/var/run/docker.sock - networks: - - caddy + - caddy_data:/data + - caddy_config:/config + restart: unless-stopped labels: - # caddy-docker-proxy automatically adds to Caddyfile - caddy: mqtt-control.yourdomain.com - caddy.reverse_proxy: "{{upstreams 3000}}" - caddy.tls: internal # or use DNS challenge for public - - # Example spawned broker container (created by mcmqtt) - mqtt-broker-customer-123: - image: python:3.11-slim - command: uvx amqtt --config /broker.yaml - networks: - - caddy - labels: - # Automatic HTTPS routing via caddy-docker-proxy - caddy: customer-123.mqtt.yourdomain.com - caddy.reverse_proxy: "{{upstreams 1883}}" + # Global TLS configuration for wildcard certificates + caddy.tls.dns: cloudflare + + mcmqtt: + image: python:3.11-slim + # http-streamable automatically configures caddy labels + command: uvx mcmqtt --transport http-streamable --port 3000 --hostname mqtt-control.${DOMAIN} + volumes: + - /var/run/docker.sock:/var/run/docker.sock:ro + networks: + - caddy + restart: unless-stopped + environment: + - DOMAIN=${DOMAIN} + - CADDY_NETWORK=caddy + # Labels automatically added by --transport http-streamable + # No manual caddy labels needed! + depends_on: + - caddy + + # Optional: Web dashboard for broker management + mqtt-dashboard: + image: nginx:alpine + volumes: + - ./dashboard:/usr/share/nginx/html:ro + networks: + - caddy + labels: + caddy: mqtt-dashboard.yourdomain.com + caddy.reverse_proxy: "{{upstreams 80}}" caddy.tls.dns: cloudflare - # WebSocket support - caddy.handle_path: "/ws" - caddy.handle_path.reverse_proxy: "{{upstreams 9001}}" - caddy.@websocket.header: "Connection *Upgrade*" - caddy.@websocket.header_2: "Upgrade websocket" networks: caddy: - external: true # Managed by load-balancers/caddy + external: false + name: caddy + +volumes: + caddy_data: + external: true + caddy_config: + external: true ``` -**The Magic: Just Labels = Instant HTTPS Routing!** +**Environment Configuration (.env):** ```bash -# When mcmqtt spawns a broker, it adds these labels: +# .env file +COMPOSE_PROJECT_NAME=mcmqtt-production + +# Cloudflare DNS challenge for wildcard certificates +CLOUDFLARE_API_TOKEN=your_cloudflare_global_api_key_here + +# Domain configuration +DOMAIN=yourdomain.com +MQTT_SUBDOMAIN=mqtt + +# Optional: Basic auth for admin interfaces +ADMIN_USER=admin +ADMIN_PASSWORD_HASH=$2a$14$hash_your_password_here +``` + +**Setup Instructions:** +```bash +# 1. Create external volumes for Caddy data persistence +docker volume create caddy_data +docker volume create caddy_config + +# 2. Configure environment variables +cp .env.example .env +# Edit .env with your domain and Cloudflare token + +# 3. Deploy the stack +docker compose up -d + +# 4. Verify Caddy is running +docker compose logs caddy + +# 5. Test mcmqtt control interface +curl https://mqtt-control.yourdomain.com/health +``` + +**How Dynamic Broker Spawning Works:** +```bash +# 1. User calls mqtt_spawn_broker tool { "tool": "mqtt_spawn_broker", "arguments": { - "name": "api-coordination", + "name": "customer-acme-prod", "websocket_port": 9001, - "caddy_labels": { - "caddy": "api-coord.mqtt.yourdomain.com", - "caddy.reverse_proxy": "{{upstreams 1883}}", - "caddy.handle_path": "/ws", - "caddy.handle_path.reverse_proxy": "{{upstreams 9001}}", - "caddy.tls.dns": "cloudflare" - } + "public_hostname": "acme.mqtt.yourdomain.com", + "auth_required": true, + "max_connections": 1000 } } -# caddy-docker-proxy automatically detects new container -# Adds route to Caddyfile: api-coord.mqtt.yourdomain.com -# Issues wildcard certificate via Cloudflare DNS -# Result: Instant HTTPS routing with zero manual config! +# 2. mcmqtt spawns Docker container with automatic caddy labels: +docker run -d \ + --name mqtt-broker-customer-acme-prod \ + --network caddy \ + --label "caddy=acme.mqtt.yourdomain.com" \ + --label "caddy.reverse_proxy={{upstreams 1883}}" \ + --label "caddy.handle_path=/ws" \ + --label "caddy.handle_path.reverse_proxy={{upstreams 9001}}" \ + --label "caddy.tls.dns=cloudflare" \ + python:3.11-slim uvx amqtt + +# 3. caddy-docker-proxy automatically detects the new container +# 4. Generates Caddyfile configuration instantly: +# acme.mqtt.yourdomain.com { +# reverse_proxy mqtt-broker-customer-acme-prod:1883 +# handle_path /ws { +# reverse_proxy mqtt-broker-customer-acme-prod:9001 +# } +# tls { +# dns cloudflare +# } +# } + +# 5. Result: https://acme.mqtt.yourdomain.com is LIVE with valid certificate! ``` +**Production Deployment Example:** +```bash +# Clone and deploy the complete stack +git clone https://github.com/your-org/mcmqtt-production-stack +cd mcmqtt-production-stack + +# Configure your domain and Cloudflare +cp .env.example .env +# Edit .env with your settings + +# Deploy production stack +make deploy + +# Test the deployment +make test-deployment + +# Spawn your first public broker +curl -X POST https://mqtt-control.yourdomain.com/api/brokers \ + -H "Content-Type: application/json" \ + -d '{ + "name": "my-first-broker", + "public_hostname": "test.mqtt.yourdomain.com", + "websocket_port": 9001, + "auth_required": true + }' + +# Result: https://test.mqtt.yourdomain.com is immediately accessible! +``` + +### ⚡ Auto-Labeling with `--transport http-streamable` + +**Zero configuration Caddy integration!** + +```bash +# Traditional: Manual caddy labels +uvx mcmqtt --transport http --port 3000 +# Requires manual caddy labels in docker-compose.yml + +# Auto-magic: Automatic caddy labels +uvx mcmqtt --transport http-streamable --hostname mqtt-control.yourdomain.com +# Automatically adds all necessary caddy-docker-proxy labels! +``` + +**What `--transport http-streamable` Does:** + +1. **Detects caddy-docker-proxy environment** +2. **Automatically adds container labels:** + ```docker + --label "caddy=${HOSTNAME}" + --label "caddy.reverse_proxy={{upstreams ${PORT}}}" + --label "caddy.tls.dns=cloudflare" # If CLOUDFLARE_API_TOKEN detected + --label "caddy.handle_path=/ws" # For WebSocket support + ``` +3. **Configures FastMCP server for streaming responses** +4. **Enables real-time broker status updates via SSE** + +**Environment-Based Auto-Configuration:** +```bash +# mcmqtt detects these environment variables: +CADDY_NETWORK=caddy # Join caddy network automatically +CLOUDFLARE_API_TOKEN=xxx # Enable DNS challenge for wildcard certs +DOMAIN=yourdomain.com # Use as base domain for spawned brokers +SSL_EMAIL=admin@yourdomain.com # Let's Encrypt certificate email + +# Result: Zero manual configuration needed! +``` + +**Simplified Docker Compose:** +```yaml +services: + mcmqtt: + image: python:3.11-slim + command: uvx mcmqtt --transport http-streamable --hostname mqtt-control.${DOMAIN} + volumes: + - /var/run/docker.sock:/var/run/docker.sock:ro + networks: + - caddy + environment: + - DOMAIN=${DOMAIN} + - CADDY_NETWORK=caddy + - CLOUDFLARE_API_TOKEN=${CLOUDFLARE_API_TOKEN} + # No manual labels needed - all automatic! +``` + +**Benefits of http-streamable mode:** +- 🏷️ **Auto-labeling**: Caddy labels added automatically +- 📡 **Real-time updates**: Server-Sent Events for broker status +- 🔄 **Live monitoring**: Streaming broker health and metrics +- 🎯 **Zero config**: Environment-based auto-configuration +- 🚀 **Production ready**: Optimized for long-running deployments + ### 🐳 Docker Socket Magic = Instant Infrastructure **How mcmqtt + caddy-docker-proxy Works:**