This documentation is part of the "Projects with Books" initiative at zenOSmosis.
The source code for this project is available on GitHub.
Environment Variables
Loading…
Environment Variables
Relevant source files
Purpose and Scope
This document provides a comprehensive reference for all environment variables used in the Docker MQTT Mosquitto with Cloudflare Tunnel system. It covers the .env file structure, the .env.sample template, and security practices for managing sensitive credentials.
For information about the Docker Compose configuration that consumes these variables, see docker-compose.yml. For the initial setup process of configuring environment variables, see Local Configuration. For version control practices related to secret management, see Version Control Best Practices.
Environment Variable System Overview
The system uses a file-based environment variable pattern where secrets are stored in a .env file that is explicitly excluded from version control. A template file, .env.sample, is committed to the repository to document the required variables without exposing actual values.
File Structure
project-root/
├── .env # Actual secrets (gitignored)
├── .env.sample # Template (version controlled)
├── .gitignore # Excludes .env
└── docker-compose.yml # Consumes environment variables
Sources : .env.sample1 .gitignore1
Environment Variable File Relationship
Analysis : This diagram shows the critical separation between template and actual secrets. The .env.sample file serves as documentation in version control, while .env contains actual credentials and is explicitly excluded by .gitignore. Developers copy the template and populate it with real values obtained from the Cloudflare dashboard.
Sources : .env.sample1 .gitignore1
CLOUDFLARE_TUNNEL_TOKEN
The system uses a single environment variable for authentication and configuration.
Variable Specification
| Variable Name | Required | Type | Description |
|---|---|---|---|
CLOUDFLARE_TUNNEL_TOKEN | Yes | String (JWT) | Authentication token generated by Cloudflare Zero Trust dashboard for tunnel access |
Sources : .env.sample1
Purpose and Function
The CLOUDFLARE_TUNNEL_TOKEN is a JSON Web Token (JWT) that contains:
- Tunnel identification information
- Authentication credentials
- Routing configuration
- Cryptographic signatures
This token authorizes the cloudflared container to establish an outbound connection to Cloudflare’s network and route traffic to the local Mosquitto broker.
Token Format
The token is a base64-encoded JWT string with the following characteristics:
- Length: Approximately 500-800 characters
- Format:
eyJ...(standard JWT prefix) - Components: Header, payload, and signature concatenated with dots
Example from template :
CLOUDFLARE_TUNNEL_TOKEN=your_token
Sources : .env.sample1
Obtaining the Token
The token is generated through the Cloudflare Zero Trust dashboard during tunnel creation. See Cloudflare Tunnel Setup for detailed instructions. The token should be copied from the dashboard and placed in the .env file.
sequenceDiagram
participant User as "User"
participant Dashboard as "Cloudflare Dashboard"
participant EnvSample as ".env.sample"
participant EnvFile as ".env (local)"
participant Compose as "docker-compose.yml"
participant Container as "cloudflared container"
participant Tunnel as "Cloudflare Tunnel Service"
User->>Dashboard: 1. Create tunnel
Dashboard-->>User: 2. Generate CLOUDFLARE_TUNNEL_TOKEN
User->>EnvSample: 3. Read template
EnvSample-->>User: CLOUDFLARE_TUNNEL_TOKEN=your_token
User->>EnvFile: 4. Create .env file
User->>EnvFile: 5. Paste actual token
Note over Compose: docker-compose up
Compose->>EnvFile: 6. Read environment variables
EnvFile-->>Compose: CLOUDFLARE_TUNNEL_TOKEN=eyJh...
Compose->>Container: 7. Start container with env var
Container->>Container: 8. cloudflared tunnel run
Container->>Tunnel: 9. Authenticate with token
Tunnel-->>Container: 10. Tunnel established
Note over Container,Tunnel: Persistent outbound connection\nmaintained for traffic routing
Token Lifecycle and Usage
Analysis : The token is generated once during tunnel creation and remains valid until the tunnel is deleted or the token is rotated. The token is read from .env at container startup and used by the cloudflared tunnel run command to authenticate with Cloudflare’s network.
Sources : .env.sample1
Security Architecture
graph LR
subgraph "Files That Can Be Committed"
SAMPLE[".env.sample\nTemplate only"]
README["README.md"]
COMPOSE["docker-compose.yml"]
MOSQUITTO["mosquitto.conf"]
GITIGNORE_FILE[".gitignore"]
end
subgraph "Files That Must Not Be Committed"
ENV[".env\nContains actual token"]
DATA["data/*\nMosquitto persistence"]
end
subgraph ".gitignore Rules"
RULE1["Line 1: .env"]
RULE2["Line 2: data/*"]
end
RULE1 -.->|excludes| ENV
RULE2 -.->|excludes| DATA
SAMPLE -.->|safe to commit| README
ENV -.->|blocked by gitignore| SAMPLE
The .gitignore Boundary
The .gitignore file establishes a security boundary that prevents accidental exposure of secrets to version control.
Analysis : The .gitignore file contains two critical rules. Line 1 excludes .env to prevent token exposure. Line 2 excludes data/* to prevent committing Mosquitto’s persistence data, which may contain message history or subscriber information.
Sources : .gitignore:1-2
File Contents and Security Model
.env.sample (Template File)
Located at .env.sample1 this file provides:
-
Documentation of required variables
-
Example structure (not functional values)
-
Onboarding guide for new developers
CLOUDFLARE_TUNNEL_TOKEN=your_token
The value your_token is a placeholder and will not work for authentication. Developers must replace it with an actual token from the Cloudflare dashboard.
Security Properties :
- Safe to commit to public repositories
- Contains no sensitive information
- Serves as self-documenting configuration reference
.env (Actual Secrets File)
Not present in the repository; created locally by developers. Contains:
- Real
CLOUDFLARE_TUNNEL_TOKENvalue - Full JWT string with authentication credentials
Security Properties :
- Excluded from version control via .gitignore1
- Should have restrictive file permissions (
chmod 600 .env) - Must never be shared publicly or committed to Git
Sources : .env.sample1 .gitignore1
graph TB
subgraph "Filesystem"
ENV_FILE[".env file"]
end
subgraph "Docker Compose Process"
COMPOSE_CMD["docker-compose up"]
COMPOSE_PARSER["YAML Parser"]
COMPOSE_ENGINE["Docker Engine API"]
end
subgraph "docker-compose.yml"
SERVICE_DEF["cloudflared service definition"]
ENV_REF["environment:\n - CLOUDFLARE_TUNNEL_TOKEN"]
end
subgraph "Container Runtime"
CONTAINER["cloudflared container"]
PROCESS["cloudflared tunnel run"]
ENV_VAR["CLOUDFLARE_TUNNEL_TOKEN\nenvironment variable"]
end
ENV_FILE -->|1. read automatically| COMPOSE_CMD
COMPOSE_CMD --> COMPOSE_PARSER
COMPOSE_PARSER -->|2. parse service config| SERVICE_DEF
SERVICE_DEF --> ENV_REF
ENV_REF -->|3. resolve variable| ENV_FILE
ENV_FILE -->|4. substitute value| COMPOSE_ENGINE
COMPOSE_ENGINE -->|5. create container with env| CONTAINER
CONTAINER -->|6. start process| PROCESS
PROCESS -->|7. read env var| ENV_VAR
Integration with Docker Compose
The docker-compose.yml file consumes environment variables from the .env file automatically through Docker Compose’s built-in environment file support.
Environment Variable Injection Flow
Analysis : Docker Compose automatically loads the .env file from the project root directory. When it encounters environment variable references in docker-compose.yml, it substitutes values from the .env file before passing them to the Docker Engine. The cloudflared process can then access CLOUDFLARE_TUNNEL_TOKEN as a standard environment variable.
Sources : .env.sample1
graph LR
subgraph "Environment Variables"
TOKEN["CLOUDFLARE_TUNNEL_TOKEN"]
end
subgraph "Containers"
CFD["cloudflared\n✓ Has access"]
MOSQ["mosquitto\n✗ No access"]
end
TOKEN -->|injected via environment| CFD
TOKEN -.->|not available| MOSQ
Variable Scoping
The CLOUDFLARE_TUNNEL_TOKEN is only available to the cloudflared container. The mosquitto container does not have access to this variable, demonstrating principle of least privilege.
Sources : .env.sample1
Best Practices
Local Development
-
Initial Setup :
- Copy .env.sample1 to
.env - Obtain token from Cloudflare dashboard (see Cloudflare Tunnel Setup)
- Replace
your_tokenwith actual JWT token - Verify
.envis listed in .gitignore1
- Copy .env.sample1 to
-
File Permissions :
Restricts read/write access to the file owner only.
- Verification : Before starting containers, verify the token is populated:
If this returns empty, the token has not been configured.
Production Deployment
For production environments, consider alternatives to file-based secrets:
| Method | Security | Rotation | Audit |
|---|---|---|---|
.env file | Low | Manual | No |
| Docker secrets | Medium | Manual | Limited |
| HashiCorp Vault | High | Automated | Yes |
| AWS Secrets Manager | High | Automated | Yes |
| Azure Key Vault | High | Automated | Yes |
Production deployments should:
- Use secrets management systems instead of
.envfiles - Implement automatic token rotation
- Enable audit logging for secret access
- Use read-only access where possible
graph TB
subgraph "Common Mistakes (DO NOT DO)"
COMMIT["❌ Committing .env to Git"]
HARDCODE["❌ Hardcoding token in docker-compose.yml"]
PUBLIC["❌ Posting token in issues/forums"]
SHARE["❌ Sharing .env file via email/chat"]
PERMISSIONS["❌ World-readable .env file"]
end
subgraph "Correct Practices (DO THIS)"
GITIGNORE_CHECK["✓ Verify .env in .gitignore"]
ENV_PATTERN["✓ Use environment variable pattern"]
ROTATE["✓ Rotate tokens regularly"]
RESTRICT["✓ Restrict file permissions"]
SECRETS_MGR["✓ Use secrets manager in production"]
end
COMMIT -.->|leads to| TOKEN_LEAK["Token Exposure"]
HARDCODE -.->|leads to| TOKEN_LEAK
PUBLIC -.->|leads to| TOKEN_LEAK
SHARE -.->|leads to| TOKEN_LEAK
PERMISSIONS -.->|leads to| TOKEN_LEAK
TOKEN_LEAK -.->|enables| UNAUTHORIZED["Unauthorized Access"]
Token Rotation
The CLOUDFLARE_TUNNEL_TOKEN can be rotated by:
- Creating a new tunnel in the Cloudflare dashboard
- Updating the
.envfile with the new token - Restarting containers:
docker-compose restart cloudflared
Common Security Mistakes
Sources : .gitignore1
Troubleshooting
Token Not Found Error
Symptom : cloudflared container fails to start with error about missing token.
Diagnosis :
- Verify
.envfile exists in project root - Check token variable name is exactly
CLOUDFLARE_TUNNEL_TOKEN - Ensure no extra spaces or quotes around the token value
Solution : Create or correct the .env file using .env.sample1 as template.
Token Authentication Failed
Symptom : cloudflared container starts but fails to establish tunnel.
Diagnosis :
- Token may be invalid or expired
- Token may be from a different tunnel
- Tunnel may have been deleted in Cloudflare dashboard
Solution : Generate new token from Cloudflare dashboard and update .env file.
.env File Accidentally Committed
Symptom : .env file appears in Git history.
Immediate Actions :
- Rotate token immediately in Cloudflare dashboard
- Remove file from Git history using
git filter-branchor BFG Repo-Cleaner - Update
.envwith new token - Verify .gitignore1 contains
.env
Environment Variable Reference Table
| Variable | Type | Required | Default | Container | Usage |
|---|---|---|---|---|---|
CLOUDFLARE_TUNNEL_TOKEN | String (JWT) | Yes | None | cloudflared | Authenticates tunnel connection to Cloudflare network |
Sources : .env.sample1
Related Documentation
- docker-compose.yml - How environment variables are consumed in Docker Compose
- Cloudflared Tunnel Connector - How the cloudflared container uses the token
- Local Configuration - Setup instructions for creating
.envfile - Security Model - Overall security architecture and secret management
- Version Control Best Practices - Git workflows for secrets
Sources : .env.sample1 .gitignore:1-2
Dismiss
Refresh this wiki
Enter email to refresh