This documentation is part of the "Projects with Books" initiative at zenOSmosis.
The source code for this project is available on GitHub.
System Architecture
Loading…
System Architecture
Relevant source files
Purpose and Scope
This page provides a detailed technical explanation of the system architecture for the Docker MQTT Mosquitto with Cloudflare Tunnel deployment. It covers container topology, network routing, external access patterns, and configuration mechanisms. For information about security principles and threat models, see Security Model. For step-by-step deployment instructions, see Getting Started.
The architecture implements a Zero Trust access pattern where the MQTT broker remains completely unexposed to the public internet, with all external access routed through Cloudflare’s network via an outbound-only tunnel connection.
Sources: README.md:1-93
Container Topology
Service Definitions
The system consists of two containerized services orchestrated by Docker Compose:
| Service Name | Container Name | Image | Purpose |
|---|---|---|---|
mosquitto | mosquitto | eclipse-mosquitto:latest | MQTT message broker with WebSocket support |
cloudflared | cloudflared | cloudflare/cloudflared:latest | Cloudflare Tunnel connector for secure external access |
Both services are defined in docker-compose.yml:3-17 and run on Docker Compose’s default bridge network, enabling service-to-service communication via Docker’s internal DNS resolver.
graph TB
subgraph DockerComposeOrchestration["Docker Compose (version 3.8)"]
subgraph MosquittoService["mosquitto service"]
MosquittoContainer["mosquitto container\n(eclipse-mosquitto:latest)"]
MosquittoVolume["Volume Mount:\n./mosquitto.conf\n→\n/mosquitto/config/mosquitto.conf"]
MosquittoRestart["restart: unless-stopped"]
end
subgraph CloudflaredService["cloudflared service"]
CloudflaredContainer["cloudflared container\n(cloudflare/cloudflared:latest)"]
CloudflaredCommand["command:\ntunnel --no-autoupdate run --token"]
CloudflaredEnv["environment:\nCLOUDFLARE_TUNNEL_TOKEN"]
CloudflaredRestart["restart: unless-stopped"]
end
DockerDNS["Docker Internal DNS"]
end
MosquittoVolume -->|configures| MosquittoContainer
MosquittoRestart -.->|lifecycle policy| MosquittoContainer
CloudflaredEnv -->|authenticates| CloudflaredCommand
CloudflaredCommand -->|runs in| CloudflaredContainer
CloudflaredRestart -.->|lifecycle policy| CloudflaredContainer
CloudflaredContainer -->|resolves 'mosquitto:9001'| DockerDNS
DockerDNS -->|maps to container IP| MosquittoContainer
Container Dependency Graph
Sources: docker-compose.yml:1-18
Network Architecture
Internal Docker Networking
Docker Compose creates an isolated bridge network where containers communicate using service names as hostnames. The cloudflared service connects to the Mosquitto broker using the internal hostname mosquitto:9001, which Docker’s DNS resolver maps to the mosquitto container’s IP address on the bridge network.
Key Architectural Properties:
graph LR
subgraph DockerBridgeNetwork["Docker Bridge Network"]
CloudflaredProc["cloudflared process\n(cloudflared container)"]
MosquittoProc["mosquitto process\n(mosquitto container)"]
CloudflaredProc -->|HTTP request to mosquitto:9001| DockerInternalDNS["Docker DNS Resolver"]
DockerInternalDNS -->|resolves to container IP| MosquittoProc
subgraph MosquittoListeners["Mosquitto Listeners"]
Port1883["Port 1883\n(MQTT protocol)"]
Port9001["Port 9001\n(WebSocket/HTTP)"]
end
MosquittoProc -->|binds| Port1883
MosquittoProc -->|binds| Port9001
end
HostMachine["Host Machine\n(NO port exposure)"]
DockerBridgeNetwork -.->|isolated from| HostMachine
- No Port Exposure: Neither service exposes ports to the host machine via the
portsdirective in docker-compose.yml - Service Discovery: The
cloudflaredcontainer resolvesmosquittovia Docker’s internal DNS without IP address configuration - Network Isolation: All inter-service communication occurs within the Docker bridge network
Sources: docker-compose.yml:4-17 README.md:64-67
External Access Flow
Cloudflare Tunnel Architecture
External clients connect to the MQTT broker through Cloudflare’s infrastructure, never directly accessing the origin server. This inverted connection model eliminates the need for inbound firewall rules or public IP addresses.
sequenceDiagram
participant ExtClient as "External MQTT Client"
participant CFEdge as "Cloudflare Edge Network\n(Global PoPs)"
participant CFTunnel as "Cloudflare Tunnel Infrastructure"
participant CloudflaredContainer as "cloudflared container"
participant MosquittoContainer as "mosquitto container"
Note over CloudflaredContainer,CFTunnel: Tunnel Establishment (Startup)
CloudflaredContainer->>CFTunnel: Outbound connection with token
CFTunnel-->>CloudflaredContainer: Tunnel established
Note over ExtClient,MosquittoContainer: Client Connection Flow
ExtClient->>CFEdge: Connect to subdomain.domain.com:443
CFEdge->>CFTunnel: Route via tunnel infrastructure
CFTunnel->>CloudflaredContainer: Forward through encrypted tunnel
CloudflaredContainer->>MosquittoContainer: HTTP request to mosquitto:9001
MosquittoContainer-->>CloudflaredContainer: HTTP response
CloudflaredContainer-->>CFTunnel: Return
CFTunnel-->>CFEdge: Return
CFEdge-->>ExtClient: HTTPS response on port 443
Note over CloudflaredContainer,MosquittoContainer: Protocol Transformation\nExternal: HTTPS/WSS (port 443)\nInternal: HTTP/WS (port 9001)
Access Pattern
- Outbound-Only Connection: The
cloudflaredcontainer initiates a persistent outbound connection to Cloudflare’s network using the commandtunnel --no-autoupdate run --token ${CLOUDFLARE_TUNNEL_TOKEN}docker-compose.yml14 - Token Authentication: The
CLOUDFLARE_TUNNEL_TOKENenvironment variable docker-compose.yml17 authenticates the tunnel to Cloudflare’s infrastructure - Protocol Transformation: Cloudflare receives external HTTPS/WSS connections on port 443 and forwards them as HTTP to
mosquitto:9001README.md:63-67 - DNS Routing: The public hostname configured in Cloudflare’s dashboard (e.g.,
subdomain.domain.com) routes to the tunnel, which forwards to the internalmosquitto:9001service endpoint
Sources: docker-compose.yml:11-17 README.md:57-82
Configuration Mechanisms
Configuration Injection Points
The system employs two distinct configuration injection mechanisms:
Configuration Details
| Component | Mechanism | File Path | Container Path | Purpose |
|---|---|---|---|---|
cloudflared | Environment Variable | .env (host) | CLOUDFLARE_TUNNEL_TOKEN env var | Tunnel authentication token |
mosquitto | Volume Mount | ./mosquitto.conf (host) | /mosquitto/config/mosquitto.conf | Broker listener and protocol configuration |
Token Injection: The CLOUDFLARE_TUNNEL_TOKEN is read from the .env file on the host system docker-compose.yml17 and passed to the cloudflared container as an environment variable. The token is referenced in the container’s command via shell variable substitution: --token ${CLOUDFLARE_TUNNEL_TOKEN} docker-compose.yml14
Configuration File Mounting: The mosquitto.conf file is mounted from the host filesystem into the container at /mosquitto/config/mosquitto.conf docker-compose.yml8 This allows the Mosquitto process to read its configuration without rebuilding the container image.
Sources: docker-compose.yml:7-17 README.md53
Service Restart Policies
Both services implement the restart: unless-stopped policy docker-compose.yml:9-15 which provides automatic recovery from failures:
- Automatic Restart: Containers restart automatically if they crash or exit unexpectedly
- Manual Control: Containers do not restart if explicitly stopped by
docker-compose stopordocker-compose down - System Reboot: Containers automatically start when the Docker daemon starts (unless manually stopped)
This policy ensures high availability while allowing manual intervention for maintenance operations.
Sources: docker-compose.yml:9-15
Container Lifecycle
Sources: docker-compose.yml:1-18
Communication Protocol Stack
The system implements a multi-layer protocol transformation:
| Layer | External (Internet) | Internal (Docker) |
|---|---|---|
| Transport | TLS 1.3 (port 443) | Unencrypted HTTP (port 9001) |
| Application | WebSocket Secure (WSS) or MQTT over TLS | WebSocket (WS) or MQTT |
| Network | Public internet via Cloudflare | Docker bridge network |
| Routing | DNS to Cloudflare Edge PoPs | Docker DNS to container IP |
Security Boundary: TLS termination occurs at Cloudflare’s edge network. The internal Docker network segment is trusted and does not require encryption, as it is isolated from external access.
Sources: README.md:63-82
Dismiss
Refresh this wiki
Enter email to refresh