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 using the new
dockflare.*
prefix (backward compatible withcloudflare.tunnel.*
). - Supports various service types (
http
,https
,tcp
,ssh
,rdp
,http_status
). - Controls
no_tls_verify
andoriginServerName
(SNI) for origin connections. - NEW: Define
httpHostHeader
to override the Host header sent to your origin service.
- Auto-configures Tunnel ingress & DNS from Docker labels using the new
- Flexible Routing: Multi-Path, Multi-Hostname & Multi-Zone:
- NEW: Route multiple URL paths on the same hostname to a single service (e.g.,
app.com/api
andapp.com/web
). - Supports multiple hostnames (unique targets, zones, policies) per Docker container using indexed labels.
- NEW: Route multiple URL paths on the same hostname to a single service (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.,
- 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: # - "dockflare.enable=true" # - "dockflare.hostname=dockflare.yourdomain.tld" # - "dockflare.service=http://dockflare:5000" # - "dockflare.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, the '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=dockflare. # The default is now 'dockflare.'. Uncomment to customize. 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 supports exporting the native Prometheus metrics from the managed cloudflared
agent, allowing you to monitor the health and performance of your tunnel with tools like Prometheus and Grafana.
To enable the metrics endpoint, simply add the following environment variable to your .env
file:
# .env.example
# Enables the Prometheus metrics endpoint on the specified port.
# This port will be exposed to the Docker host.
CLOUDFLARED_METRICS_PORT=2000
DockFlare's built-in reconciliation logic will automatically handle everything for you. If you add, remove, or change this variable and restart DockFlare, the cloudflared-agent
container will be automatically recreated with the correct settings.
Once enabled, you'll need a Prometheus instance to scrape the metrics endpoint.
To help you get started immediately, a pre-built, detailed Grafana dashboard is included in the repository at examples/dashboard.json
. You can import this file directly into your Grafana instance to get instant visibility into:
- Request & Error Rates
- Request Latency Percentiles (P99, P95, P50)
- Active HA Connections
- HTTP Status Code Breakdowns
- And more...
Quick Start: Prometheus & Grafana Docker Compose Setup
If you don't already have a monitoring stack, here is a minimal setup to add to your docker-compose.yml
to start scraping and visualizing your tunnel metrics.
Create these files and folders next to your main docker-compose.yml
:
.
βββ docker-compose.yml
βββ prometheus.yml
βββ grafana-provisioning/
βββ datasources/
βββ datasource.yml
Add the following services to your docker-compose.yml
:
services:
# ... your existing dockflare service ...
prometheus:
image: prom/prometheus:latest
container_name: prometheus
restart: unless-stopped
volumes:
- ./prometheus.yml:/etc/prometheus/prometheus.yml
- ./prometheus_data:/prometheus
command:
- '--config.file=/etc/prometheus/prometheus.yml'
networks:
- your-dockflare-network # <-- IMPORTANT: Use the same network as DockFlare
labels:
- "dockflare.enable=true"
- "dockflare.hostname=prometheus.your-domain.com"
- "dockflare.service=http://prometheus:9090"
grafana:
image: grafana/grafana-oss:latest
container_name: grafana
restart: unless-stopped
volumes:
- ./grafana_data:/var/lib/grafana
- ./grafana-provisioning:/etc/grafana/provisioning
networks:
- your-dockflare-network # <-- IMPORTANT: Use the same network as DockFlare
labels:
- "dockflare.enable=true"
- "dockflare.hostname=metrics.your-domain.com" # Exposes Grafana
- "dockflare.service=http://grafana:3000"
Permissions Tip: If you encounter a "Permission denied" error on startup, you may need to set the ownership of the host directories. Run
sudo chown -R 472:472 ./grafana_data
for Grafana andsudo chown -R 65534:65534 ./prometheus_data
for Prometheus.
Create the prometheus.yml
file with the following content:
global:
scrape_interval: 15s
scrape_configs:
- job_name: 'cloudflared'
static_configs:
- targets: ['your-agent-container-name:2000']
# --- IMPORTANT ---
# 1. Replace 'your-agent-container-name' with the name of your cloudflared container.
# 2. Replace '2000' with your chosen CLOUDFLARED_METRICS_PORT.
Create the grafana-provisioning/datasources/datasource.yml
file:
apiVersion: 1
datasources:
- name: Prometheus
type: prometheus
access: proxy
url: http://prometheus:9090
isDefault: true
- Run
docker-compose up -d
. - Navigate to your Prometheus URL and check Status -> Targets to ensure the
cloudflared
job is UP. - Navigate to your Grafana URL, log in (default:
admin
/admin
), and import thedashboard.json
from theexamples/
directory.
DockFlare listens for Docker container events.
- Label-First for Initial Setup: By labeling your containers with the new
dockflare.
prefix, 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)
Note: As of v1.8.9, the recommended label prefix is
dockflare.
. The oldcloudflare.tunnel.
prefix is still fully supported for backward compatibility.
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
- "dockflare.enable=true"
# The public hostname to expose
- "dockflare.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.
- "dockflare.service=http://my-service:80"
# Optional: Specify a URL path. Only requests to hostname/path will match.
# - "dockflare.path=/app"
# Optional: Specify a different Cloudflare Zone for this hostname
# - "dockflare.zonename=another.example.com"
# Optional: Disable TLS verification if your internal service uses HTTP or a self-signed cert
# - "dockflare.no_tls_verify=true"
# Optional: Specify Origin Server Name (SNI) for TLS connection to origin
# - "dockflare.originsrvname=internal.service.local"
# Optional: Override the HTTP Host header sent to the origin
# Applies only to HTTP/HTTPS services.
# - "dockflare.httpHostHeader=actual.backend.host"
networks:
- cloudflare-net
To expose multiple hostnames, paths, or services from a single container, use indexed labels:
services:
my-api-gateway:
image: nginx:alpine
labels:
- "dockflare.enable=true"
# --- Rule 0: Root path (/) for api.example.com ---
- "dockflare.0.hostname=api.example.com"
- "dockflare.0.service=http://my-api-gateway:80"
- "dockflare.0.httpHostHeader=internal-api-service" # Specific Host header for this rule
# --- Rule 1: /v1 path for api.example.com ---
- "dockflare.1.hostname=api.example.com"
- "dockflare.1.path=/v1"
- "dockflare.1.service=http://my-api-gateway:80"
- "dockflare.1.no_tls_verify=true"
# --- Rule 2: A different hostname and service on the same container ---
- "dockflare.2.hostname=status.example.com"
- "dockflare.2.service=http://my-api-gateway:80" # Points to a different Nginx location block
- "dockflare.2.access.policy=authenticate"
# Note: Default values (like for 'service') can be set without an 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 service. UI changes persist and override these labels unless "Reverted to Labels".
Label | Description | Default | Example |
---|---|---|---|
dockflare.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) | dockflare.access.policy="authenticate" |
dockflare.access.name |
Custom name for the Cloudflare Access Application. | DockFlare-{hostname} |
dockflare.access.name="My Web App Access" |
dockflare.access.session_duration |
Session duration (e.g., 24h , 30m ). |
24h |
dockflare.access.session_duration="1h" |
dockflare.access.app_launcher_visible |
If "true" , app is visible in Cloudflare App Launcher. |
false |
dockflare.access.app_launcher_visible="true" |
dockflare.access.allowed_idps |
Comma-separated IdP UUIDs. If authenticate & unset, allows any account IdP. |
(Account Default) | dockflare.access.allowed_idps="<IdP_UUID_1>,<IdP_UUID_2>" |
dockflare.access.auto_redirect_to_identity |
If "true" , auto-redirects to IdP login. |
false |
dockflare.access.auto_redirect_to_identity="true" |
dockflare.access.custom_rules |
JSON string array of Cloudflare Access Policy rules. Overrides basic access.policy decisions. |
(None) | '...=[{"email":{"email":"user@example.com"},"action":"allow"},{"action":"block"}]' |
Example of Access Policy Labels:
labels:
- "dockflare.enable=true"
- "dockflare.hostname=secure-app.example.com"
- "dockflare.service=http://my-secure-app:8080"
- "dockflare.access.policy=authenticate"
- "dockflare.access.session_duration=8h"
# - "dockflare.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 |
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
dockflare.zonename="yourdomain.com"
on a container (or indexed entry) to specify its zone. DockFlare resolves the Zone ID automatically.labels: - "dockflare.0.hostname=app.customdomain.com" - "dockflare.0.service=http://my-service:80" - "dockflare.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.