This documentation is part of the "Projects with Books" initiative at zenOSmosis.
The source code for this project is available on GitHub.
Overview
Loading…
Overview
Relevant source files
Purpose and Scope
This document provides a comprehensive introduction to the Docker MQTT Mosquitto with Cloudflare Tunnel system, explaining its architecture, components, and operational model. This system deploys a containerized Eclipse Mosquitto MQTT broker and securely exposes it to the internet via Cloudflare Tunnel, eliminating the need for publicly exposed ports or inbound firewall rules.
For detailed architectural diagrams and component interactions, see System Architecture. For security principles and Zero Trust implementation details, see Security Model. For step-by-step deployment instructions, see Getting Started.
Sources: README.md:1-23
What is This System?
The Docker MQTT Mosquitto with Cloudflare Tunnel system is a production-ready deployment pattern that combines:
- Eclipse Mosquitto : An open-source MQTT message broker that facilitates publish/subscribe messaging between IoT devices and applications
- Cloudflare Tunnel : A secure tunneling service that exposes local services to the internet without opening inbound ports
- Docker Compose : Container orchestration for reproducible, multi-container deployments
The system implements a Zero Trust security model where the MQTT broker has no internet-facing attack surface. All external traffic is routed through Cloudflare’s global edge network, which provides DDoS protection, SSL termination, and geographic distribution.
Sources: README.md:17-23
Key Features
The system provides the following capabilities:
| Feature | Description | Implementation |
|---|---|---|
| Zero Trust Access | No publicly exposed inbound ports on origin server | Cloudflare Tunnel with outbound-only connections |
| Protocol Support | Native MQTT and WebSocket protocols | Mosquitto listeners on ports 1883 and 9001 |
| Container Orchestration | Reproducible multi-container deployment | Docker Compose with service definitions |
| Automated Testing | Service health verification on every commit | GitHub Actions CI workflow |
| Documentation | Auto-generated and published documentation | GitHub Actions with DeepWiki integration |
| Secret Management | Secure credential handling excluded from version control | .env file with .gitignore protection |
| TLS Encryption | End-to-end encrypted connections | Cloudflare edge network SSL termination |
| Global Distribution | Low-latency access from any geographic region | Cloudflare’s global edge network |
Sources: README.md:1-23 .github/workflows/ci.yml:1-41 .github/workflows/build-docs.yml:1-84
Core Components
The system consists of three primary components orchestrated by Docker Compose:
Component Summary
| Component | Container Name | Purpose | Configuration |
|---|---|---|---|
| Mosquitto Broker | mosquitto | MQTT message broker handling pub/sub messaging | mosquitto.conf:1-5 volume mount |
| Cloudflare Connector | cloudflared | Tunnel client establishing secure outbound connection | Environment variable CLOUDFLARE_TUNNEL_TOKEN |
| Docker Compose | N/A | Orchestration layer managing container lifecycle | docker-compose.yml:1-19 |
Supporting Configuration Files
| File | Purpose | Version Control Status |
|---|---|---|
mosquitto.conf | Defines MQTT listener ports and protocols | Committed to repository |
.env | Contains CLOUDFLARE_TUNNEL_TOKEN secret | Excluded via .gitignore |
.env.sample | Template showing required environment variables | Committed to repository |
.gitignore | Prevents secret leakage to version control | Committed to repository |
Sources: docker-compose.yml:1-19 mosquitto.conf:1-5 .env.sample1 .gitignore:1-2
graph TB
subgraph Internet["Internet / Public Network"]
Client["External MQTT Clients\n(IoT Devices, Applications)"]
end
subgraph CF["Cloudflare Network"]
Edge["Cloudflare Edge\nTLS Termination\nPort 443"]
Tunnel["Cloudflare Tunnel Service"]
end
subgraph DockerHost["Docker Host"]
Compose["docker-compose.yml\nServices Orchestration"]
subgraph Network["Docker Network (Bridge)"]
MosqContainer["Container: mosquitto\neclipse-mosquitto:latest\ncontainer_name: mosquitto"]
CFDContainer["Container: cloudflared\ncloudflare/cloudflared:latest\ncontainer_name: cloudflared"]
end
MosqConf["mosquitto.conf\nVolume Mount\n/mosquitto/config/mosquitto.conf"]
EnvFile[".env\nCLOUDFLARE_TUNNEL_TOKEN"]
end
Client -->|HTTPS/WSS Port 443| Edge
Edge -->|Secure Tunnel| Tunnel
Tunnel <-->|Outbound Connection Token Authentication| CFDContainer
Compose -->|manages| MosqContainer
Compose -->|manages| CFDContainer
MosqConf -->|volumes: ./mosquitto.conf| MosqContainer
EnvFile -->|environment: CLOUDFLARE_TUNNEL_TOKEN| CFDContainer
CFDContainer -->|HTTP to mosquitto:9001| MosqContainer
MosqContainer -->|listener 1883 protocol mqtt| ListenerMQTT["MQTT Protocol\nInternal Port 1883"]
MosqContainer -->|listener 9001 protocol websockets| ListenerWS["WebSocket Protocol\nInternal Port 9001"]
System Topology
The following diagram illustrates the complete system architecture, mapping high-level concepts to specific code entities and configuration elements:
Container and Network Topology
Key Code Entities:
- Service Name :
mosquittoin docker-compose.yml4 - used for Docker internal DNS resolution - Container Name :
mosquittoin docker-compose.yml5 - named container instance - Container Name :
cloudflaredin docker-compose.yml12 - tunnel connector instance - Volume Mount :
./mosquitto.conf:/mosquitto/config/mosquitto.confin docker-compose.yml:8-9 - Environment Variable :
CLOUDFLARE_TUNNEL_TOKENreferenced in docker-compose.yml:16-17 - Listener Directives :
listener 1883andlistener 9001in mosquitto.conf:1-5 - Command :
tunnel runin docker-compose.yml13 - starts tunnel connector with token authentication
Sources: docker-compose.yml:1-19 mosquitto.conf:1-5 README.md:64-67
sequenceDiagram
participant Client as "External Client\n(MQTT/WebSocket)"
participant CFEdge as "Cloudflare Edge\nPort 443 HTTPS"
participant CFTunnel as "Cloudflare Tunnel\nInfrastructure"
participant CloudflaredContainer as "Container: cloudflared\nCommand: tunnel run"
participant DockerDNS as "Docker Internal DNS\nmosquitto:9001"
participant MosquittoContainer as "Container: mosquitto\nPort 9001 Listener"
Note over Client,MosquittoContainer: Initial Connection Phase
CloudflaredContainer->>CFTunnel: Establish tunnel using\nCLOUDFLARE_TUNNEL_TOKEN
CFTunnel-->>CloudflaredContainer: Tunnel authenticated and ready
Note over Client,MosquittoContainer: Client CONNECT Request
Client->>CFEdge: CONNECT to https://subdomain.domain:443
CFEdge->>CFTunnel: Route via tunnel config\nPublic Hostname mapping
CFTunnel->>CloudflaredContainer: Forward through secure tunnel
CloudflaredContainer->>DockerDNS: Resolve "mosquitto:9001"
DockerDNS-->>CloudflaredContainer: Return container IP
CloudflaredContainer->>MosquittoContainer: HTTP request to port 9001\nprotocol websockets
MosquittoContainer-->>CloudflaredContainer: WebSocket upgrade response
CloudflaredContainer-->>CFTunnel: Return response
CFTunnel-->>CFEdge: Return response
CFEdge-->>Client: HTTPS/WSS connection established
Note over Client,MosquittoContainer: Client PUBLISH Message
Client->>CFEdge: PUBLISH to topic
CFEdge->>CFTunnel: Forward
CFTunnel->>CloudflaredContainer: Via tunnel
CloudflaredContainer->>MosquittoContainer: HTTP POST to mosquitto:9001
MosquittoContainer->>MosquittoContainer: Process message\nRoute to subscribers
MosquittoContainer-->>CloudflaredContainer: PUBACK
CloudflaredContainer-->>CFTunnel: Return
CFTunnel-->>CFEdge: Return
CFEdge-->>Client: PUBACK confirmation
Request Flow Architecture
This diagram traces a complete MQTT message flow from external client to broker, mapping each step to specific code entities and configuration elements:
End-to-End Message Flow
Key Code References in Flow:
- Tunnel Authentication :
CLOUDFLARE_TUNNEL_TOKENfrom docker-compose.yml:16-17 passed tocloudflaredcontainer - Tunnel Command :
tunnel runin docker-compose.yml13 establishes outbound connection - DNS Resolution : Service name
mosquittodefined in docker-compose.yml4 resolved by Docker’s internal DNS - Port Configuration :
9001listener defined in mosquitto.conf:4-5 handles WebSocket connections - Protocol Setting :
protocol websocketsin mosquitto.conf5 enables WebSocket support - Public Hostname : Configured in Cloudflare dashboard (Step 3 of README.md:57-72) maps public URL to internal
mosquitto:9001
Sources: docker-compose.yml:1-19 mosquitto.conf:1-5 README.md:57-72
Deployment Model
The system uses a two-phase deployment model that separates cloud configuration from local execution:
Phase 1: Cloud Configuration (One-Time Setup)
| Step | Action | Outcome |
|---|---|---|
| 1 | Create Cloudflare Tunnel via Zero Trust dashboard | Generates unique tunnel identifier |
| 2 | Configure tunnel connector type (Cloudflared) | Provides Docker deployment command |
| 3 | Copy CLOUDFLARE_TUNNEL_TOKEN from generated command | Token for authenticating local connector |
| 4 | Configure Public Hostname mapping | Maps public URL to mosquitto:9001 internal address |
Sources: README.md:29-72
Phase 2: Local Deployment (Repeatable)
| Step | Command/Action | File Reference |
|---|---|---|
| 1 | Create .env file from .env.sample template | .env.sample1 |
| 2 | Add CLOUDFLARE_TUNNEL_TOKEN=<token> to .env | docker-compose.yml:16-17 |
| 3 | Verify .env excluded from Git | .gitignore1 |
| 4 | Run docker compose up | docker-compose.yml1 |
Sources: README.md:53-78 .env.sample1 .gitignore:1-2
Security Architecture
The system implements defense-in-depth security through multiple layers:
Security Layers
Key Security Implementations:
- No Inbound Ports : docker-compose.yml:1-19 defines no
ports:sections, preventing host exposure - Outbound-Only Connection :
tunnel runcommand in docker-compose.yml13 establishes connection from origin to Cloudflare - Secret Exclusion :
.envpattern in .gitignore1 prevents accidental token commits - Anonymous Access : Currently configured as
allow_anonymous truein mosquitto.conf3 - see Authentication and Access Control for implications
For comprehensive security documentation, see Security Model.
Sources: docker-compose.yml:1-19 mosquitto.conf:1-5 .gitignore:1-2
Advanced Features
The repository includes an alternative branch with additional security features:
Protected Branch Features
The protected-no-wildcard branch implements:
| Feature | Implementation | Documentation |
|---|---|---|
| Wildcard Topic Restrictions | ACL file restricting cross-user wildcard subscriptions | README.md9 |
| Encrypted Retained Messages | gocryptfs filesystem encryption | README.md10 |
| Auto-Save Persistence | Automatic message persistence after every publish | README.md11 |
See Protected Branch Features for detailed documentation.
Sources: README.md:7-13
CI/CD Integration
The system includes automated quality assurance through GitHub Actions:
Continuous Integration Workflow
The .github/workflows/ci.yml:1-41 workflow performs:
- Service Provisioning : Starts
mosquittocontainer viadocker-compose up -d mosquitto - Health Check Loop : Polls container status up to 10 times with 10-second intervals
- Verification : Ensures
docker ps | grep mosquitto | grep "Up"succeeds - Cleanup : Executes
docker-compose downregardless of test outcome
Documentation Pipeline
The .github/workflows/build-docs.yml:1-84 workflow:
- Generates documentation using DeepWiki integration
- Builds mdBook static site
- Deploys to GitHub Pages on weekly schedule or manual trigger
For complete CI/CD documentation, see CI/CD and Automation.
Sources: .github/workflows/ci.yml:1-41 .github/workflows/build-docs.yml:1-84
Quick Start Reference
To deploy this system:
- Prerequisites : Docker, Docker Compose, Cloudflare account (see Prerequisites)
- Cloudflare Setup : Create tunnel and obtain token (see Cloudflare Tunnel Setup)
- Local Configuration : Create
.envfile with token (see Local Configuration) - Deployment : Run
docker compose up(see Deployment)
Your MQTT broker will be accessible at https://<subdomain>.<domain>:443 as configured in the Cloudflare Public Hostname settings.
Important : The URL mosquitto:9001 referenced in README.md64 is internal to Docker and resolved via the service name in docker-compose.yml4 The public URL is configured separately in the Cloudflare dashboard and uses HTTPS on port 443, not HTTP on port 9001.
For complete deployment instructions, see Getting Started.
Sources: README.md:25-84 docker-compose.yml:1-19
Dismiss
Refresh this wiki
Enter email to refresh