Keyboard shortcuts

Press or to navigate between chapters

Press S or / to search in the book

Press ? to show this help

Press Esc to hide this help

GitHub

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 NameContainer NameImagePurpose
mosquittomosquittoeclipse-mosquitto:latestMQTT message broker with WebSocket support
cloudflaredcloudflaredcloudflare/cloudflared:latestCloudflare 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 ports directive in docker-compose.yml
  • Service Discovery: The cloudflared container resolves mosquitto via 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

  1. Outbound-Only Connection: The cloudflared container initiates a persistent outbound connection to Cloudflare’s network using the command tunnel --no-autoupdate run --token ${CLOUDFLARE_TUNNEL_TOKEN} docker-compose.yml14
  2. Token Authentication: The CLOUDFLARE_TUNNEL_TOKEN environment variable docker-compose.yml17 authenticates the tunnel to Cloudflare’s infrastructure
  3. Protocol Transformation: Cloudflare receives external HTTPS/WSS connections on port 443 and forwards them as HTTP to mosquitto:9001 README.md:63-67
  4. DNS Routing: The public hostname configured in Cloudflare’s dashboard (e.g., subdomain.domain.com) routes to the tunnel, which forwards to the internal mosquitto:9001 service 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

ComponentMechanismFile PathContainer PathPurpose
cloudflaredEnvironment Variable.env (host)CLOUDFLARE_TUNNEL_TOKEN env varTunnel authentication token
mosquittoVolume Mount./mosquitto.conf (host)/mosquitto/config/mosquitto.confBroker 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 stop or docker-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:

LayerExternal (Internet)Internal (Docker)
TransportTLS 1.3 (port 443)Unencrypted HTTP (port 9001)
ApplicationWebSocket Secure (WSS) or MQTT over TLSWebSocket (WS) or MQTT
NetworkPublic internet via CloudflareDocker bridge network
RoutingDNS to Cloudflare Edge PoPsDocker 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