๐ Automatic DNS record management for Docker containers and Swarm services using Cloudflare. Label your containers, get DNS records.
๐ Docker/Swarm Cloudflare DNS Manager (WIP)
A Node.js service that automatically manages DNS records in Cloudflare based on Docker events. It monitors both Docker containers and Swarm services for specific labels and updates corresponding DNS records.
โจ Features
- ๐ Automatic DNS record management based on Docker service labels
- ๐ Real-time monitoring of both Docker containers and Swarm services events
- ๐ท๏ธ Support for multiple DNS record types (A, AAAA, CNAME, MX, TXT)
- ๐ Public IP caching and validation
- ๐ช Fault-tolerant design with retry mechanisms
- ๐ Automatic DNS creation from Traefik labels (optional)
๐ Prerequisites
- ๐ฆ Node.js 20 or higher
- ๐ณ Docker (works in both Swarm and standalone mode)
- โ๏ธ Cloudflare account and API token with DNS edit permissions
- ๐ Access to Docker socket (read-only is sufficient)
๐ Installation
Quick Start with Docker Swarm
# Create a config file for environment variables
cat << EOF > cloudflare-dns.env
CLOUDFLARETOKEN=yourcloudflareapitoken
LOG_LEVEL=info
EOF
Deploy the service to your swarm
docker service create \
--name cloudflare-dns \
--env-file cloudflare-dns.env \
--mount type=bind,source=/var/run/docker.sock,target=/var/run/docker.sock,ro \
--constraint 'node.role == manager' \
marlburrow/cloudflare-dns-swarm
Or using a stack file (for Portainer or docker stack deploy):
version: "3.8"
services: dns-manager: image: marlburrow/cloudflare-dns-swarm:latest environment: - CLOUDFLARETOKEN=yourcloudflareapitoken - LOG_LEVEL=info - RETRY_ATTEMPTS=3 - RETRY_DELAY=300000 - IPCHECKINTERVAL=3600000 volumes: - /var/run/docker.sock:/var/run/docker.sock:ro deploy: mode: replicated replicas: 1 placement: constraints: - node.role == manager resources: limits: memory: 256M reservations: memory: 128M restart_policy: condition: any delay: 5s max_attempts: 3 window: 120s
Save this as cloudflare-dns-stack.yml and deploy:
docker stack deploy -c cloudflare-dns-stack.yml cloudflare-dns
๐ Usage
Works with both Docker containers and Swarm services. Here are examples for both:
๐ท๏ธ Available Labels
dns.cloudflare.hostname: DNS record name (required)dns.cloudflare.type: Record type (A, AAAA, CNAME, TXT, MX)dns.cloudflare.content: Record content (required for CNAME, optional for A/AAAA)dns.cloudflare.ttl: Time to live in seconds (optional, default: 1)dns.cloudflare.proxied: Enable/disable Cloudflare proxy (optional, default: true)
๐ฏ Default Behaviors
The service includes smart defaults to minimize configuration:
- ๐ค Record Type: If not specified, defaults to
Arecord - ๐ Record Content:
A records: Uses public IP from ipify.org if not specified
- For AAAA records: Uses public IPv6 if available, else skips record creation
- For other types (CNAME, TXT, MX): Content is required
- โก Proxy Status: Defaults to
true(traffic proxied through Cloudflare) - โฑ๏ธ TTL: Defaults to 1 (automatic)
# Only hostname specified - creates an A record with public IP
docker service create \
--name my-service \
--label dns.cloudflare.hostname=api.domain.com \
your-image
๐ฆ Docker Container
# Create a container with DNS records
docker run -d \
--name my-container \
--label dns.cloudflare.hostname=api.domain.com \
--label dns.cloudflare.type=A \
--label dns.cloudflare.proxied=false \
your-image
๐ณ Docker Swarm Service
๐น Basic A Record
# Create a service with an A record and custom TTL
docker service create \
--name my-service \
--label dns.cloudflare.hostname=subdomain.domain.com \
--label dns.cloudflare.type=A \
--label dns.cloudflare.ttl=3600 \
your-image
๐ CNAME Record
# Create a service with a CNAME record
docker service create \
--name my-service \
--label dns.cloudflare.hostname=alias.domain.com \
--label dns.cloudflare.type=CNAME \
--label dns.cloudflare.content=target.domain.com \
--label dns.cloudflare.proxied=true \
your-image
๐ IPv4 and IPv6 Records
# Create a service with both A and AAAA records
docker service create \
--name my-service \
--label dns.cloudflare.hostname=api.domain.com \
--label dns.cloudflare.type=A \
--label dns.cloudflare.proxied=true \
--label dns.cloudflare.hostname.v6=api.domain.com \
--label dns.cloudflare.type.v6=AAAA \
--label dns.cloudflare.content.v6=2001:db8::1 \
--label dns.cloudflare.proxied.v6=false \
your-image
๐ท๏ธ Multiple Subdomains
# Create a service with multiple subdomains
docker service create \
--name my-service \
--label dns.cloudflare.hostname=api.domain.com \
--label dns.cloudflare.type=A \
--label dns.cloudflare.hostname.admin=admin.domain.com \
--label dns.cloudflare.type.admin=A \
--label dns.cloudflare.hostname.web=www.domain.com \
--label dns.cloudflare.type.web=CNAME \
--label dns.cloudflare.content.web=domain.com \
your-image
๐ Multiple Records
# Create a service with mixed record types
docker service create \
--name my-service \
--label dns.cloudflare.hostname=domain.com \
--label dns.cloudflare.type=A \
--label dns.cloudflare.hostname.mx=domain.com \
--label dns.cloudflare.type.mx=MX \
--label dns.cloudflare.content.mx="10 mail.domain.com" \
--label dns.cloudflare.hostname.txt=domain.com \
--label dns.cloudflare.type.txt=TXT \
--label dns.cloudflare.content.txt="v=spf1 include:_spf.domain.com ~all" \
your-image
โ๏ธ Configuration
The following environment variables can be used to configure the application:
Core Settings
| Variable | Description | Default | Required | | ------------------- | ---------------------------------------- | ---------------------- | -------- | | CLOUDFLARE_TOKEN | Cloudflare API token | - | Yes | | DOCKER_SOCKET | Docker socket path | /var/run/docker.sock | No | | LOG_LEVEL | Logging level (debug, info, warn, error) | info | No | | RETRY_ATTEMPTS | Number of retry attempts | 3 | No | | RETRY_DELAY | Delay between retries (ms) | 300000 | No | | IPCHECKINTERVAL | IP check interval (ms) | 3600000 | No |
DNS Settings
| Variable | Description | Default | Required | | ------------------------- | ------------------------------- | ------- | -------- | | USETRAEFIKLABELS | Enable Traefik label support | false | No | | DNSDEFAULTRECORD_TYPE | Default DNS record type | A | No | | DNSDEFAULTCONTENT | Default record content | - | No | | DNSDEFAULTPROXIED | Default Cloudflare proxy status | true | No | | DNSDEFAULTTTL | Default TTL | 1 | No |
Examples
Basic Configuration
CLOUDFLARETOKEN=yourtoken_here
USETRAEFIKLABELS=true
DNSDEFAULTRECORD_TYPE=A
DNSDEFAULTPROXIED=true
CNAME Configuration
DNSDEFAULTRECORD_TYPE=CNAME
DNSDEFAULTCONTENT=origin.domain.com
DNSDEFAULTPROXIED=false
DNSDEFAULTTTL=3600
๐ Traefik Integration
The service can automatically create DNS records from your Traefik Host rules.
Important Notes
- Traefik integration must be explicitly enabled with
USETRAEFIKLABELS=true - DNS records are only created for services with
traefik.enable=true - DNS settings can be overridden using explicit dns.cloudflare.\* labels
- Multiple hosts in a single rule are supported and will create separate DNS records
- CNAME records require explicit content to be specified
Configuration
Enable Traefik integration and configure default behavior:
# Enable Traefik integration
USETRAEFIKLABELS=true
Configure default DNS settings (optional)
DNSDEFAULTRECORD_TYPE=A
DNSDEFAULTCONTENT=
DNSDEFAULTPROXIED=true
DNSDEFAULTTTL=1
Examples
Basic Usage
services:
webapp:
labels:
- "traefik.enable=true"
- "traefik.http.routers.webapp.rule=Host(app.domain.com)"
# This will create:
# - An A record for app.domain.com
# - Using your public IP as content
# - With Cloudflare proxy enabled
Custom DNS Settings
services:
webapp:
labels:
- "traefik.enable=true"
- "traefik.http.routers.webapp.rule=Host(app.domain.com)"
# Override default DNS settings
- "dns.cloudflare.type=CNAME"
- "dns.cloudflare.content=origin.domain.com"
- "dns.cloudflare.proxied=false"
Multiple Hosts
services:
webapp:
labels:
- "traefik.enable=true"
- "traefik.http.routers.webapp.rule=Host(app.domain.com) || Host(api.domain.com)"
# This will create DNS records for both domains
# using the default settings
Development Setup
If you want to contribute or modify the code:
- Clone the repository:
git clone https://github.com/yourusername/docker-swarm-dns-manager.git
cd docker-swarm-dns-manager
- Copy
.env.exampleto.envand fill in your Cloudflare credentials:
cp .env.example .env
- Install dependencies and start in development mode:
yarn install
yarn dev
Or using docker-compose for development:
docker compose up -d
The development setup includes:
- Hot reloading for code changes
- Debug level logging
- Source maps for debugging
๐งช Testing
The project uses Jest for testing. The test suite includes:
- Unit tests for all services and utilities
- Integration tests for Docker events and DNS updates
- Validation tests for labels and configurations
- Mock implementations for external services (Docker, Cloudflare, IP services)
# Run tests
yarn test
Run tests in watch mode
yarn test:watch
Run tests with coverage report
yarn test:coverage
๐ Error Handling & Reliability
Based on the test suite, the service includes:
- Automatic retries for failed DNS operations
- IP address validation and double-checking
- Graceful handling of Docker event failures
- Caching of IP addresses with periodic refresh
- Validation of all DNS record configurations
- Fault tolerance for network issues
The project maintains a high test coverage to ensure reliability. All new contributions should include appropriate tests.
๐ค Contributing
Contributions are welcome! Feel free to open an issue or pull request.
๐บ๏ธ Roadmap
๐ฏ Upcoming Features
๐ Multi-Provider Support
The next major version will introduce a plugin system for multiple DNS providers:
- ๐ Plugin Architecture
- ๐ข Planned Providers
Want to contribute to these features? Check our Contributing section!
๐ License
MIT