This documentation is part of the "Projects with Books" initiative at zenOSmosis.
The source code for this project is available on GitHub.
Deployment
Loading…
Deployment
Relevant source files
This page covers the process of deploying the Docker MQTT Mosquitto with Cloudflare Tunnel system using Docker Compose. It assumes you have completed the Cloudflare Tunnel setup (see Cloudflare Tunnel Setup) and local configuration (see Local Configuration). For production deployment considerations, see Production Deployment Considerations. For detailed troubleshooting, see Troubleshooting.
Starting the System
With the .env file configured and mosquitto.conf in place, deploy the system using Docker Compose:
This command starts both the mosquitto and cloudflared containers as defined in docker-compose.yml:3-17 The command runs in the foreground, displaying logs from both containers in real-time.
Deployment Modes
| Command | Behavior | Use Case |
|---|---|---|
docker compose up | Foreground mode with logs | Development, debugging, initial testing |
docker compose up -d | Detached mode (background) | Production, long-running deployments |
docker compose up --build | Rebuild images before starting | After configuration changes requiring rebuild |
Sources: README.md:74-78 docker-compose.yml:1-18
Deployment Sequence
The following sequence diagram shows the complete deployment lifecycle from command execution to operational state:
Deployment Initialization Flow
sequenceDiagram
participant User
participant DockerCompose as "docker-compose\n(Orchestrator)"
participant DockerEngine as "Docker Engine"
participant MosqContainer as "mosquitto\n(Container)"
participant CFDContainer as "cloudflared\n(Container)"
participant CFTunnel as "Cloudflare Tunnel\n(Service)"
participant MosqProcess as "Mosquitto Process\n(MQTT Broker)"
User->>DockerCompose: docker compose up
DockerCompose->>DockerEngine: Parse docker-compose.yml
DockerEngine->>DockerEngine: Create bridge network
Note over DockerEngine,MosqContainer: Start mosquitto service
DockerEngine->>MosqContainer: Pull eclipse-mosquitto:latest
DockerEngine->>MosqContainer: Create container
DockerEngine->>MosqContainer: Mount ./mosquitto.conf to /mosquitto/config/
MosqContainer->>MosqProcess: Start mosquitto daemon
MosqProcess->>MosqProcess: Read /mosquitto/config/mosquitto.conf
MosqProcess->>MosqProcess: Bind listener on port 1883
MosqProcess->>MosqProcess: Bind listener on port 9001 (websockets)
MosqProcess-->>DockerEngine: Container running
Note over DockerEngine,CFDContainer: Start cloudflared service
DockerEngine->>CFDContainer: Pull cloudflare/cloudflared:latest
DockerEngine->>CFDContainer: Create container
DockerEngine->>CFDContainer: Inject CLOUDFLARE_TUNNEL_TOKEN from .env
CFDContainer->>CFDContainer: Execute: tunnel --no-autoupdate run --token
CFDContainer->>CFTunnel: Establish tunnel connection
CFTunnel-->>CFDContainer: Tunnel established
CFDContainer->>CFDContainer: Resolve mosquitto via DNS
CFDContainer-->>DockerEngine: Container running
DockerEngine-->>DockerCompose: Both services started
DockerCompose-->>User: Display container logs
Note over User,MosqProcess: System operational
Sources: docker-compose.yml:1-18 README.md:74-78
Container Startup Behavior
Each service defined in docker-compose.yml:3-17 has specific startup characteristics:
mosquitto Container
The mosquitto container starts with the following configuration:
- Image:
eclipse-mosquitto:latest(docker-compose.yml5) - Container Name:
mosquitto(docker-compose.yml6) - Volume Mount:
./mosquitto.conf→/mosquitto/config/mosquitto.conf(docker-compose.yml:7-8) - Restart Policy:
unless-stopped(docker-compose.yml9)
Upon startup, the Mosquitto process reads the mounted configuration file and initializes two listeners as specified in mosquitto.conf.
cloudflared Container
The cloudflared container starts with the following configuration:
- Image:
cloudflare/cloudflared:latest(docker-compose.yml12) - Container Name:
cloudflared(docker-compose.yml13) - Command:
tunnel --no-autoupdate run --token ${CLOUDFLARE_TUNNEL_TOKEN}(docker-compose.yml14) - Environment:
CLOUDFLARE_TUNNEL_TOKENinjected from.env(docker-compose.yml:16-17) - Restart Policy:
unless-stopped(docker-compose.yml15)
The --no-autoupdate flag prevents the container from attempting to update itself, maintaining version consistency with the Docker image.
Sources: docker-compose.yml:3-18
Verifying Deployment
After starting the system, verify that both containers are running and the tunnel is operational.
Container Status Verification Flow
graph TD
Start["Deployment Started"]
CheckContainers["docker compose ps"]
VerifyStatus{"Both containers\nSTATUS=Up?"}
CheckLogs["docker compose logs"]
VerifyMosquitto{"Mosquitto logs show\nlisteners bound?"}
VerifyCloudflared{"Cloudflared logs show\ntunnel registered?"}
TestConnection["Test MQTT connection\nto public hostname"]
Success["Deployment Verified"]
Failure["Deployment Failed"]
Start --> CheckContainers
CheckContainers --> VerifyStatus
VerifyStatus -->|No| Failure
VerifyStatus -->|Yes| CheckLogs
CheckLogs --> VerifyMosquitto
VerifyMosquitto -->|No| Failure
VerifyMosquitto -->|Yes| VerifyCloudflared
VerifyCloudflared -->|No| Failure
VerifyCloudflared -->|Yes| TestConnection
TestConnection -->|Connection successful| Success
TestConnection -->|Connection failed| Failure
Sources: README.md:82-84
Check Container Status
List running containers and their status:
Expected output should show both containers with STATUS as Up:
| NAME | IMAGE | STATUS | PORTS |
|---|---|---|---|
| mosquitto | eclipse-mosquitto:latest | Up X minutes | 1883/tcp, 9001/tcp |
| cloudflared | cloudflare/cloudflared:latest | Up X minutes |
Sources: docker-compose.yml:4-17
View Container Logs
View logs from all services:
View logs from a specific service:
Follow logs in real-time:
Expected Mosquitto Logs
Successful Mosquitto startup logs include:
mosquitto | 1234567890: mosquitto version X.X.X starting
mosquitto | 1234567890: Config loaded from /mosquitto/config/mosquitto.conf
mosquitto | 1234567890: Opening ipv4 listen socket on port 1883.
mosquitto | 1234567890: Opening websockets listen socket on port 9001.
mosquitto | 1234567890: mosquitto version X.X.X running
Expected Cloudflared Logs
Successful tunnel connection logs include:
cloudflared | Registered tunnel connection
cloudflared | Connection <UUID> registered connIndex=0
cloudflared | Route propagating
Sources: docker-compose.yml:1-18
Verify Public Accessibility
After deployment, the MQTT broker is accessible at https://<subdomain>.<domain>:443, where the subdomain and domain are configured in the Cloudflare Tunnel public hostname settings (see Cloudflare Tunnel Setup).
Important: The broker is not directly accessible on ports 1883 or 9001 from the public internet. All traffic is routed through Cloudflare’s network on port 443 using HTTPS/WSS protocols. Internal container communication uses HTTP on port 9001.
Sources: README.md:82-84
Container Lifecycle Management
Container State Transitions
Sources: docker-compose.yml:9-15
Stopping the System
Stop all containers while preserving their state:
This sends a SIGTERM signal to each container, allowing graceful shutdown. Containers can be restarted with docker compose start.
Sources: docker-compose.yml:1-18
Removing the Deployment
Stop and remove all containers, networks, and anonymous volumes:
This completely tears down the deployment. The next docker compose up will create fresh containers.
To also remove named volumes (use with caution):
Sources: docker-compose.yml:1-18
Restarting Services
Restart all services:
Restart a specific service:
Sources: docker-compose.yml:4-17
Viewing Live Container Processes
Inspect running processes inside containers:
This displays process information for each running container.
Executing Commands in Containers
Execute a command in a running container:
This opens an interactive shell inside the specified container. Useful for debugging and inspecting the container’s filesystem.
Sources: docker-compose.yml:6-13
Deployment Verification Checklist
Use this checklist to confirm successful deployment:
.envfile exists with validCLOUDFLARE_TUNNEL_TOKENmosquitto.conffile exists in the project rootdocker compose psshows both containers withSTATUS: Updocker compose logs mosquittoshows listeners bound on ports 1883 and 9001docker compose logs cloudflaredshows tunnel registered and connection established- Public hostname resolves to Cloudflare’s network
- MQTT client can connect to
https://<subdomain>.<domain>:443
Sources: README.md:74-84 docker-compose.yml:1-18
Common Deployment Issues
This section provides brief guidance on common deployment failures. For comprehensive troubleshooting, see Troubleshooting.
| Issue | Possible Cause | Quick Resolution |
|---|---|---|
| Container exits immediately | Missing or invalid CLOUDFLARE_TUNNEL_TOKEN | Verify .env file and token validity |
cloudflared fails to start | Token expired or revoked | Regenerate token in Cloudflare dashboard |
mosquitto fails to start | Syntax error in mosquitto.conf | Check configuration file syntax |
| Cannot connect to public URL | Tunnel not registered or hostname misconfigured | Verify public hostname configuration in Cloudflare |
| Port binding errors | Port already in use on host | Containers do not expose ports to host by default; check for conflicting services |
Sources: README.md84 docker-compose.yml:1-18
Restart Policy Behavior
Both containers are configured with restart: unless-stopped (docker-compose.yml:9-15), which provides automatic recovery:
- Container Crash: Automatically restarts
- Docker Daemon Restart: Automatically restarts (unless manually stopped)
- Manual Stop: Does not automatically restart until explicitly started
This policy ensures high availability without manual intervention after transient failures or system reboots.
Sources: docker-compose.yml:9-15
Next Steps
After successful deployment:
- Test MQTT connectivity using an MQTT client (see Testing Connection)
- Review component documentation (see Components)
- Implement monitoring (see Monitoring and Health Checks)
- Consider production hardening (see Production Deployment Considerations)
Sources: README.md:82-84
Dismiss
Refresh this wiki
Enter email to refresh