DockFlare simplifies Cloudflare Tunnel and Zero Trust Access policy management by using Docker labels for automated configuration, while also providing a powerful web UI for manual service definitions and policy overrides. It enables secure, hassle-free public access to both Dockerized and non-Dockerized applications with minimal direct interaction with Cloudflare. Acting as a dynamic, self-hosted ingress controller, DockFlare offers persistent, UI-driven control over access policies centralizing and streamlining your access management.
✨ Key Features
- Unified Cloudflare Tunnel Management:
- Automates Tunnel creation/use &
cloudflared
agent lifecycle (optional internal deployment or external).
- Automates Tunnel creation/use &
- Dynamic Ingress via Docker Labels:
- Auto-configures Tunnel ingress & DNS from Docker labels (e.g.,
hostname
,service
,path
). - Supports various service types (
http
,https
,tcp
,ssh
,rdp
,http_status
). - Controls
no_tls_verify
andoriginServerName
(SNI) for origin connections.
- Auto-configures Tunnel ingress & DNS from Docker labels (e.g.,
- Manual Ingress Rule Management:
- Add & manage public hostnames for non-Docker services (e.g., router, NAS) via Web UI; DockFlare handles Tunnel rules & DNS.
- Versatile Access Policy Control (Docker & Manual):
- Define Cloudflare Access Policies (e.g.,
bypass
,authenticate
, custom JSON) via Docker labels; auto-manages Access Applications. - Web UI to manage/override policies for any rule; UI changes persist, override labels, with revert option & clear indicators.
- Define Cloudflare Access Policies (e.g.,
- Multi-Hostname & Multi-Zone:
- Supports multiple hostnames (unique targets, zones, policies) per Docker container (indexed labels) or manual rule.
- State Persistence & Graceful Deletion:
- Configurable grace period for Docker rule cleanup; persists all managed rules, Access App IDs, & UI overrides in
state.json
.
- Configurable grace period for Docker rule cleanup; persists all managed rules, Access App IDs, & UI overrides in
- Intelligent Reconciliation:
- Continuously syncs Docker, manual entries, & saved state (respecting UI overrides) with Cloudflare (Tunnel, DNS, Access Apps); shows UI progress.
- Comprehensive Web UI (DaisyUI):
- Dashboard: Tunnel/agent status & controls.
- Unified Rule List: View/manage all rules (Docker & manual) with status, target, Access Policy (Cloudflare links, UI override badges), & delete options.
- Easy Manual Entry: Add non-Docker services via UI.
- Account Tools: View account tunnels/DNS.
- Real-time Logs & Themes: SSE activity logs & multiple UI themes.
- Secure & Robust:
- Content Security Policy (CSP), API retries, and error reporting.
📋 Important Prerequisites for Cloudflare API
- Docker: Install Docker
- Docker Compose: Install Docker Compose
- Cloudflare Account with:
- API Token with Account:Cloudflare Tunnel:Edit, Account:Account Settings:Read, Account:Access: Apps and Policies:Edit, Zone:Zone:Read, Zone:DNS:Edit
(Note: Account Settings Read is planned for future features, not strictly required for current core functionality.)
- Account ID (found in Cloudflare Dashboard → Overview)
- Zone ID (found in Cloudflare Dashboard → Overview for your primary domain)
- API Token with Account:Cloudflare Tunnel:Edit, Account:Account Settings:Read, Account:Access: Apps and Policies:Edit, Zone:Zone:Read, Zone:DNS:Edit
-
Create
docker-compose.yml
:# Your docker-compose.yml content version: '3.8' services: dockflare: image: alplat/dockflare:stable # Or :unstable for the latest features container_name: dockflare restart: unless-stopped ports: - "5000:5000" env_file: - .env environment: - STATE_FILE_PATH=/app/data/state.json - TZ=Europe/Zurich # Set your timezone volumes: - /var/run/docker.sock:/var/run/docker.sock:ro - dockflare_data:/app/data networks: - cloudflare-net # Optional labels to expose DockFlare itself via DockFlare # labels: # - cloudflare.tunnel.enable=true # - cloudflare.tunnel.hostname=dockflare.yourdomain.tld # - cloudflare.tunnel.service=http://dockflare:5000 # - cloudflare.tunnel.access.policy=authenticate # Example: require login volumes: dockflare_data: networks: cloudflare-net: name: cloudflare-net
-
Create
.env
File: Copyenv.example
to.env
and fill in your details.📄 Example `.env` content (Click to expand)
# === REQUIRED CLOUDFLARE CREDENTIALS === CF_API_TOKEN=your_cloudflare_api_token_here CF_ACCOUNT_ID=your_cloudflare_account_id_here # Default Cloudflare Zone ID (Recommended) # If not set, cloudflare.tunnel.zonename label is REQUIRED for all services. CF_ZONE_ID=your_default_cloudflare_zone_id_here # === TUNNEL CONFIGURATION === # Name for the Cloudflare Tunnel managed by DockFlare # (Required if NOT using an external cloudflared instance) TUNNEL_NAME=DockFlare-Tunnel # === DOCKFLARE BEHAVIOR & CUSTOMIZATION === LABEL_PREFIX=cloudflare.tunnel GRACE_PERIOD_SECONDS=28800 CLEANUP_INTERVAL_SECONDS=300 AGENT_STATUS_UPDATE_INTERVAL_SECONDS=10 # STATE_FILE_PATH=/app/data/state.json # Usually set in docker-compose SCAN_ALL_NETWORKS=false CLOUDFLARED_NETWORK_NAME=cloudflare-net # TUNNEL_DNS_SCAN_ZONE_NAMES=extradomain.com,another-zone.net # === PERFORMANCE & RESOURCE MANAGEMENT === MAX_CONCURRENT_DNS_OPS=3 # RECONCILIATION_BATCH_SIZE=3 # Placeholder
Refer to
env.example
for a full list of options and detailed comments. -
Run DockFlare:
docker compose up -d
-
Access the Web UI: Open
http://your-server-ip:5000
in your browser.
DockFlare listens for Docker container events.
- Label-First for Initial Setup: By labeling your containers, DockFlare initially configures Cloudflare Tunnel ingress rules, DNS records, and associated Cloudflare Zero Trust Access Applications.
- UI for Dynamic Overrides: The Web UI allows you to dynamically change Access Policies for individual services. These UI changes take precedence over container labels and are persistent.
- Revert Option: You can always revert a UI-managed Access Policy back to be controlled by the container's labels via the Web UI.
📝 Labeling Your Containers (Examples & Details)
DockFlare supports two approaches for labeling containers:
To expose a service through DockFlare, add the following labels to your container:
services:
my-service:
image: nginx:latest
labels:
# Enable DockFlare management for this container
- "cloudflare.tunnel.enable=true"
# The public hostname to expose
- "cloudflare.tunnel.hostname=my-service.example.com"
# The internal service address (protocol://container_name_or_ip:port)
# Service type (http, https, tcp, ssh, rdp, http_status) is inferred from the prefix.
- "cloudflare.tunnel.service=http://my-service:80"
# Optional: Specify a URL path. Only requests to hostname/path will match.
# - "cloudflare.tunnel.path=/app"
# Optional: Specify a different Cloudflare Zone for this hostname
# - "cloudflare.tunnel.zonename=another.example.com"
# Optional: Disable TLS verification if your internal service uses HTTP or a self-signed cert
# - "cloudflare.tunnel.no_tls_verify=true"
# Optional: Specify Origin Server Name (SNI) for TLS connection to origin
# - "cloudflare.tunnel.originsrvname=internal.service.local"
networks:
- cloudflare-net
To expose multiple hostnames or services from a single container, use indexed labels:
services:
multi-host-app:
image: my-custom-app:latest
labels:
- "cloudflare.tunnel.enable=true"
# First hostname configuration
- "cloudflare.tunnel.0.hostname=app1.example.com"
- "cloudflare.tunnel.0.service=http://multi-host-app:8080" # Points to port 8080
- "cloudflare.tunnel.0.path=/frontend" # Path for this specific hostname/service
# - "cloudflare.tunnel.0.originsrvname=app1-sni.internal"
# - "cloudflare.tunnel.0.access.policy=authenticate"
# Second hostname configuration
- "cloudflare.tunnel.1.hostname=api.example.com"
- "cloudflare.tunnel.1.service=tcp://multi-host-app:3000" # Example of TCP service
# - "cloudflare.tunnel.1.path=/rpc" # Path might be less common for TCP but possible
# - "cloudflare.tunnel.1.zonename=otherexample.com"
# - "cloudflare.tunnel.1.no_tls_verify=true" # Not typical for TCP but shown as an option
# - "cloudflare.tunnel.1.originsrvname=api-sni.internal"
# Note: Default service/path/originsrvname can also be set without index,
# and indexed entries will fall back to them if not specified.
networks:
- cloudflare-net
Note: Index numbers must be sequential starting from
0
(e.g.,0
,1
,2
). Any gap will stop further processing of indexed labels for that container. Each indexed entry is treated as a separate rule.
🛡️ Access Policy Labels (Zero Trust)
These labels define the initial Cloudflare Access Policy for an exposed hostname
. UI changes persist and override these labels unless "Reverted to Labels".
Label | Description | Default | Example |
---|---|---|---|
{prefix}.access.policy |
Type: bypass (public app), authenticate (IdP login), default_tld (inherits from *.domain.com policy, no specific app created). If unset, service is public (no Access App). |
(None/Public) | cloudflare.tunnel.access.policy="authenticate" |
{prefix}.access.name |
Custom name for the Cloudflare Access Application. | DockFlare-{hostname} |
cloudflare.tunnel.access.name="My Web App Access" |
{prefix}.access.session_duration |
Session duration (e.g., 24h , 30m ). |
24h |
cloudflare.tunnel.access.session_duration="1h" |
{prefix}.access.app_launcher_visible |
If "true" , app is visible in Cloudflare App Launcher. |
false |
cloudflare.tunnel.access.app_launcher_visible="true" |
{prefix}.access.allowed_idps |
Comma-separated IdP UUIDs. If authenticate & unset, allows any account IdP. |
(Account Default) | cloudflare.tunnel.access.allowed_idps="<IdP_UUID_1>,<IdP_UUID_2>" |
{prefix}.access.auto_redirect_to_identity |
If "true" , auto-redirects to IdP login. |
false |
cloudflare.tunnel.access.auto_redirect_to_identity="true" |
{prefix}.access.custom_rules |
JSON string array of Cloudflare Access Policy rules. Overrides basic access.policy decisions. |
(None) | '...=[{"email":{"email":"[email protected]"},"action":"allow"},{"action":"block"}]' |
Example of Access Policy Labels:
labels:
- "cloudflare.tunnel.enable=true"
- "cloudflare.tunnel.hostname=secure-app.example.com"
- "cloudflare.tunnel.service=http://my-secure-app:8080"
- "cloudflare.tunnel.access.policy=authenticate"
- "cloudflare.tunnel.access.session_duration=8h"
# - "cloudflare.tunnel.access.allowed_idps=YOUR_GITHUB_IDP_UUID_HERE"
This creates an Access Application named "DockFlare-secure-app.example.com" requiring authentication with an 8-hour session.
⚙️ All Environment Variables
Variable | Description | Default |
---|---|---|
CF_API_TOKEN |
Cloudflare API token | (Required) |
CF_ACCOUNT_ID |
Cloudflare account ID | (Required) |
CF_ZONE_ID |
Default/fallback Cloudflare zone ID. | (None - zonename label needed) |
TUNNEL_NAME |
Name for the Cloudflare tunnel (if DockFlare manages it). | dockflared-tunnel |
GRACE_PERIOD_SECONDS |
Time (sec) before removing rules after container stops. | 28800 (8 hours) |
CLEANUP_INTERVAL_SECONDS |
Interval (sec) for checking expired rules. | 300 (5 minutes) |
AGENT_STATUS_UPDATE_INTERVAL_SECONDS |
Interval (sec) to update managed agent status. | 10 |
LABEL_PREFIX |
Prefix for Docker labels. | cloudflare.tunnel |
USE_EXTERNAL_CLOUDFLARED |
Set to true to use an existing cloudflared agent. |
false |
EXTERNAL_TUNNEL_ID |
Tunnel ID for external cloudflared mode. |
(Required if external is true) |
SCAN_ALL_NETWORKS |
Scan containers across all Docker networks. | false |
CLOUDFLARED_NETWORK_NAME |
Docker network for DockFlare's managed cloudflared agent. |
cloudflare-net |
STATE_FILE_PATH |
Path inside container for state persistence (state.json ). |
/app/data/state.json |
TUNNEL_DNS_SCAN_ZONE_NAMES |
Comma-separated additional Zone NAMES for UI DNS scan (e.g., another.com,mydomain.org ). |
(None) |
MAX_CONCURRENT_DNS_OPS |
Limits simultaneous DNS API calls during reconciliation. | 3 |
RECONCILIATION_BATCH_SIZE |
(Placeholder for future) DNS records to process per batch. | 3 |
ACCOUNT_EMAIL_CACHE_TTL |
(Internal) How long to cache the account email (seconds). | 3600 (1 hour) |
TZ |
Set timezone for the container, e.g. America/New_York . Affects log timestamps. |
(System Default) |
🔄 External `cloudflared` Mode & Switching
[!CAUTION] ADVANCED USERS ONLY - HIGH POTENTIAL FOR MISCONFIGURATION
External
cloudflared
mode is powerful but requires a deep understanding of Docker networking and Cloudflare Tunnels. Misconfiguration can easily lead to services being unreachable or DockFlare being unable to manage resources correctly.Proceed with extreme caution and only if you are comfortable managing
cloudflared
and Docker network configurations independently. This mode is not recommended for users new to Docker or Cloudflare Tunnels.
DockFlare can integrate with an existing cloudflared
tunnel that you manage completely separately (i.e., not started or configured by DockFlare). In this mode, DockFlare focuses on DNS and Cloudflare Access Application management for that tunnel.
Critical Prerequisite: Docker Network Configuration
- For DockFlare to successfully interact with your services when using an external
cloudflared
tunnel, all relevant containers (DockFlare itself, your target application containers, and potentially your externally managedcloudflared
agent if it needs to resolve services by Docker DNS) must share a common Docker network and be able to communicate. - You are responsible for ensuring that the "Service Address" you define in DockFlare (via labels or UI) is resolvable and reachable from your externally managed
cloudflared
agent. - Incorrect network setup is the most common source of issues in this mode.
To Use External Mode:
-
Set
USE_EXTERNAL_CLOUDFLARED=true
in your.env
file. -
Set
EXTERNAL_TUNNEL_ID
in your.env
file to your existing tunnel's UUID.How to Find Your Existing Tunnel ID
- Log in to the Cloudflare Dashboard.
- Navigate to Zero Trust -> Access -> Tunnels.
- Select your desired pre-existing tunnel.
- The Tunnel ID (a UUID) is displayed on the tunnel's overview page and is also present in the URL.
DockFlare's Behavior in External Mode:
- ✅ WILL create/update/delete CNAME DNS records in your configured Cloudflare zones, pointing to your
EXTERNAL_TUNNEL_ID
. - ✅ WILL create/update/delete Cloudflare Access Applications based on Docker labels or UI interactions for services it manages.
- ❌ WILL NOT start, stop, or manage a
cloudflared
agent Docker container. You are fully responsible for the lifecycle and configuration of yourcloudflared
agent. - ❌ WILL NOT modify the tunnel's ingress rules via the Cloudflare API. Ingress routing (which public hostnames/paths map to which internal services) must be configured directly in your externally managed
cloudflared
agent's configuration file (e.g.,config.yml
). DockFlare assumes your externalcloudflared
agent is already correctly routing traffic for the hostnames it manages DNS for.
[!WARNING] Authoritative DNS Management in External Mode: When
USE_EXTERNAL_CLOUDFLARED=true
, DockFlare assumes it has authoritative control over CNAME DNS records in the specified Cloudflare zones that point to theEXTERNAL_TUNNEL_ID
.
- It may remove CNAME records it doesn't recognize as actively managed by its current rules if those CNAMEs point to the same
EXTERNAL_TUNNEL_ID
within the monitored zones.- Ensure no other systems or manual configurations are creating CNAMEs for this specific external tunnel in the zones DockFlare monitors, as they might be overwritten or deleted.
Before Enabling External Mode, Ensure You Can Answer "Yes" To:
- Do I have a
cloudflared
tunnel already running and configured independently of DockFlare? - Does my external
cloudflared
agent's configuration file (config.yml
) correctly define ingress rules for the services I want DockFlare to manage DNS/Access for? - Are DockFlare, my target application containers, and my external
cloudflared
agent (if resolving services by Docker DNS) all on a shared Docker network that allows them to communicate as needed? - Am I comfortable troubleshooting Docker networking issues independently?
- Do I understand that DockFlare will manage DNS records pointing to my external tunnel ID and may remove conflicting ones?
If you cannot confidently answer "yes" to all these questions, using DockFlare's default managed cloudflared
mode is strongly recommended.
Switching Modes (e.g., Internal to External): This requires careful steps to avoid conflicts.
- Stop DockFlare:
docker compose stop dockflare
- If moving from Internal to External:
- Remove the DockFlare-managed agent:
docker rm -f cloudflared-agent-YOUR_TUNNEL_NAME
(replaceYOUR_TUNNEL_NAME
with the value from your old.env
). - Consider deleting the old tunnel object and its DNS CNAMEs from the Cloudflare dashboard if you are setting up a brand new external tunnel.
- Remove the DockFlare-managed agent:
- Set up your external
cloudflared
agent and get its Tunnel ID. - Update
.env
: SetUSE_EXTERNAL_CLOUDFLARED=true
andEXTERNAL_TUNNEL_ID
. Clear or comment outTUNNEL_NAME
. - Optional: Clear Old State: For a clean switch, you might consider removing the old
state.json
(e.g.,docker volume rm dockflare_data
thendocker volume create dockflare_data
, or delete the file if mapped to host). DockFlare will then rebuild state from active containers. - Start DockFlare:
docker compose up -d dockflare
- Verify: Check UI, logs, and Cloudflare dashboard.
🗺️ Multi-Zone DNS Management
DockFlare handles services across multiple Cloudflare zones (domains).
- Container-Specific Zone (Label):
Use
cloudflare.tunnel.zonename="yourdomain.com"
on a container (or indexed entry) to specify its zone. DockFlare resolves the Zone ID automatically.labels: - "cloudflare.tunnel.0.hostname=app.customdomain.com" - "cloudflare.tunnel.0.service=http://my-service:80" - "cloudflare.tunnel.0.zonename=customdomain.com"
- Default Zone (Environment Variable):
Set
CF_ZONE_ID
in your.env
file. This is used if azonename
label isn't provided for a rule. - UI DNS Scan (Multiple Zones):
To see DNS records for a tunnel across multiple zones you own (in the "All Cloudflare Tunnels" UI section), set
TUNNEL_DNS_SCAN_ZONE_NAMES
in your.env
with a comma-separated list of zone names (e.g.,TUNNEL_DNS_SCAN_ZONE_NAMES=domain1.com,another.org
).CF_ZONE_ID
's domain is included automatically if set.
🔍 Troubleshooting & Health Checks
Common Issues:
- Log Stream Not Working: Ensure browser supports SSE. Check for network filtering or reverse proxy issues (ensure SSE/long-polling is allowed).
- Container Not Detected:
- Verify correct labels (prefix, enable, hostname, service).
- Container network accessible by DockFlare/agent (or
SCAN_ALL_NETWORKS=true
). - Valid hostname and service format (e.g.,
http://host:port
).
- Cloudflare API Errors: Check
CF_API_TOKEN
permissions,CF_ACCOUNT_ID
, andCF_ZONE_ID
.
Debugging:
- View logs in DockFlare Web UI or via
docker logs dockflare
.
Health Checks:
- DockFlare App Ping:
http://<dockflare_host>:5000/ping
- Cloudflare Connectivity (via Tunnel): Access
http://<your_dockflare_public_hostname>/cloudflare-ping
(if you've exposed DockFlare itself) to check headers from Cloudflare.
Contributions are welcome! Please see CONTRIBUTING.md or open an issue/PR.
DockFlare is licensed under the GNU General Public License v3.0. See LICENSE.MD for details.