A Docker-based solution that automatically manages Cloudflare DNS records and tunnel configurations for your containers. This project makes it easy to expose your local services through Cloudflare Tunnels with automatic DNS record management.
- 🔄 Automatic DNS record management for Docker containers
- 🚇 Cloudflare Tunnel integration
- 🏷️ Simple container label-based configuration
- 🔒 Secure exposure of local services
- 📝 Comprehensive logging
- 🔌 Zero-trust network access
- Docker and Docker Compose
- A Cloudflare account with:
- A registered domain
- API token with edit / view permissions:
- Account -> Cloudflare Tunnel
- Zone -> DNS
- Cloudflare Tunnel created
- Zero Trust access
Create a .env file with the following variables:
# Cloudflare configuration
DOMAIN=your-domain.com
HOST_IP=your.machine.ip.address # defaults to localhost
# Cloudflare API configuration
TUNNEL_TOKEN=your-tunnel-token
CF_API_TOKEN=your-api-token
CF_ACCOUNT_ID=your-account-id
CF_ZONE_ID=your-zone-idAdd these labels to any container you want to expose through Cloudflare:
services:
nginx:
image: nginx:latest
ports:
- 80:80
labels:
- "cloudflare.enabled=true" # Required: Enable Cloudflare integration
- "cloudflare.subdomain=hello" # Creates hello.yourdomain.com
- "cloudflare.port=80" # Optional: Enables a specific portThe DNS manager will automatically:
- Create
hello.**yourdomain**.comhostname on your Cloudflare tunnel- and create a dns record pointing to tunnel
- Remove these records when the container stops
- Update the record if labels change upon container re-creation
The easiest way to get started is using our pre-built image from GitHub Container Registry:
-
Create a docker-compose file alongside cloudflared:
services: cloudflared: image: cloudflare/cloudflared:latest container_name: cloudflared restart: unless-stopped command: tunnel run volumes: - ./cloudflared:/etc/cloudflared environment: - TUNNEL_TOKEN=${TUNNEL_TOKEN} tunnel-manager: image: ghcr.io/dancorley/cloudflared-tunnel-manager:latest container_name: cloudflared-tunnel-manager restart: unless-stopped volumes: - /var/run/docker.sock:/var/run/docker.sock:ro - ./logs:/app/logs environment: - CF_API_TOKEN=${CF_API_TOKEN} - CF_ACCOUNT_ID=${CF_ACCOUNT_ID} - TUNNEL_TOKEN=${TUNNEL_TOKEN} - CF_ZONE_ID=${CF_ZONE_ID} - DOMAIN=${DOMAIN} - HOST_IP=${HOST_IP:-localhost}
-
Set up your environment variables in
.env -
Set labels like
cloudflare.enabled=trueon others + restart containers -
Start the services with cloudflared-tunnel-manager:
docker compose up -d
-
Restart other containers if labels not set.
If you prefer to build the image locally:
-
Clone the repository as above
-
Modify the
docker-compose.ymlto build locally:tunnel-manager: build: context: ./tunnel-manager dockerfile: Dockerfile # ... rest of configuration
-
Build and start the services:
docker compose up -d --build
.
├── docker-compose.yml # Main compose file
├── .env # Environment variables
├── tunnel-manager/
│ ├── Dockerfile # DNS manager container definition
│ ├── requirements.txt # Python dependencies
│ ├── main.py # Application entry point
│ ├── cloudflare_manager.py # Cloudflare API interactions
│ └── docker_manager.py # Docker API interactions
├── .github/
│ └── workflows/ # GitHub Actions workflows
│ └── publish.yml # Container publishing workflow
└── logs/ # Log directory
-
Naming
- Use descriptive subdomains that reflect the service
- Avoid using special characters in subdomains
- Keep subdomains short and memorable
-
Security
- Only enable Cloudflare integration for services that need external access
- Consider using separate domains for internal and external services
-
Organization
- Group related services under similar subdomain patterns
- Use consistent naming conventions across your infrastructure