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.

Cloudflared Tunnel Service

Relevant source files

Purpose and Scope

This document provides in-depth technical documentation of the cloudflared service, which establishes a secure, outbound-only tunnel connection between the Docker host environment and Cloudflare's edge network. It covers the Docker container configuration, tunnel authentication mechanism, traffic routing behavior, and operational characteristics of the tunnel client.

For information about configuring the Cloudflare Tunnel through the Zero Trust dashboard and obtaining the tunnel token, see Cloudflare Tunnel Configuration. For information about the Mosquitto service that cloudflared routes traffic to, see Mosquitto MQTT Broker.


Service Overview

The cloudflared service runs the official Cloudflare Tunnel client (cloudflare/cloudflared:latest) as a Docker container. Its primary responsibility is to establish and maintain an encrypted, outbound-only tunnel connection to Cloudflare's global edge network. This tunnel enables external MQTT clients to reach the internal mosquitto service without requiring inbound firewall rules or exposing ports directly to the internet.

The service operates as a reverse proxy within the Docker Compose stack, forwarding all traffic received from the Cloudflare edge through the tunnel to the mosquitto container's WebSocket listener on port 9001.

Sources: docker-compose.yml:11-17 README.md:15-20


Docker Container Configuration

Service Definition

The cloudflared service is defined in docker-compose.yml:11-17 with the following configuration:

Configuration AspectValuePurpose
Service NamecloudflaredIdentifier used by Docker Compose
Imagecloudflare/cloudflared:latestOfficial Cloudflare Tunnel client image
Container NamecloudflaredHostname accessible within Docker network
Commandtunnel --no-autoupdate run --token ${CLOUDFLARE_TUNNEL_TOKEN}Starts tunnel with authentication token
Restart Policyunless-stoppedAutomatically restarts on failure or reboot
Environment VariablesCLOUDFLARE_TUNNEL_TOKENTunnel authentication credential

Command Line Arguments

The container executes with three key command line arguments:

  • tunnel - Invokes the tunnel subcommand of cloudflared
  • --no-autoupdate - Prevents automatic updates of the cloudflared binary (recommended for containerized deployments where the Docker image should control versioning)
  • run --token ${CLOUDFLARE_TUNNEL_TOKEN} - Runs the tunnel using token-based authentication

Sources: docker-compose.yml14


Container Configuration Diagram

Diagram: cloudflared Service Configuration Flow

This diagram illustrates how the service definition in docker-compose.yml translates to a running container, with the authentication token sourced from the .env file.

Sources: docker-compose.yml:11-17 .env.sample1


Tunnel Authentication Mechanism

Authentication Token

The cloudflared service authenticates with Cloudflare's edge network using CLOUDFLARE_TUNNEL_TOKEN, an opaque authentication credential generated by the Cloudflare Zero Trust dashboard. This token:

  1. Uniquely identifies the tunnel - Each tunnel has a unique token that maps to a specific tunnel configuration in Cloudflare's system
  2. Contains embedded authentication - The token includes all necessary authentication information; no username/password is required
  3. Associates with routing rules - The token links to public hostname configurations that determine traffic routing

The token is provided to the container via the CLOUDFLARE_TUNNEL_TOKEN environment variable, which Docker Compose populates from the .env file docker-compose.yml17

Token Security

The token grants full control over the tunnel and must be protected:

  • Never committed to version control - The .env file is excluded via .gitignore
  • Stored only in local environment - Each deployment maintains its own .env file
  • Template provided - .env.sample1 shows the required format without exposing actual credentials

Sources: docker-compose.yml:14-17 .env.sample1 README.md51


Tunnel Establishment Process

sequenceDiagram
    participant Compose as "docker-compose"
    participant Container as "cloudflared Container"
    participant Token as "CLOUDFLARE_TUNNEL_TOKEN"
    participant CFEdge as "Cloudflare Edge Network"
    participant CFControl as "Cloudflare Control Plane"
    
    Compose->>Container: Start container with command:\ntunnel --no-autoupdate run --token
    Container->>Token: Read environment variable
    Token-->>Container: Return token value
    
    Container->>CFControl: Authenticate with token
    CFControl->>CFControl: Validate token\nRetrieve tunnel configuration
    CFControl-->>Container: Authentication successful\nRouting rules provided
    
    Container->>CFEdge: Establish outbound encrypted connection\n(typically TLS over TCP)
    CFEdge-->>Container: Connection established
    
    Container->>Container: Enter ready state\nListening for tunnel traffic
    
    Note over Container,CFEdge: Tunnel is now active and ready to route traffic

Startup Sequence

When the cloudflared container starts, it follows this sequence to establish the tunnel:

Diagram: Cloudflared Tunnel Establishment Sequence

This diagram shows the complete startup sequence from container launch to tunnel readiness.

Sources: docker-compose.yml14 README.md:47-54

Connection Characteristics

The tunnel connection exhibits these characteristics:

CharacteristicBehavior
DirectionOutbound-only from cloudflared to Cloudflare edge
ProtocolEncrypted (TLS) over TCP
PersistenceLong-lived connection, automatically reconnects if dropped
Firewall RequirementsNone - no inbound ports need to be opened
Restart BehaviorContainer restarts automatically (unless-stopped policy) if tunnel fails

Sources: docker-compose.yml15


Traffic Routing and Proxying

Routing Configuration

The cloudflared service acts as a reverse proxy, forwarding traffic from Cloudflare's edge to the internal mosquitto service. The routing configuration is established through the Cloudflare Zero Trust dashboard, not in the Docker configuration:

  1. Public hostname - Configured in Cloudflare dashboard (e.g., mqtt.example.com)
  2. Service type - Set to HTTP in the dashboard
  3. Target URL - Set to mosquitto:9001 README.md62
graph LR
    subgraph "External"
        Client["MQTT Client"]
CFEdge["Cloudflare Edge\n(Public IP)"]
end
    
    subgraph "Docker Host"
        subgraph "Docker Internal Network"
            CFContainer["cloudflared Container"]
MosqContainer["mosquitto Container\n(container_name: mosquitto)"]
end
    end
    
    subgraph "Cloudflare Dashboard Config"
        PublicHost["Public Hostname:\nmqtt.example.com"]
ServiceURL["Service URL:\nmosquitto:9001"]
end
    
 
   Client -->|MQTT over Internet| CFEdge
 
   CFEdge -->|Encrypted Tunnel| CFContainer
 
   CFContainer -->|HTTP Proxy to mosquitto:9001| MosqContainer
    
 
   PublicHost -.->|Maps to| CFEdge
 
   ServiceURL -.->|Resolves via Docker DNS| MosqContainer

The hostname mosquitto in the target URL resolves to the mosquitto container via Docker's internal DNS, using the container_name field from the mosquitto service definition.

Traffic Flow

Diagram: Cloudflared Traffic Routing Architecture

This diagram illustrates the complete traffic path from external clients through the tunnel to the mosquitto service, showing how the mosquitto:9001 service URL resolves within Docker's network.

Sources: README.md:59-66 docker-compose.yml:6-13


Network Behavior

Internal Docker Networking

The cloudflared service participates in Docker Compose's default bridge network alongside the mosquitto service. This enables:

  1. DNS-based service discovery - The hostname mosquitto automatically resolves to the IP address of the mosquitto container
  2. Direct container-to-container communication - Traffic between cloudflared and mosquitto stays within the Docker network
  3. No port exposure required - Neither service exposes ports to the host machine

No Inbound Port Requirements

A key architectural benefit of the cloudflared tunnel is that it requires no inbound firewall rules. The tunnel connection is established outbound from the cloudflared container to Cloudflare's edge network. All traffic flows through this pre-established tunnel, eliminating the need to expose any ports on the Docker host to the public internet.

Sources: docker-compose.yml:1-17 README.md:15-20


Operational Characteristics

Automatic Restart Behavior

The service is configured with restart: unless-stopped docker-compose.yml15 which means:

ScenarioBehavior
Container crashesAutomatically restarts
Docker daemon restartsContainer starts automatically
System rebootContainer starts automatically
Manual stopContainer remains stopped until manually started

This restart policy ensures high availability of the tunnel connection without manual intervention.

Update Management

The --no-autoupdate flag docker-compose.yml14 prevents cloudflared from automatically updating itself. This is recommended for containerized deployments because:

  • Version control - Updates are managed by changing the Docker image tag, not by in-container updates
  • Predictability - The deployed version matches the image version
  • Consistency - All instances run the same version of cloudflared

To update cloudflared, pull a newer version of the cloudflare/cloudflared image and recreate the container.

Sources: docker-compose.yml:14-15


Authentication and Token Management Diagram

Diagram: Token Lifecycle and Security

This diagram traces the complete lifecycle of the tunnel authentication token, from generation in the Cloudflare dashboard to consumption by the cloudflared container, highlighting the security boundaries.

Sources: docker-compose.yml:16-17 .env.sample1 README.md:47-51


Integration with Mosquitto Service

Service Dependency

While the docker-compose.yml file does not explicitly define a depends_on relationship, the cloudflared service functionally depends on the mosquitto service being available:

  1. Routing target - The tunnel routes traffic to mosquitto:9001
  2. Service availability - If mosquitto is not running, routed traffic will fail
  3. Docker DNS resolution - The hostname mosquitto must resolve for proxying to work

The lack of an explicit dependency is acceptable because:

  • Both services have restart: unless-stopped policies, ensuring they both remain running
  • Cloudflared will queue or retry connections if mosquitto is temporarily unavailable
  • The tunnel itself remains active even if the backend service is down

Port Mapping

The cloudflared service routes traffic specifically to port 9001 on the mosquitto container README.md62 This port corresponds to mosquitto's WebSocket listener configuration. The choice of port 9001 rather than 1883 (standard MQTT) is significant because:

  • Cloudflare Tunnel works with HTTP/WebSocket protocols
  • MQTT over WebSockets is supported on port 9001
  • Standard MQTT (port 1883) uses raw TCP, which requires WebSocket encapsulation when tunneled

Sources: README.md62 docker-compose.yml:4-9


Operational Monitoring

Container Status

The health and status of the cloudflared service can be monitored using standard Docker commands:

Expected Log Output

When functioning correctly, the cloudflared container logs will show:

  • Successful authentication with Cloudflare
  • Tunnel registration confirmation
  • Active connection status
  • Traffic routing information

Common Operational States

StateIndicationMeaning
RunningContainer status shows "Up"Tunnel is active and routing traffic
RestartingContainer repeatedly starts and stopsAuthentication failure or network issue
ExitedContainer stopped with exit codeConfiguration error or manual stop

Sources: docker-compose.yml:11-17


Summary

The cloudflared service provides secure, managed tunnel connectivity from Cloudflare's global edge network to the internal mosquitto MQTT broker. Key characteristics include:

  • Container: cloudflare/cloudflared:latest running with container_name: cloudflared
  • Authentication: Token-based via CLOUDFLARE_TUNNEL_TOKEN environment variable
  • Command: tunnel --no-autoupdate run --token ${CLOUDFLARE_TUNNEL_TOKEN}
  • Restart Policy: unless-stopped for high availability
  • Network Role: Reverse proxy forwarding traffic to mosquitto:9001
  • Security Model: Outbound-only connection, no inbound firewall rules required
  • Configuration Management: Tunnel routing configured in Cloudflare dashboard, not in Docker files

Sources: docker-compose.yml:11-17 README.md:15-73 .env.sample1