This documentation is part of the "Projects with Books" initiative at zenOSmosis.
The source code for this project is available on GitHub.
Overview
Relevant source files
This document provides a high-level introduction to the Docker MQTT Mosquitto Cloudflare Tunnel system. It covers the system's purpose, architecture, key components, and how they interact to provide secure MQTT message brokering accessible over the internet.
For detailed setup instructions, see Getting Started. For in-depth component documentation, see Components. For security architecture details, see Security Model.
System Purpose
The Docker MQTT Mosquitto Cloudflare Tunnel system provides a secure MQTT broker deployment that is accessible from the public internet without exposing ports directly on the host machine. It accomplishes this by combining Eclipse Mosquitto (an MQTT message broker) with Cloudflare Tunnel (a secure proxy service).
The system solves the following challenges:
- Port Exposure : Eliminates the need for port forwarding or firewall rules to expose MQTT services
- Secure Access : Provides encrypted transport between external clients and the internal broker through Cloudflare's global network
- DDoS Protection : Leverages Cloudflare's infrastructure for traffic filtering and protection
- Easy Deployment : Uses Docker Compose for simplified orchestration and deployment
This system is particularly suited for IoT applications, home automation, and message brokering scenarios where devices need to communicate with a central MQTT broker over the internet.
Sources : README.md:1-21
Key Components
The system consists of two containerized services orchestrated by Docker Compose, plus configuration files and authentication credentials.
graph TB
subgraph "docker-compose.yml"
mosquitto_service["mosquitto service"]
cloudflared_service["cloudflared service"]
end
subgraph "Container Images"
mosquitto_image["eclipse-mosquitto:latest"]
cloudflared_image["cloudflare/cloudflared:latest"]
end
subgraph "Configuration Files"
mosquitto_conf["mosquitto.conf"]
env_file[".env"]
env_sample[".env.sample"]
end
subgraph "Environment Variables"
token_var["CLOUDFLARE_TUNNEL_TOKEN"]
end
subgraph "Data Storage"
data_dir["data/ directory"]
end
mosquitto_service -->|uses image| mosquitto_image
mosquitto_service -->|volume mount| mosquitto_conf
mosquitto_service -->|may store data in| data_dir
cloudflared_service -->|uses image| cloudflared_image
cloudflared_service -->|reads from| env_file
env_file -->|contains| token_var
env_sample -->|template for| env_file
token_var -->|authenticates| cloudflared_service
Component Map
Sources : docker-compose.yml:1-18 mosquitto.conf:1-6 .env.sample README.md51
Service Definitions
| Service | Container Name | Image | Purpose |
|---|---|---|---|
mosquitto | mosquitto | eclipse-mosquitto:latest | MQTT message broker with two listeners (TCP and WebSocket) |
cloudflared | cloudflared | cloudflare/cloudflared:latest | Cloudflare Tunnel client that proxies traffic to the broker |
Sources : docker-compose.yml:4-17
Configuration Files
| File | Purpose | Version Controlled |
|---|---|---|
docker-compose.yml | Service orchestration and container definitions | Yes |
mosquitto.conf | Mosquitto broker configuration (listeners, protocols, access control) | Yes |
.env | Environment variables including CLOUDFLARE_TUNNEL_TOKEN | No (secret) |
.env.sample | Template for .env file | Yes |
Sources : docker-compose.yml:1-18 mosquitto.conf:1-6 README.md51
Service Architecture
The following diagram shows how the two Docker services are configured and how they relate to their configuration sources.
Sources : docker-compose.yml:3-17 mosquitto.conf:1-6
graph TB
subgraph "Docker Compose Services"
direction LR
subgraph mosquitto["mosquitto service (container_name: mosquitto)"]
mosq_image["image: eclipse-mosquitto:latest"]
mosq_restart["restart: unless-stopped"]
mosq_volume["volume: ./mosquitto.conf:/mosquitto/config/mosquitto.conf"]
end
subgraph cloudflared["cloudflared service (container_name: cloudflared)"]
cf_image["image: cloudflare/cloudflared:latest"]
cf_command["command: tunnel --no-autoupdate run --token"]
cf_restart["restart: unless-stopped"]
cf_env["environment: CLOUDFLARE_TUNNEL_TOKEN"]
end
end
subgraph "Configuration Sources"
conf_file["mosquitto.conf\n- listener 1883\n- listener 9001 (websockets)\n- allow_anonymous true"]
env_file[".env\nCLOUDFLARE_TUNNEL_TOKEN=..."]
end
conf_file -->|mounted into| mosq_volume
env_file -->|provides| cf_env
Mosquitto Service Configuration
The mosquitto service docker-compose.yml:4-9 runs the Eclipse Mosquitto broker with the following characteristics:
- Image :
eclipse-mosquitto:latestdocker-compose.yml5 - Container Name :
mosquittodocker-compose.yml6 - Configuration :
mosquitto.confis mounted to/mosquitto/config/mosquitto.confdocker-compose.yml:7-8 - Restart Policy :
unless-stoppeddocker-compose.yml9
The broker exposes two listeners defined in mosquitto.conf:1-6:
- Port
1883: Standard MQTT TCP listener mosquitto.conf1 - Port
9001: MQTT over WebSocket listener mosquitto.conf:4-5
Anonymous access is enabled mosquitto.conf2 meaning no authentication is required to connect to the broker. For details on anonymous access implications, see Anonymous Access.
Sources : docker-compose.yml:4-9 mosquitto.conf:1-6
Cloudflared Service Configuration
The cloudflared service docker-compose.yml:11-17 establishes a secure tunnel to Cloudflare's network with the following configuration:
- Image :
cloudflare/cloudflared:latestdocker-compose.yml12 - Container Name :
cloudflareddocker-compose.yml13 - Command :
tunnel --no-autoupdate run --token ${CLOUDFLARE_TUNNEL_TOKEN}docker-compose.yml14 - Environment Variable :
CLOUDFLARE_TUNNEL_TOKENsourced from.envfile docker-compose.yml:16-17 - Restart Policy :
unless-stoppeddocker-compose.yml15
The --no-autoupdate flag prevents automatic updates of the cloudflared binary, ensuring consistent behavior. The token authenticates the tunnel client with Cloudflare's network.
Sources : docker-compose.yml:11-17 README.md51
sequenceDiagram
participant Client as "MQTT Client"
participant CFEdge as "Cloudflare Edge Network"
participant cloudflared as "cloudflared container"
participant mosquitto as "mosquitto container"
Note over cloudflared: Startup with CLOUDFLARE_TUNNEL_TOKEN
cloudflared->>CFEdge: Establish encrypted tunnel
CFEdge-->>cloudflared: Tunnel connected
Note over Client,mosquitto: Client Connection Flow
Client->>CFEdge: MQTT CONNECT to public hostname
CFEdge->>cloudflared: Route through tunnel
cloudflared->>mosquitto: Proxy to mosquitto:9001
mosquitto-->>cloudflared: MQTT CONNACK
cloudflared-->>CFEdge: Through tunnel
CFEdge-->>Client: MQTT CONNACK
Note over Client,mosquitto: Message Publishing
Client->>CFEdge: MQTT PUBLISH topic/message
CFEdge->>cloudflared: Through tunnel
cloudflared->>mosquitto: Proxy to port 9001
mosquitto->>mosquitto: Deliver to subscribers
mosquitto-->>Client: MQTT PUBACK (via tunnel)
Traffic Flow
The following diagram illustrates how MQTT traffic flows from external clients to the internal broker through Cloudflare's tunnel.
Traffic Flow Steps
- Tunnel Establishment : The
cloudflaredcontainer connects outbound to Cloudflare using theCLOUDFLARE_TUNNEL_TOKENfrom.envdocker-compose.yml:16-17 - Client Connection : External MQTT clients connect to the Cloudflare public hostname configured in the Zero Trust dashboard README.md:59-64
- Proxy Routing : Cloudflare routes the traffic through the encrypted tunnel to the
cloudflaredcontainer - Internal Forwarding : The
cloudflaredcontainer proxies traffic tomosquitto:9001README.md62 - MQTT Processing : The
mosquittocontainer processes MQTT messages on its WebSocket listener mosquitto.conf:4-5
Note that the cloudflared service proxies to mosquitto:9001 specifically, which corresponds to the WebSocket listener mosquitto.conf:4-5 rather than the standard TCP listener on port 1883 mosquitto.conf1
Sources : README.md:15-73 docker-compose.yml:13-14 mosquitto.conf:1-6
Project Structure
The repository contains the following key files:
File Descriptions
| File Path | Purpose | Notes |
|---|---|---|
README.md | Setup guide and documentation | Includes Cloudflare dashboard walkthrough |
docker-compose.yml | Service definitions for mosquitto and cloudflared | Orchestrates both containers |
mosquitto.conf | Mosquitto broker configuration | Defines listeners on ports 1883 and 9001 |
.env | Environment variables (contains CLOUDFLARE_TUNNEL_TOKEN) | Not version controlled (secret) |
.env.sample | Template for .env file | Shows required variables without actual values |
.gitignore | Git exclusions | Prevents committing .env and data/* |
.github/workflows/ci.yml | GitHub Actions CI pipeline | Tests mosquitto startup |
Sources : README.md:1-73 docker-compose.yml:1-18 mosquitto.conf:1-6
How the System Works
Network Topology
The system eliminates the need for port forwarding or inbound firewall rules because the cloudflared container establishes an outbound connection to Cloudflare's network docker-compose.yml14 This architectural pattern is known as a reverse tunnel.
Sources : README.md:15-20 docker-compose.yml:11-17
Key Characteristics
- No Direct Internet Exposure : The
mosquittobroker is never directly accessible from the internet - Outbound-Only Connection : The
cloudflaredcontainer initiates the tunnel connection to Cloudflare - Service Discovery : Docker's internal DNS resolves
mosquittoto themosquittocontainer docker-compose.yml6 - WebSocket Routing : Public traffic is routed to the WebSocket listener on port 9001 mosquitto.conf:4-5
- Anonymous Access : No authentication is required at the MQTT protocol level mosquitto.conf2
For detailed architectural information, see System Architecture. For security considerations, see Security Model.
Sources : docker-compose.yml:1-18 mosquitto.conf:1-6 README.md:15-73
Quick Start Reference
To deploy this system, you need to:
- Create a Cloudflare Tunnel and obtain the
CLOUDFLARE_TUNNEL_TOKENREADME.md:23-54 - Create a
.envfile with the token README.md51 - Configure a public hostname to route to
mosquitto:9001README.md62 - Run
docker compose upREADME.md:70-72
For detailed step-by-step instructions, see Getting Started. For Cloudflare-specific configuration, see Cloudflare Tunnel Configuration.
Sources : README.md:23-73
Branch Variants
This repository includes a variant branch called protected-no-wildcard that adds:
- Topic access control via ACL file (restricts wildcard searches)
- Encrypted retained messages using gocryptfs
- Auto-save functionality for retained messages
For information about these advanced features, see Topic Access Control (ACL)) and Encrypted Retained Messages.
Sources : README.md:5-11
Next Steps
Sources : README.md:1-73