external-dns-unifios-webhook
November 19, 2025 ยท View on GitHub
Webhook provider for external-dns that integrates with UniFi OS DNS management. Enables automatic DNS record management in UniFi controllers (UniFi Dream Machine, Cloud Key, etc.) from Kubernetes.
Features
- DNS record type support: A, AAAA, CNAME, TXT
- Domain filtering with include/exclude patterns and regex
- Kubernetes-ready health checks and readiness probes
- Prometheus metrics endpoint for monitoring
- Structured JSON logging with configurable levels
- OpenTelemetry instrumentation
- Lightweight container image built from scratch
๐ฏ Requirements
Minimum Versions
- ExternalDNS >= v0.20.0
- UniFi OS >= 4.3.9
- UniFi Network >= 9.4.19
UniFi Controller
- UniFi OS Controller (UniFi Dream Machine, Cloud Key Gen2+, or UniFi Network Application)
- UniFi controller with API access enabled
- API key with DNS management permissions
Creating UniFi API Key
- Log in to UniFi controller web interface
- Navigate to Settings โ Admins
- Select your admin user
- Scroll to API Access section
- Generate new API key
- Save the key securely (shown only once)
Important: The API key inherits permissions from the admin user account. Ensure the user has sufficient privileges to manage DNS records.
Optional
- Kubernetes cluster with external-dns deployed
- Prometheus for metrics collection
๐ซ Limitations
DNS Backend Limitations
UniFi uses dnsmasq as the backend for its DNS resolver. This project is subject to dnsmasq limitations.
Unsupported configurations:
-
Wildcard CNAME records
*.example.com IN CNAME target.example.com # NOT SUPPORTED -
Duplicate CNAME records
app.example.com IN CNAME internal.example.com app.example.com IN CNAME external.example.com # NOT SUPPORTED
If you encounter issues with DNS record creation, verify your configuration against these limitations.
Request Body Size Limit
5MB request body limit (~25,000 DNS records). If you hit this limit, open an issue.
๐ Installation
Kubernetes with Helm
Deploy external-dns with this webhook provider using the official external-dns Helm chart.
Prerequisites:
-
Add external-dns Helm repository:
helm repo add external-dns https://kubernetes-sigs.github.io/external-dns/ helm repo update -
Create namespace and secret with UniFi API key:
kubectl create namespace external-dns-unifi kubectl create secret generic unifi-credentials \ --namespace external-dns-unifi \ --from-literal=api-key=YOUR_UNIFI_API_KEY -
Create
values.yamlwith webhook configuration:# This is a minimal configuration snippet for the webhook provider. # You are responsible for configuring other external-dns values according to your needs # (e.g., domainFilters, policy, interval, sources, etc.). # See https://github.com/kubernetes-sigs/external-dns/tree/master/charts/external-dns for all options. provider: name: webhook webhook: image: repository: ghcr.io/lexfrei/external-dns-unifios-webhook tag: latest # Recommended: pin to a specific version (e.g., v1.0.0) env: - name: WEBHOOK_UNIFI_API_KEY valueFrom: secretKeyRef: name: unifi-credentials key: api-key - name: WEBHOOK_UNIFI_HOST value: "https://192.168.1.1" livenessProbe: httpGet: path: /healthz port: 8080 initialDelaySeconds: 10 periodSeconds: 10 readinessProbe: httpGet: path: /readyz port: 8080 initialDelaySeconds: 10 periodSeconds: 10 -
Deploy external-dns with the webhook:
helm upgrade --install external-dns-unifi external-dns/external-dns \ --namespace external-dns-unifi \ --values values.yaml
โ๏ธ Configuration
Webhook Configuration
Required Parameters
| Environment Variable | Description |
|---|---|
WEBHOOK_UNIFI_HOST | UniFi controller URL (use IP address, not hostname like unifi.local) |
WEBHOOK_UNIFI_API_KEY | API key from UniFi controller (stored in Kubernetes secret) |
Optional Parameters
| Environment Variable | Description | Default |
|---|---|---|
WEBHOOK_UNIFI_SITE | UniFi site name | default |
WEBHOOK_UNIFI_SKIP_TLS_VERIFY | Skip TLS certificate verification | true |
WEBHOOK_SERVER_HOST | Webhook server bind address | localhost |
WEBHOOK_SERVER_PORT | Webhook server port | 8888 |
WEBHOOK_HEALTH_HOST | Health server bind address | 0.0.0.0 |
WEBHOOK_HEALTH_PORT | Health server port | 8080 |
WEBHOOK_LOGGING_LEVEL | Log level: debug, info, warn, error | info |
WEBHOOK_LOGGING_FORMAT | Log format: json or text | json |
WEBHOOK_DEBUG_PPROF_ENABLED | Enable pprof profiling endpoints (DO NOT use in production) | false |
WEBHOOK_DEBUG_PPROF_PORT | pprof server port (when enabled) | 6060 |
๐ป Development
Build
go build -o webhook ./cmd/webhook
Run Locally
export WEBHOOK_UNIFI_HOST="192.168.1.1"
export WEBHOOK_UNIFI_API_KEY="your-api-key"
export WEBHOOK_LOGGING_LEVEL="debug"
go run ./cmd/webhook server
Run Tests
go test ./...
Build Container Image
podman build --tag external-dns-unifios-webhook:local --file Containerfile .
Contributing
Contributions are welcome! Please:
- Fork the repository
- Create a feature branch
- Make your changes
- Add tests if applicable
- Submit a pull request
License
BSD-3-Clause License. See LICENSE file for details.
Author
Aleksei Sviridkin <f@lex.la>