external-dns-unifios-webhook

November 19, 2025 ยท View on GitHub

Go Version License GitHub Release

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

  1. Log in to UniFi controller web interface
  2. Navigate to Settings โ†’ Admins
  3. Select your admin user
  4. Scroll to API Access section
  5. Generate new API key
  6. 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:

  1. Add external-dns Helm repository:

    helm repo add external-dns https://kubernetes-sigs.github.io/external-dns/
    helm repo update
    
  2. 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
    
  3. Create values.yaml with 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
    
  4. 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 VariableDescription
WEBHOOK_UNIFI_HOSTUniFi controller URL (use IP address, not hostname like unifi.local)
WEBHOOK_UNIFI_API_KEYAPI key from UniFi controller (stored in Kubernetes secret)

Optional Parameters

Environment VariableDescriptionDefault
WEBHOOK_UNIFI_SITEUniFi site namedefault
WEBHOOK_UNIFI_SKIP_TLS_VERIFYSkip TLS certificate verificationtrue
WEBHOOK_SERVER_HOSTWebhook server bind addresslocalhost
WEBHOOK_SERVER_PORTWebhook server port8888
WEBHOOK_HEALTH_HOSTHealth server bind address0.0.0.0
WEBHOOK_HEALTH_PORTHealth server port8080
WEBHOOK_LOGGING_LEVELLog level: debug, info, warn, errorinfo
WEBHOOK_LOGGING_FORMATLog format: json or textjson
WEBHOOK_DEBUG_PPROF_ENABLEDEnable pprof profiling endpoints (DO NOT use in production)false
WEBHOOK_DEBUG_PPROF_PORTpprof 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:

  1. Fork the repository
  2. Create a feature branch
  3. Make your changes
  4. Add tests if applicable
  5. Submit a pull request

License

BSD-3-Clause License. See LICENSE file for details.

Author

Aleksei Sviridkin <f@lex.la>