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.

Cloudflare Tunnel Configuration

Relevant source files

Purpose and Scope

This page provides a detailed walkthrough of setting up a Cloudflare Tunnel through the Cloudflare Zero Trust dashboard, obtaining the tunnel token, and configuring public hostnames to route traffic to the mosquitto MQTT broker. This configuration is required before deploying the system via docker-compose.

For information about the overall system architecture and security model, see System Architecture and Security Model. For details about configuring the mosquitto broker itself, see Mosquitto Configuration. For environment variable setup, see Environment Variables.

Cloudflare Tunnel Architecture

The following diagram illustrates how the Cloudflare Tunnel configuration integrates with the codebase:

Cloudflare Tunnel Configuration Flow

graph TB
    subgraph "Cloudflare Zero Trust Dashboard"
        ZT["Zero Trust Portal"]
CreateTunnel["Create Tunnel Action"]
TunnelConfig["Tunnel Configuration\nName: user-defined"]
TokenGen["Token Generator"]
HostnameConfig["Public Hostname Config\nService: HTTP\nURL: mosquitto:9001"]
end
    
    subgraph "Local Environment"
        EnvFile[".env file"]
TokenVar["CLOUDFLARE_TUNNEL_TOKEN"]
end
    
    subgraph "docker-compose.yml"
        CloudflaredService["cloudflared service"]
Command["command: tunnel --no-autoupdate run --token"]
EnvVarRef["environment:\n- CLOUDFLARE_TUNNEL_TOKEN"]
MosquittoRef["mosquitto:9001\ncontainer_name: mosquitto"]
end
    
    subgraph "Runtime"
        CloudflaredContainer["cloudflared container"]
CFNetwork["Cloudflare Edge Network"]
MosquittoContainer["mosquitto container\nport 9001"]
end
    
 
   ZT --> CreateTunnel
 
   CreateTunnel --> TunnelConfig
 
   TunnelConfig --> TokenGen
 
   TokenGen -->|Copy token| TokenVar
 
   TunnelConfig --> HostnameConfig
    
 
   TokenVar -->|Store in| EnvFile
 
   EnvFile -->|Provides value to| EnvVarRef
    
 
   EnvVarRef --> Command
 
   Command -->|Runs in| CloudflaredService
 
   CloudflaredService -->|Creates| CloudflaredContainer
    
 
   HostnameConfig -->|Routes traffic to| MosquittoRef
 
   MosquittoRef -->|Resolves to| MosquittoContainer
    
 
   CloudflaredContainer -->|Authenticates with| CFNetwork
 
   CloudflaredContainer -->|Proxies traffic to| MosquittoContainer

Sources: README.md:23-67, docker-compose.yml:11-17, .env.sample:1

Configuration Steps

Step 1: Access Cloudflare Zero Trust Dashboard

Navigate to the Cloudflare Zero Trust portal to begin tunnel configuration. This interface manages all Cloudflare Tunnel settings.

ActionLocationDetails
Log inCloudflare DashboardUse your Cloudflare account credentials
NavigateLeft sidebarSelect "Zero Trust" option

Sources: README.md:27-29

Step 2: Create a Tunnel

The tunnel creation process generates a unique identifier and authentication token for your deployment.

StepActionConfiguration
1Navigate to Networks → TunnelsAccess tunnel management interface
2Click "Create a tunnel"Initialize tunnel creation workflow
3Select tunnel typeChoose "Cloudflared" connector type
4Name the tunnelEnter descriptive name (e.g., my_tunnel_name)
5Save tunnelFinalize tunnel creation

Tunnel Creation Process

Sources: README.md:33-44

Step 3: Extract and Store the Tunnel Token

After tunnel creation, the dashboard displays a Docker command containing the CLOUDFLARE_TUNNEL_TOKEN. This token must be stored in the .env file for use by the cloudflared service.

Token Extraction and Storage

graph LR
    subgraph "Cloudflare Dashboard"
        DockerCmd["Docker command display\nEnvironment: Docker"]
TokenInCmd["Token embedded in command"]
end
    
    subgraph "Local Repository"
        EnvSample[".env.sample\nCLOUDFLARE_TUNNEL_TOKEN=your_token"]
EnvFile[".env\nCLOUDFLARE_TUNNEL_TOKEN=actual_token"]
end
    
    subgraph "docker-compose.yml:16-17"
        EnvDeclaration["environment:\n- CLOUDFLARE_TUNNEL_TOKEN"]
end
    
 
   DockerCmd --> TokenInCmd
 
   TokenInCmd -->|Copy token value| EnvFile
 
   EnvSample -.->|Template for| EnvFile
 
   EnvFile -->|Provides variable to| EnvDeclaration
ActionFileFormat
Copy token from dashboardN/ALong alphanumeric string from Docker command
Create .env file.env (root directory)CLOUDFLARE_TUNNEL_TOKEN=<your_token>
Reference template.env.sample:1Shows required format

Important: Do not execute the Docker command displayed in the dashboard. The docker-compose.yml:11-17 configuration in this repository replaces that step by running the cloudflared container with the token from the .env file.

Sources: README.md:47-53, .env.sample:1, docker-compose.yml:16-17

Step 4: Configure Public Hostname

The public hostname configuration routes external traffic through the Cloudflare edge network to the internal mosquitto service.

Hostname Configuration Parameters

ParameterValueDescription
Public hostnameUser-defined subdomain and domainExternal URL for MQTT clients to connect
Service typeHTTPProtocol for tunnel transport (not MQTT protocol)
URLmosquitto:9001Internal Docker service reference

Important Implementation Details:

  • The URL mosquitto:9001 uses Docker's internal DNS resolution
  • mosquitto resolves to the container with container_name: mosquitto from docker-compose.yml6
  • Port 9001 corresponds to the WebSocket listener configured in mosquitto.conf
  • The service type HTTP refers to the tunnel transport protocol; MQTT over WebSocket is carried within HTTP

Public Hostname Routing Flow

graph LR
    subgraph "Public Internet"
        Client["MQTT Client"]
PublicHostname["public-hostname.domain.com"]
end
    
    subgraph "Cloudflare Network"
        CFEdge["Cloudflare Edge"]
TunnelRoute["Tunnel Route\nService: HTTP\nURL: mosquitto:9001"]
end
    
    subgraph "Docker Network"
        CloudflaredContainer["cloudflared container\ncontainer_name: cloudflared"]
DNSResolution["Docker DNS\nmosquitto → 172.x.x.x"]
MosquittoContainer["mosquitto container\ncontainer_name: mosquitto\nport 9001 listener"]
end
    
 
   Client -->|Connect to| PublicHostname
 
   PublicHostname -->|Resolves to| CFEdge
 
   CFEdge -->|Routes via| TunnelRoute
 
   TunnelRoute -->|Proxies to| CloudflaredContainer
 
   CloudflaredContainer -->|Resolves| DNSResolution
 
   DNSResolution -->|Forwards to| MosquittoContainer

Configuration Steps:

  1. Navigate to the newly created tunnel in the Zero Trust dashboard
  2. Click "Next" to proceed to hostname configuration
  3. Fill in the public hostname configuration form:
    • Enter your desired subdomain and domain
    • Select HTTP as the service type
    • Enter mosquitto:9001 as the URL
  4. Click "Save hostname" to finalize

Sources: README.md:55-66, docker-compose.yml:4-9

Token Integration with docker-compose

The CLOUDFLARE_TUNNEL_TOKEN environment variable is consumed by the cloudflared service definition in docker-compose.yml:11-17:

cloudflared Service Configuration

Configuration ElementValuePurpose
imagecloudflare/cloudflared:latestOfficial Cloudflare tunnel client
container_namecloudflaredDNS-resolvable name within Docker network
commandtunnel --no-autoupdate run --token ${CLOUDFLARE_TUNNEL_TOKEN}Runs tunnel with token from environment
environment- CLOUDFLARE_TUNNEL_TOKENPasses variable from .env to container
restartunless-stoppedEnsures tunnel reconnects after failures

Environment Variable Flow

Sources: docker-compose.yml:11-17, .env.sample:1

Configuration Verification

After completing the configuration steps, verify the setup before deployment:

Pre-Deployment Checklist

ItemLocationVerification Method
Tunnel created in dashboardCloudflare Zero Trust → Networks → TunnelsTunnel appears in list with "Inactive" status
Public hostname configuredTunnel details → Public Hostname tabHostname entry shows mosquitto:9001 as URL
.env file existsRepository root directoryFile contains CLOUDFLARE_TUNNEL_TOKEN=<token>
Token format valid.env:1Token is long alphanumeric string (typically 150+ characters)
docker-compose.yml unchangedRepository root directoryFile matches repository version

Expected State Before Deployment:

  • Tunnel status in Cloudflare dashboard: "Inactive" (no connector running yet)
  • .env file: Contains valid token, not tracked by git (see .gitignore)
  • Public hostname: Configured but not yet accessible (no traffic can flow until containers start)

The next step is to deploy the system using docker compose up, covered in Deployment.

Sources: README.md:23-73, docker-compose.yml:1-18

Common Configuration Issues

IssueSymptomSolution
Invalid token formatcloudflared container exits immediatelyVerify token copied completely from dashboard, check for extra spaces or newlines
Public hostname not resolvingDNS lookup fails for public hostnameCheck DNS propagation, verify domain is active in Cloudflare
Wrong service URLcloudflared starts but clients cannot connectEnsure URL is mosquitto:9001, not localhost:9001 or IP address
Service type misconfigurationConnection errors despite tunnel activeService type must be HTTP, not TCP or other protocols
Token in version controlSecurity warning in git statusVerify .env is listed in .gitignore never commit .env file

Sources: docker-compose.yml:11-17, README.md:47-67