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.
- 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.,
cloudflare.tunnel.hostname,service) by monitoring container events.
- Auto-configures Tunnel ingress & DNS from Docker labels (e.g.,
- Manual Ingress Rule Management (New!):
- 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.
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.
- Start DockFlare: Run the DockFlare container with the required environment variables.
- Label Your Containers: Add labels to your Docker containers to define their public hostname, service target, and initial desired Access Policy.
- Automatic Configuration: DockFlare detects labeled containers and:
- Updates the Cloudflare Tunnel configuration.
- Creates/updates DNS CNAME records.
- Creates/updates Cloudflare Access Applications based on
access.*labels (if not already UI-overridden).
- Manage Access Policies via UI (Optional): Modify Access Policies directly through the DockFlare web interface. These changes are persistent and override labels. Click "Revert to Labels" to restore label-based management.
- Graceful Deletion: When a container stops, DockFlare schedules its ingress rule and any DockFlare-managed Access Application for deletion after a configurable grace period.
-
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
(Account Settings Read is no needed but planned for upcoming new feature)
- Account ID (found in Cloudflare Dashboard → Overview)
- Zone ID (found in Cloudflare Dashboard → Overview)
- 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:version: '3.8' services: dockflare: image: alplat/dockflare:stable container_name: dockflare restart: unless-stopped ports: - "5000:5000" # Web UI port env_file: - .env # Load environment variables from .env file environment: - STATE_FILE_PATH=/app/data/state.json - TZ=Europe/Zurich # Set your timezone here volumes: - /var/run/docker.sock:/var/run/docker.sock:ro # Required to monitor Docker events - dockflare_data:/app/data # Persistent storage for state networks: - cloudflare-net # Network for communication with cloudflared agent labels: # Optional keep in mind to set access policy - cloudflare.tunnel.enable=true - cloudflare.tunnel.hostname=dockflare.yourdomain.tld # update your domain - cloudflare.tunnel.service=http://dockflare:5000 volumes: dockflare_data: networks: cloudflare-net: name: cloudflare-net
-
Create
.envFile:# Cloudflare API Token (REQUIRED) CF_API_TOKEN=your_cloudflare_api_token # Cloudflare Account ID (REQUIRED) - dash.cloudflare.com/ACCOUNT_ID CF_ACCOUNT_ID=your_cloudflare_account_id # Cloudflare Zone ID (REQUIRED) CF_ZONE_ID=your_cloudflare_zone_id # Tunnel Name (REQUIRED only when NOT using external cloudflared) TUNNEL_NAME=DockFlare # Docker Network Name (internal cloudflared mode) CLOUDFLARED_NETWORK_NAME=cloudflare-net # Label Prefix for Docker Containers LABEL_PREFIX=cloudflare.tunnel # Grace Period for Rule Deletion (seconds, default: 1h) GRACE_PERIOD_SECONDS=6000 # Cleanup Interval (seconds) CLEANUP_INTERVAL_SECONDS=300 # Agent Status Update Interval (seconds) AGENT_STATUS_UPDATE_INTERVAL_SECONDS=10 # Scan All Docker Networks (default: false) SCAN_ALL_NETWORKS=false # Max Concurrent DNS Operations (default: 3) MAX_CONCURRENT_DNS_OPS=3 # Reconciliation Batch Size (default: 3) RECONCILIATION_BATCH_SIZE=3 # Trusted Proxies (IPs/CIDR ranges) # TRUSTED_PROXIES=172.16.0.0/12,192.168.0.0/16 # Default TLS Verification Setting (skip verification) (default: false) DEFAULT_NO_TLS_VERIFY=false STATE_FILE_PATH=/app/data/state.json
-
Run DockFlare:
docker compose up -d
-
Access the Web UI: Open
http://localhost:5000in your browser.
DockFlare supports two approaches for labeling containers:
To expose a single 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 (must be a valid domain you control)
cloudflare.tunnel.hostname: "my-service.example.com"
# The internal service address (protocol://host:port)
cloudflare.tunnel.service: "http://my-service:80"
# Optional: Specify a different zone for this hostname
# cloudflare.tunnel.zonename: "example.com"
# Optional: Disable TLS verification for this service
# cloudflare.tunnel.no_tls_verify: "true"
networks:
- cloudflare-net # Must be in a network that DockFlare can reach To expose multiple domains from a single container, use indexed labels to define each configuration:
services:
multi-domain-service:
image: nginx:latest
labels:
# Enable DockFlare for this container
- "cloudflare.tunnel.enable=true"
# First hostname (using indexed notation)
- "cloudflare.tunnel.0.hostname=my-service.example.com"
- "cloudflare.tunnel.0.service=http://my-service:80"
- "cloudflare.tunnel.0.no_tls_verify=true"
# Second hostname (using indexed notation)
- "cloudflare.tunnel.1.hostname=my-service2.example.com"
- "cloudflare.tunnel.1.service=http://my-service:80"
- "cloudflare.tunnel.1.no_tls_verify=true"
# Third hostname with a different zone
- "cloudflare.tunnel.2.hostname=my-service.otherdomain.com"
- "cloudflare.tunnel.2.service=http://my-service:80"
- "cloudflare.tunnel.2.no_tls_verify=true"
- "cloudflare.tunnel.2.zonename=otherdomain.com"
networks:
- cloudflare-netWith indexed labels, each domain can have:
Different target services (useful for exposing different ports or paths) Different TLS verification settings Different zone names for multi-domain management This feature works with both internal and external cloudflared modes, making it perfect for services that need to be accessible across multiple domains or subdomains.
Note: Index numbers must be sequential starting from 0 (0, 1, 2, etc.). Any gap in the sequence will cause DockFlare to stop processing further indices.
When using the external cloudflared mode, you'll need to provide the Tunnel ID. Here's how to find it:
- Log in to your Cloudflare Dashboard
- Navigate to Access → Tunnels in the left sidebar
- Find your tunnel in the list and click on it
- The Tunnel ID is displayed in two places:
- In the URL of the page:
https://dash.cloudflare.com/[account-id]/access/tunnels/view/[tunnel-id] - In the Overview tab under "Tunnel ID"
- In the URL of the page:
- Copy this ID and set it as your
EXTERNAL_TUNNEL_IDin the.envfile
Example Tunnel ID format: 6ff42ae2-765d-4adf-befc-ca51f8e4e688
If you want to switch from using DockFlare's built-in cloudflared container to an external cloudflared instance, you'll need to perform several cleanup steps to ensure a smooth transition:
-
Stop the DockFlare container first:
docker stop dockflare
-
Remove the existing cloudflared agent container managed by DockFlare:
docker rm -f cloudflared-agent-your_tunnel_name
-
Clean up DNS records in Cloudflare dashboard:
- Navigate to Cloudflare Dashboard → DNS
- Find and delete the CNAME records created for your services
- These typically have names matching your container hostnames and point to
{tunnel-id}.cfargotunnel.com
-
Delete the tunnel in Cloudflare dashboard (if you're creating a new external tunnel):
- Navigate to Cloudflare Dashboard → Access → Tunnels
- Find the tunnel created by DockFlare
- Click the three dots menu → Delete
-
Reset the state file to ensure clean configuration:
# If using Docker volumes docker volume rm dockflare_data # Or if mounted as a file rm /path/to/your/state.json
-
Set up your external cloudflared instance following Cloudflare's documentation:
- Create a new tunnel or use an existing one
- Make sure to note the Tunnel ID
- Configure and run the cloudflared daemon
-
Update your .env file with the external configuration:
USE_EXTERNAL_CLOUDFLARED=true EXTERNAL_TUNNEL_ID=your_external_tunnel_id
-
Restart DockFlare with the new configuration:
docker start dockflare # Or if you removed the volume, you may need to recreate the container docker compose up -d -
Verify container discovery after restart:
- Check the Web UI to ensure your containers are detected
- Verify that DNS records are created for your services
- Test that your services are accessible through the tunnel
After the switch, DockFlare will:
- Discover containers with the appropriate labels
- Create new DNS records pointing to your external tunnel
- Update the ingress configuration for your external tunnel
- Start with a fresh state based on your running containers
Note: During this transition, your services may experience brief downtime as DNS records are deleted and recreated. The DNS propagation might take some time depending on TTL settings.
Important: When switching to external mode, the tunnel name in your .env file is no longer used, but you still need to specify the correct
EXTERNAL_TUNNEL_ID.
| 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 | (Required unless all containers use zonename label) |
TUNNEL_NAME |
Name for the Cloudflare tunnel | dockflared-tunnel (Required unless using external tunnel) |
GRACE_PERIOD_SECONDS |
Time before removing rules after container stops | 28800 (8 hours) |
CLEANUP_INTERVAL_SECONDS |
Interval for checking expired rules | 300 (5 minutes) |
LABEL_PREFIX |
Prefix for Docker labels | cloudflare.tunnel |
USE_EXTERNAL_CLOUDFLARED |
Use an existing cloudflared agent | false |
EXTERNAL_TUNNEL_ID |
Tunnel ID for external cloudflared mode | (Required if USE_EXTERNAL_CLOUDFLARED=true) |
SCAN_ALL_NETWORKS |
Scan containers across all Docker networks | false |
CLOUDFLARED_NETWORK_NAME |
Docker network for cloudflared agent | cloudflare-net |
STATE_FILE_PATH |
Path for state persistence | /app/data/state.json |
| Label | Description | Required | Example |
|---|---|---|---|
{prefix}.enable |
Enable DockFlare for this container | Yes | "true" |
{prefix}.hostname |
Public hostname to expose | Yes | "app.example.com" |
{prefix}.service |
Internal service address | Yes | "http://app:80" |
{prefix}.zonename |
Zone name for this hostname | No | "example.com" |
{prefix}.no_tls_verify |
Disable TLS verification | No | "true" |
These labels define the initial Cloudflare Access Policy for the exposed hostname. Note: These label-defined policies can be overridden by changes made in the DockFlare Web UI. If a UI override is active, these labels will not be re-applied unless the policy is "Reverted to Labels" via the UI.
| Label | Description | Default | Example |
|---|---|---|---|
{prefix}.access.policy |
Defines the type of Access Policy. Common values: bypass (public), authenticate (requires login via configured IdPs), default_tld (inherits from *.yourdomain.com policy, no app created for this specific hostname). |
(None) | 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 for the Access Application (e.g., 24h, 30m). |
24h |
cloudflare.tunnel.access.session_duration="1h" |
{prefix}.access.app_launcher_visible |
If "true", the application will be visible in the Cloudflare App Launcher. |
false |
cloudflare.tunnel.access.app_launcher_visible="true" |
{prefix}.access.allowed_idps |
Comma-separated list of allowed Identity Provider (IdP) UUIDs. If access.policy="authenticate" and this is not set, it typically allows any configured IdP for the account. |
(Account Default) | cloudflare.tunnel.access.allowed_idps="<IdP_UUID_1>,<IdP_UUID_2>" |
{prefix}.access.auto_redirect_to_identity |
If "true", automatically redirects to the identity provider login page. |
false |
cloudflare.tunnel.access.auto_redirect_to_identity="true" |
{prefix}.access.custom_rules |
A JSON string representing an array of Cloudflare Access Policy rules. Overrides access.policy if set to authenticate or bypass for policy decision. See Cloudflare Access Policy Docs for schema. |
(None) | cloudflare.tunnel.access.custom_rules='[{"email":{"email":"user@example.com"},"action":"allow"}]' |
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"
# that requires authentication via the specified GitHub IdP with an 8-hour session.DockFlare can work with an existing cloudflared container. This is useful if you're already using cloudflared for other services or prefer to manage it separately. To enable this mode:
- Set
USE_EXTERNAL_CLOUDFLARED=truein your.envfile. - Provide the external tunnel ID using
EXTERNAL_TUNNEL_ID.
In this mode, DockFlare will only manage DNS records and ingress rules, but not the cloudflared agent itself.
USE_EXTERNAL_CLOUDFLARED=true
EXTERNAL_TUNNEL_ID=your-tunnel-id-from-cloudflareUpdate on version 1.7
The update_cloudflare_config function now takes a more authoritative stance: for the DockFlare-managed tunnel, any non-wildcard, non-catch-all ingress rule found on Cloudflare that is not present in DockFlare's managed_rules (either from Docker labels or manual UI entries) will be removed by DockFlare. This ensures the tunnel configuration accurately reflects DockFlare's intended state. True external wildcards and the API's catch-all rule are still preserved.
This means as well that DNS records that are not present in the DockFlare rules will be removed from your DNS Zone. External Mode is not recommended only if you know what to do and are for Edge cases.
DockFlare provides real-time logs using Server-Sent Events (SSE). Open the "Real-time Activity Logs" section in the Web UI to view logs as they happen. This feature is especially useful for monitoring container events and configuration changes.
DockFlare supports hosting services across multiple Cloudflare zones (domains). There are two ways to specify which zone a hostname belongs to:
-
Container-specific zone using labels: Use the
cloudflare.tunnel.zonenamelabel to specify the zone name for a specific hostname. DockFlare will look up the zone ID automatically. -
Default zone using environment variable: Set the
CF_ZONE_IDenvironment variable as a fallback for any hostname that doesn't specify azonenamelabel.
For multi-domain setups, you have two options:
- Option 1: Set
CF_ZONE_IDto your primary domain's Zone ID, and usezonenamelabels only for hostnames in other zones - Option 2: Always specify
zonenamelabels for all hostnames, making theCF_ZONE_IDenvironment variable optional
Note: When using wildcard domains like
*.example.com, ensure you're using the correct zone, either via thezonenamelabel or the defaultCF_ZONE_ID.
services:
my-service:
# ...other configuration...
labels:
cloudflare.tunnel.0.enable: "true"
cloudflare.tunnel.0.hostname: "app.customdomain.com"
cloudflare.tunnel.0.service: "http://my-service:80"
cloudflare.tunnel.0.zonename: "customdomain.com" # Explicitly defines the zoneDockFlare supports wildcard domains for routing all subdomains through your tunnel:
services:
wildcard-service:
image: nginx:latest
labels:
- "cloudflare.tunnel.enable=true"
# Wildcard domain - routes all subdomains
- "cloudflare.tunnel.hostname=*.example.com"
- "cloudflare.tunnel.service=https://my-service:443"
- "cloudflare.tunnel.no_tls_verify=true"
networks:
- cloudflare-netThis configuration will route all subdomains of example.com through your tunnel to the specified service. This is useful for:
- Multi-tenant applications where each tenant gets their own subdomain
- Development environments with dynamic subdomains
- Catch-all routing for a domain
Note: Specific subdomain rules take precedence over wildcard rules. For example, if you have both
*.example.comandspecific.example.comconfigured, requests tospecific.example.comwill be routed according to its specific rule.
DockFlare includes several features to optimize performance and prevent rate limiting:
-
Concurrent DNS Operation Limiting:
- Controls how many simultaneous DNS operations can run
- Prevents Cloudflare API rate limiting during large reconciliations
- Configurable via
MAX_CONCURRENT_DNS_OPS(default: 3)
-
Batched DNS Processing:
- Processes DNS records in small batches during reconciliation
- Shows real-time progress feedback in the web UI
- Configurable via
RECONCILIATION_BATCH_SIZE(default: 3)
-
Asynchronous Initialization:
- Web UI is immediately available while initialization continues
- Progress indicators show current status of initialization and reconciliation
These optimizations are particularly helpful when managing tunnels with many domains or when running on systems with limited resources.
- Log Stream Not Working: Ensure your browser supports Server-Sent Events (SSE). Try a different browser or check for network filtering.
- Reverse Proxy Issues: If you're using a reverse proxy in front of DockFlare's Web UI, make sure it's configured to properly handle SSE connections and WebSocket connections.
- Container Not Being Detected: Verify that:
- Your container has the right labels
- The container is in a network DockFlare can access (use
SCAN_ALL_NETWORKS=trueif needed) - The hostname format is valid (must be a proper domain name)
- The service format is valid (must include protocol and host:port)
-
Check the logs in the Web UI or the container logs using:
docker logs dockflare
-
Verify Cloudflare API token permissions: Requires Zone:DNS:Edit and Account:Cloudflare Tunnel:Edit
-
If a container stops responding to changes, try forcing deletion of the rule via the Web UI and then restart the container.
- DockFlare Health: Access
http://localhost:5000/pingfor basic health information - Cloudflare Connectivity: Access
http://localhost:5000/cloudflare-pingthrough your tunnel to verify Cloudflare connection details
Contributions are welcome! Please open an issue or submit a pull request on GitHub.
- Fork the repository
- Create a feature branch (
git checkout -b feature/amazing-feature) - Commit your changes (
git commit -m 'Add some amazing feature') - Push to the branch (
git push origin feature/amazing-feature) - Open a Pull Request
DockFlare is licensed under the GNU General Public License version 3 License. See LICENSE.MD for details.