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 &
cloudflaredagent 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_verifyandoriginServerName(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
.envFile: Copyenv.exampleto.envand 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.examplefor a full list of options and detailed comments. -
Run DockFlare:
docker compose up -d
-
Access the Web UI: Open
http://your-server-ip:5000in 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-netNote: 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":"user@example.com"},"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
cloudflaredmode 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
cloudflaredand 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
cloudflaredtunnel, all relevant containers (DockFlare itself, your target application containers, and potentially your externally managedcloudflaredagent 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
cloudflaredagent. - Incorrect network setup is the most common source of issues in this mode.
To Use External Mode:
-
Set
USE_EXTERNAL_CLOUDFLARED=truein your.envfile. -
Set
EXTERNAL_TUNNEL_IDin your.envfile 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
cloudflaredagent Docker container. You are fully responsible for the lifecycle and configuration of yourcloudflaredagent. - β 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
cloudflaredagent's configuration file (e.g.,config.yml). DockFlare assumes your externalcloudflaredagent 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_IDwithin 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
cloudflaredtunnel already running and configured independently of DockFlare? - Does my external
cloudflaredagent'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
cloudflaredagent (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_NAMEwith 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
cloudflaredagent and get its Tunnel ID. - Update
.env: SetUSE_EXTERNAL_CLOUDFLARED=trueandEXTERNAL_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_datathendocker 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_IDin your.envfile. This is used if azonenamelabel 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_NAMESin your.envwith 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_TOKENpermissions,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.