{"id":27832039,"url":"https://github.com/ChrispyBacon-dev/DockFlare","last_synced_at":"2025-05-02T06:01:27.979Z","repository":{"id":288025587,"uuid":"964990473","full_name":"ChrispyBacon-dev/DockFlare","owner":"ChrispyBacon-dev","description":"DockFlare - CloudFlare Tunnel Controller","archived":false,"fork":false,"pushed_at":"2025-04-22T07:56:34.000Z","size":1179,"stargazers_count":275,"open_issues_count":1,"forks_count":18,"subscribers_count":1,"default_branch":"stable","last_synced_at":"2025-04-22T08:43:13.199Z","etag":null,"topics":["automation","cloudflare","cloudflare-dns","cloudflare-dns-api","cloudflare-tunnel","cloudflared","cloudflareddns","dns","docker","docker-compose","ingress-controller","networking","python","reverse-proxy","reverse-proxy-application","selfhosted","zero-trust"],"latest_commit_sha":null,"homepage":"","language":"Python","has_issues":true,"has_wiki":null,"has_pages":null,"mirror_url":null,"source_name":null,"license":"other","status":null,"scm":"git","pull_requests_enabled":true,"icon_url":"https://github.com/ChrispyBacon-dev.png","metadata":{"files":{"readme":"README.MD","changelog":null,"contributing":null,"funding":".github/FUNDING.yml","license":"LICENSE.MD","code_of_conduct":null,"threat_model":null,"audit":null,"citation":null,"codeowners":null,"security":null,"support":null,"governance":null,"roadmap":null,"authors":null,"dei":null,"publiccode":null,"codemeta":null,"zenodo":null},"funding":{"github":["ChrispyBacon-dev"]}},"created_at":"2025-04-12T07:03:12.000Z","updated_at":"2025-04-22T08:03:06.000Z","dependencies_parsed_at":"2025-04-15T07:34:42.112Z","dependency_job_id":"fe0d5387-3b62-4165-85cd-780fdf4d5419","html_url":"https://github.com/ChrispyBacon-dev/DockFlare","commit_stats":null,"previous_names":["chrispybacon-dev/dockflare"],"tags_count":1,"template":false,"template_full_name":null,"repository_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repositories/ChrispyBacon-dev%2FDockFlare","tags_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repositories/ChrispyBacon-dev%2FDockFlare/tags","releases_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repositories/ChrispyBacon-dev%2FDockFlare/releases","manifests_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repositories/ChrispyBacon-dev%2FDockFlare/manifests","owner_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/owners/ChrispyBacon-dev","download_url":"https://codeload.github.com/ChrispyBacon-dev/DockFlare/tar.gz/refs/heads/stable","host":{"name":"GitHub","url":"https://github.com","kind":"github","repositories_count":251993055,"owners_count":21677026,"icon_url":"https://github.com/github.png","version":null,"created_at":"2022-05-30T11:31:42.601Z","updated_at":"2022-07-04T15:15:14.044Z","host_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub","repositories_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repositories","repository_names_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repository_names","owners_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/owners"}},"keywords":["automation","cloudflare","cloudflare-dns","cloudflare-dns-api","cloudflare-tunnel","cloudflared","cloudflareddns","dns","docker","docker-compose","ingress-controller","networking","python","reverse-proxy","reverse-proxy-application","selfhosted","zero-trust"],"created_at":"2025-05-02T06:01:22.684Z","updated_at":"2025-05-02T06:01:27.964Z","avatar_url":"https://github.com/ChrispyBacon-dev.png","language":"Python","funding_links":["https://github.com/sponsors/ChrispyBacon-dev"],"categories":["网络信息服务","Python","security"],"sub_categories":["网络代理"],"readme":"![DockFlareBanner](images/bannertr.png)\n[![Maintenance](https://img.shields.io/badge/Maintained%3F-yes-green.svg)](https://github.com/ChrispyBacon-dev/baconflip)\n[![OS](https://img.shields.io/badge/os-linux%20%7C%20windows%20%7C%20macos-brightgreen)]()\n[![CPU Architectures](https://img.shields.io/badge/CPU-x86_64%20%7C%20arm64-brightgreen)](https://en.wikipedia.org/wiki/Central_processing_unit)\n[![Generic badge](https://img.shields.io/badge/Status-Beta-yellow.svg)](https://shields.io/)\n[![Docker Pulls](https://img.shields.io/docker/pulls/alplat/dockflare)](https://hub.docker.com/r/alplat/dockflare)\n[![made-with-python](https://img.shields.io/badge/Made%20with-Python-1f425f.svg)](https://www.python.org/)\n[![GitHub issues](https://img.shields.io/github/issues/ChrispyBacon-dev/dockflare)](https://github.com/ChrispyBacon-dev/dockflare/issues)\n[![GitHub last commit](https://img.shields.io/github/last-commit/ChrispyBacon-dev/dockflare)](https://github.com/ChrispyBacon-dev/dockflare/commits/stable)\n[![GitHub commit activity](https://img.shields.io/github/commit-activity/m/ChrispyBacon-dev/dockflare)](https://github.com/ChrispyBacon-dev/dockflare/commits/stable)\n\nDockFlare automates Cloudflare Tunnel ingress rule management based on Docker container labels, simplifying public exposure of your Dockerized applications. It eliminates manual Cloudflare configuration, acting as a self-hosted ingress controller.\n\n## Key Features\n\n- **Automated Cloudflare Tunnel Management**: Creates/uses a specified tunnel, retrieves Tunnel ID \u0026 Token.\n- **`cloudflared` Agent Lifecycle**: Deploys \u0026 manages the `cloudflared` container (using Tunnel Token).\n- **Dynamic Ingress via Docker Labels**:\n  - Monitors Docker events for containers with labels (prefix: `cloudflare.tunnel.`): `enable=\"true\"`, `hostname=\"subdomain.example.com\"`, `service=\"http://target:port\"`.\n  - Automatically updates Cloudflare Tunnel configuration to match running, labeled containers.\n- **Multi-Domain Support**: Configure multiple domains for a single container using indexed labels, each with its own service target and zone configuration.\n- **Graceful Deletion**: Configurable grace period before removing ingress rules when a container stops.\n- **State Persistence**: Saves `managed_rules` to `state.json` for restarts.\n- **Optimized Reconciliation**: \n  - On startup, ensures consistency between Docker containers, saved state, and Cloudflare configuration\n  - Processes DNS operations in small batches to prevent API rate limiting\n  - Shows real-time reconciliation progress in the UI\n- **Web UI**: Status dashboard with:\n  - Tunnel \u0026 agent status.\n  - Start/Stop agent controls.\n  - Managed ingress rule list with status, container ID, deletion time, and \"Force Delete\" option.\n- **Real-time Log Streaming**: View logs in real-time using Server-Sent Events (SSE).\n- **Content Security Policy (CSP)**: Ensures secure loading of resources and compatibility with reverse proxies.\n\n[Learn more on the GitHub Wiki](https://github.com/ChrispyBacon-dev/DockFlare/wiki)\n\n![Web ui example](images/status_web.png)\n## How It Works\n\nDockFlare listens for Docker container events and manages Cloudflare Tunnel ingress rules dynamically. By labeling your containers, DockFlare automatically configures the tunnel and DNS records, ensuring your services are publicly accessible.\n\n### Example Workflow\n\n1. **Start DockFlare**: Run the DockFlare container with the required environment variables.\n2. **Label Your Containers**: Add labels to your Docker containers to define their public hostname and service target.\n3. **Automatic Configuration**: DockFlare detects the labeled containers and updates the Cloudflare Tunnel configuration and DNS records.\n4. **Graceful Deletion**: When a container stops, DockFlare schedules its ingress rule for deletion after a configurable grace period.\n\n## Getting Started\n\n### Prerequisites\n\n- Docker: [Install Docker](https://docs.docker.com/engine/install/)\n- Docker Compose: [Install Docker Compose](https://docs.docker.com/compose/install/)\n- Cloudflare Account with:\n  - API Token with Zone:DNS:Edit and Account:Cloudflare Tunnel:Edit permissions\n  - Account ID (found in Cloudflare Dashboard → Overview)\n  - Zone ID (found in Cloudflare Dashboard → Overview)\n\n### Quick Start (Using Docker Compose)\n\n1. **Create `docker-compose.yml`**:\n\n   ```yaml\n   version: '3.8'\n   services:\n     dockflare:\n       image: alplat/dockflare:stable\n       container_name: dockflare\n       restart: unless-stopped\n       ports:\n         - \"5000:5000\"  # Web UI port\n       env_file:\n         - .env  # Load environment variables from .env file\n       volumes:\n         - /var/run/docker.sock:/var/run/docker.sock:ro  # Required to monitor Docker events\n         - dockflare_data:/app/data  # Persistent storage for state\n       networks:\n         - cloudflare-net  # Network for communication with cloudflared agent\n   volumes:\n     dockflare_data:\n   networks:\n     cloudflare-net:\n   ```\n\n2. **Create `.env` File**:\n\n   ```dotenv\n   # Required Cloudflare credentials\n   CF_API_TOKEN=your_cloudflare_api_token\n   CF_ACCOUNT_ID=your_cloudflare_account_id\n   CF_ZONE_ID=your_cloudflare_zone_id\n   \n   # Tunnel configuration\n   TUNNEL_NAME=your_tunnel_name\n   \n   # Optional configuration\n   GRACE_PERIOD_SECONDS=28800  # 8 hours before removing rules after container stops\n   LABEL_PREFIX=cloudflare.tunnel  # Prefix for Docker labels\n   \n   # Optional: External cloudflared mode\n   # USE_EXTERNAL_CLOUDFLARED=true\n   # EXTERNAL_TUNNEL_ID=your_external_tunnel_id\n   \n   # Optional: Scanning configuration\n   # SCAN_ALL_NETWORKS=true  # Scan containers across all Docker networks\n   ```\n\n3. **Run DockFlare**:\n\n   ```bash\n   docker compose up -d\n   ```\n\n4. **Access the Web UI**: Open `http://localhost:5000` in your browser.\n\n### Labeling Containers\n\nDockFlare supports two approaches for labeling containers:\n\n#### 1. Standard Labels (Single Domain)\n\nTo expose a single service through DockFlare, add the following labels to your container:\n\n```yaml\nservices:\n  my-service:\n    image: nginx:latest\n    labels:\n      # Enable DockFlare management for this container\n      cloudflare.tunnel.enable: \"true\"\n      \n      # The public hostname to expose (must be a valid domain you control)\n      cloudflare.tunnel.hostname: \"my-service.example.com\"\n      \n      # The internal service address (protocol://host:port)\n      cloudflare.tunnel.service: \"http://my-service:80\"\n      \n      # Optional: Specify a different zone for this hostname\n      # cloudflare.tunnel.zonename: \"example.com\"\n      \n      # Optional: Disable TLS verification for this service\n      # cloudflare.tunnel.no_tls_verify: \"true\"\n    networks:\n      - cloudflare-net  # Must be in a network that DockFlare can reach\n```\n\n#### 2. Indexed Labels (Multiple Domains)\n\nTo expose multiple domains from a single container, use indexed labels to define each configuration:\n\n```yaml\nservices:\n  multi-domain-service:\n    image: nginx:latest\n    labels:\n      # Enable DockFlare for this container\n      - \"cloudflare.tunnel.enable=true\"\n      \n      # First hostname (using indexed notation)\n      - \"cloudflare.tunnel.0.hostname=my-service.example.com\"\n      - \"cloudflare.tunnel.0.service=http://my-service:80\"\n      - \"cloudflare.tunnel.0.no_tls_verify=true\"\n      \n      # Second hostname (using indexed notation)\n      - \"cloudflare.tunnel.1.hostname=my-service2.example.com\"\n      - \"cloudflare.tunnel.1.service=http://my-service:80\"\n      - \"cloudflare.tunnel.1.no_tls_verify=true\"\n      \n      # Third hostname with a different zone\n      - \"cloudflare.tunnel.2.hostname=my-service.otherdomain.com\"\n      - \"cloudflare.tunnel.2.service=http://my-service:80\"\n      - \"cloudflare.tunnel.2.no_tls_verify=true\"\n      - \"cloudflare.tunnel.2.zonename=otherdomain.com\"\n    networks:\n      - cloudflare-net\n```\n\nWith indexed labels, each domain can have:\n\nDifferent target services (useful for exposing different ports or paths)\nDifferent TLS verification settings\nDifferent zone names for multi-domain management\nThis feature works with both internal and external cloudflared modes, making it perfect for services that need to be accessible across multiple domains or subdomains.\n\n\u003e **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.\n\n### Finding Your Tunnel ID\n\nWhen using the external cloudflared mode, you'll need to provide the Tunnel ID. Here's how to find it:\n\n1. Log in to your [Cloudflare Dashboard](https://dash.cloudflare.com)\n2. Navigate to **Access** → **Tunnels** in the left sidebar\n3. Find your tunnel in the list and click on it\n4. The Tunnel ID is displayed in two places:\n   - In the URL of the page: `https://dash.cloudflare.com/[account-id]/access/tunnels/view/[tunnel-id]`\n   - In the **Overview** tab under \"Tunnel ID\"\n5. Copy this ID and set it as your `EXTERNAL_TUNNEL_ID` in the `.env` file\n\nExample Tunnel ID format: `6ff42ae2-765d-4adf-befc-ca51f8e4e688`\n\n### Switching Between Internal and External Cloudflared Modes\n\nIf 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:\n\n1. **Stop the DockFlare container** first:\n   ```bash\n   docker stop dockflare\n   ```\n\n2. **Remove the existing cloudflared agent container** managed by DockFlare:\n   ```bash\n   docker rm -f cloudflared-agent-your_tunnel_name\n   ```\n\n3. **Clean up DNS records in Cloudflare dashboard**:\n   - Navigate to Cloudflare Dashboard → DNS\n   - Find and delete the CNAME records created for your services\n   - These typically have names matching your container hostnames and point to `{tunnel-id}.cfargotunnel.com`\n\n4. **Delete the tunnel in Cloudflare dashboard** (if you're creating a new external tunnel):\n   - Navigate to Cloudflare Dashboard → Access → Tunnels\n   - Find the tunnel created by DockFlare\n   - Click the three dots menu → Delete\n\n5. **Reset the state file** to ensure clean configuration:\n   ```bash\n   # If using Docker volumes\n   docker volume rm dockflare_data\n   # Or if mounted as a file\n   rm /path/to/your/state.json\n   ```\n\n6. **Set up your external cloudflared instance** following Cloudflare's documentation:\n   - Create a new tunnel or use an existing one\n   - Make sure to note the Tunnel ID\n   - Configure and run the cloudflared daemon\n\n7. **Update your .env file** with the external configuration:\n   ```dotenv\n   USE_EXTERNAL_CLOUDFLARED=true\n   EXTERNAL_TUNNEL_ID=your_external_tunnel_id\n   ```\n\n8. **Restart DockFlare** with the new configuration:\n   ```bash\n   docker start dockflare\n   # Or if you removed the volume, you may need to recreate the container\n   docker compose up -d\n   ```\n\n9. **Verify container discovery** after restart:\n   - Check the Web UI to ensure your containers are detected\n   - Verify that DNS records are created for your services\n   - Test that your services are accessible through the tunnel\n\nAfter the switch, DockFlare will:\n- Discover containers with the appropriate labels\n- Create new DNS records pointing to your external tunnel\n- Update the ingress configuration for your external tunnel\n- Start with a fresh state based on your running containers\n\n\u003e **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.\n\n\u003e **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`.\n\n## Advanced Configuration\n\n### Environment Variables\n\n| Variable | Description | Default |\n|----------|-------------|---------|\n| `CF_API_TOKEN` | Cloudflare API token | (Required) |\n| `CF_ACCOUNT_ID` | Cloudflare account ID | (Required) |\n| `CF_ZONE_ID` | Default/fallback Cloudflare zone ID | (Required unless all containers use `zonename` label) |\n| `TUNNEL_NAME` | Name for the Cloudflare tunnel | dockflared-tunnel (Required unless using external tunnel) |\n| `GRACE_PERIOD_SECONDS` | Time before removing rules after container stops | 28800 (8 hours) |\n| `CLEANUP_INTERVAL_SECONDS` | Interval for checking expired rules | 300 (5 minutes) |\n| `LABEL_PREFIX` | Prefix for Docker labels | cloudflare.tunnel |\n| `USE_EXTERNAL_CLOUDFLARED` | Use an existing cloudflared agent | false |\n| `EXTERNAL_TUNNEL_ID` | Tunnel ID for external cloudflared mode | (Required if `USE_EXTERNAL_CLOUDFLARED=true`) |\n| `SCAN_ALL_NETWORKS` | Scan containers across all Docker networks | false |\n| `CLOUDFLARED_NETWORK_NAME` | Docker network for cloudflared agent | cloudflare-net |\n| `STATE_FILE_PATH` | Path for state persistence | /app/data/state.json |\n\n### Container Labels\n\n| Label | Description | Required | Example |\n|-------|-------------|----------|---------|\n| `{prefix}.enable` | Enable DockFlare for this container | Yes | `\"true\"` |\n| `{prefix}.hostname` | Public hostname to expose | Yes | `\"app.example.com\"` |\n| `{prefix}.service` | Internal service address | Yes | `\"http://app:80\"` |\n| `{prefix}.zonename` | Zone name for this hostname | No | `\"example.com\"` |\n| `{prefix}.no_tls_verify` | Disable TLS verification | No | `\"true\"` |\n\n### External Cloudflared Mode\n\nDockFlare 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:\n\n1. Set `USE_EXTERNAL_CLOUDFLARED=true` in your `.env` file.\n2. Provide the external tunnel ID using `EXTERNAL_TUNNEL_ID`.\n\nIn this mode, DockFlare will only manage DNS records and ingress rules, but not the cloudflared agent itself.\n\n```dotenv\nUSE_EXTERNAL_CLOUDFLARED=true\nEXTERNAL_TUNNEL_ID=your-tunnel-id-from-cloudflare\n```\n\n### Real-time Log Streaming\n\nDockFlare 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.\n\n### DNS Zone Management\n\nDockFlare supports hosting services across multiple Cloudflare zones (domains). There are two ways to specify which zone a hostname belongs to:\n\n1. **Container-specific zone using labels**: Use the `cloudflare.tunnel.zonename` label to specify the zone name for a specific hostname. DockFlare will look up the zone ID automatically.\n\n2. **Default zone using environment variable**: Set the `CF_ZONE_ID` environment variable as a fallback for any hostname that doesn't specify a `zonename` label.\n\nFor multi-domain setups, you have two options:\n- **Option 1**: Set `CF_ZONE_ID` to your primary domain's Zone ID, and use `zonename` labels only for hostnames in other zones\n- **Option 2**: Always specify `zonename` labels for all hostnames, making the `CF_ZONE_ID` environment variable optional\n\n\u003e **Note**: When using wildcard domains like `*.example.com`, ensure you're using the correct zone, either via the `zonename` label or the default `CF_ZONE_ID`.\n\n```yaml\nservices:\n  my-service:\n    # ...other configuration...\n    labels:\n      cloudflare.tunnel.0.enable: \"true\"\n      cloudflare.tunnel.0.hostname: \"app.customdomain.com\"\n      cloudflare.tunnel.0.service: \"http://my-service:80\"\n      cloudflare.tunnel.0.zonename: \"customdomain.com\"  # Explicitly defines the zone\n```\n\n#### 3. Wildcard Domain Support\n\nDockFlare supports wildcard domains for routing all subdomains through your tunnel:\n\n```yaml\nservices:\n  wildcard-service:\n    image: nginx:latest\n    labels:\n      - \"cloudflare.tunnel.enable=true\"\n      # Wildcard domain - routes all subdomains\n      - \"cloudflare.tunnel.hostname=*.example.com\"\n      - \"cloudflare.tunnel.service=https://my-service:443\"\n      - \"cloudflare.tunnel.no_tls_verify=true\"\n    networks:\n      - cloudflare-net\n```\n\nThis configuration will route all subdomains of example.com through your tunnel to the specified service. This is useful for:\n- Multi-tenant applications where each tenant gets their own subdomain\n- Development environments with dynamic subdomains\n- Catch-all routing for a domain\n\n\u003e **Note**: Specific subdomain rules take precedence over wildcard rules. For example, if you have both `*.example.com` and `specific.example.com` configured, requests to `specific.example.com` will be routed according to its specific rule.\n\n### Performance Tuning\n\nDockFlare includes several features to optimize performance and prevent rate limiting:\n\n1. **Concurrent DNS Operation Limiting**: \n   - Controls how many simultaneous DNS operations can run\n   - Prevents Cloudflare API rate limiting during large reconciliations\n   - Configurable via `MAX_CONCURRENT_DNS_OPS` (default: 3)\n\n2. **Batched DNS Processing**:\n   - Processes DNS records in small batches during reconciliation\n   - Shows real-time progress feedback in the web UI\n   - Configurable via `RECONCILIATION_BATCH_SIZE` (default: 3)\n\n3. **Asynchronous Initialization**:\n   - Web UI is immediately available while initialization continues\n   - Progress indicators show current status of initialization and reconciliation\n\nThese optimizations are particularly helpful when managing tunnels with many domains or when running on systems with limited resources.\n\n## Troubleshooting\n\n### Common Issues\n\n- **Log Stream Not Working**: Ensure your browser supports Server-Sent Events (SSE). Try a different browser or check for network filtering.\n- **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.\n- **Container Not Being Detected**: Verify that:\n  - Your container has the right labels\n  - The container is in a network DockFlare can access (use `SCAN_ALL_NETWORKS=true` if needed)\n  - The hostname format is valid (must be a proper domain name)\n  - The service format is valid (must include protocol and host:port)\n\n### Debugging\n\n- Check the logs in the Web UI or the container logs using:\n\n  ```bash\n  docker logs dockflare\n  ```\n\n- Verify Cloudflare API token permissions: Requires Zone:DNS:Edit and Account:Cloudflare Tunnel:Edit\n\n- If a container stops responding to changes, try forcing deletion of the rule via the Web UI and then restart the container.\n\n### Health Checks\n\n- **DockFlare Health**: Access `http://localhost:5000/ping` for basic health information\n- **Cloudflare Connectivity**: Access `http://localhost:5000/cloudflare-ping` through your tunnel to verify Cloudflare connection details\n\n## Contributing\n\nContributions are welcome! Please open an issue or submit a pull request on GitHub.\n\n1. Fork the repository\n2. Create a feature branch (`git checkout -b feature/amazing-feature`)\n3. Commit your changes (`git commit -m 'Add some amazing feature'`)\n4. Push to the branch (`git push origin feature/amazing-feature`)\n5. Open a Pull Request\n\n## License\n\nDockFlare is licensed under the GNU General Public License version 3 License. See [LICENSE.MD](https://github.com/ChrispyBacon-dev/DockFlare?tab=License-1-ov-file) for details.\n","project_url":"https://awesome.ecosyste.ms/api/v1/projects/github.com%2FChrispyBacon-dev%2FDockFlare","html_url":"https://awesome.ecosyste.ms/projects/github.com%2FChrispyBacon-dev%2FDockFlare","lists_url":"https://awesome.ecosyste.ms/api/v1/projects/github.com%2FChrispyBacon-dev%2FDockFlare/lists"}