nextdns-operator

module
v0.5.0 Latest Latest
Warning

This package is not in the latest version of its module.

Go to latest
Published: Feb 4, 2026 License: Apache-2.0

README

NextDNS Kubernetes Operator

A Kubernetes operator for managing NextDNS profiles declaratively using Custom Resources.

Features

  • Declarative DNS Management: Define NextDNS profiles as Kubernetes resources
  • Multi-CRD Architecture: Separate resources for allowlists, denylists, and TLD lists that can be shared across profiles
  • Full NextDNS API Coverage: Security, privacy, parental control, and settings configuration
  • Profile Lifecycle Management: Create new profiles or adopt existing ones; operator-created profiles are deleted on resource removal
  • Drift Detection: Automatic periodic reconciliation (default: 1 hour) catches manual changes made outside the operator
  • ConfigMap Export: Optionally create a ConfigMap with DNS connection details for easy integration with other applications

Custom Resources

CRD Description
NextDNSProfile Main profile configuration with security, privacy, and parental control settings
NextDNSAllowlist Reusable list of allowed domains
NextDNSDenylist Reusable list of blocked domains
NextDNSTLDList Reusable list of blocked TLDs
NextDNSCoreDNS Deploy CoreDNS instances forwarding to NextDNS upstream

Installation

# Install from OCI registry
helm install nextdns-operator oci://ghcr.io/jacaudi/charts/nextdns-operator \
  --version 0.1.0 \
  --namespace nextdns-operator-system \
  --create-namespace
Kubectl
# Install CRDs
kubectl apply -f https://github.com/jacaudi/nextdns-operator/releases/latest/download/install.yaml

# Deploy operator
kubectl apply -f https://github.com/jacaudi/nextdns-operator/releases/latest/download/operator.yaml
Local Development
# Install CRDs
make install

# Run locally
make run

Quick Start

Once the operator is installed:

  1. Create a Secret with your NextDNS API key:
apiVersion: v1
kind: Secret
metadata:
  name: nextdns-credentials
  namespace: default
type: Opaque
stringData:
  api-key: "your-nextdns-api-key"
  1. Create a NextDNSProfile:
apiVersion: nextdns.io/v1alpha1
kind: NextDNSProfile
metadata:
  name: my-profile
  namespace: default
spec:
  name: "My DNS Profile"
  credentialsRef:
    name: nextdns-credentials
  security:
    aiThreatDetection: true
    googleSafeBrowsing: true
  1. Apply the resources:
kubectl apply -f secret.yaml
kubectl apply -f profile.yaml
  1. Check the status:
kubectl get nextdnsprofile my-profile -o yaml

Examples

See the config/samples directory for complete examples:

Configuration

ConfigMap Export

Optionally create a ConfigMap containing your profile's DNS connection details. This is useful for configuring DNS clients (CoreDNS, Blocky, etc.) or injecting connection details into pods.

apiVersion: nextdns.io/v1alpha1
kind: NextDNSProfile
metadata:
  name: my-profile
spec:
  name: "My Profile"
  credentialsRef:
    name: nextdns-credentials
  configMapRef:
    enabled: true
    name: my-dns-config  # optional, defaults to "<profile-name>-nextdns"

The created ConfigMap contains:

data:
  NEXTDNS_PROFILE_ID: "abc123"
  NEXTDNS_DOT: "abc123.dns.nextdns.io"
  NEXTDNS_DOH: "https://dns.nextdns.io/abc123"
  NEXTDNS_DOQ: "quic://abc123.dns.nextdns.io"
  NEXTDNS_IPV4_1: "45.90.28.0"
  NEXTDNS_IPV4_2: "45.90.30.0"
  NEXTDNS_IPV6_1: "2a07:a8c0::"
  NEXTDNS_IPV6_2: "2a07:a8c1::"

Use it in your pods with envFrom:

envFrom:
  - configMapRef:
      name: my-dns-config
CoreDNS Deployment

Deploy a dedicated CoreDNS instance that forwards DNS queries to NextDNS. This is useful for providing DNS services to devices on your network (home routers, IoT devices, etc.) that can't use DoH/DoT directly.

apiVersion: nextdns.io/v1alpha1
kind: NextDNSCoreDNS
metadata:
  name: home-dns
spec:
  profileRef:
    name: my-profile  # References an existing NextDNSProfile

  upstream:
    primary: DoT      # DNS over TLS (recommended)
    fallback: DoH     # Fallback to DNS over HTTPS

  deployment:
    mode: Deployment
    replicas: 2

  service:
    type: LoadBalancer
    loadBalancerIP: "192.168.1.53"  # Optional static IP

  cache:
    enabled: true
    successTTL: 3600  # Cache TTL in seconds

Features:

  • Upstream protocols: DoT (DNS over TLS), DoH (DNS over HTTPS), or plain DNS
  • Deployment modes: Kubernetes Deployment (with replicas) or DaemonSet
  • Service types: ClusterIP, LoadBalancer, or NodePort
  • Placement controls: nodeSelector, affinity, tolerations
  • Caching: Configurable DNS response caching
  • Metrics: Prometheus metrics endpoint with optional ServiceMonitor
  • Security: Containers run read-only with dropped capabilities

Check deployment status:

kubectl get nextdnscoredns home-dns
# NAME       PROFILE ID   DNS IP          READY   AGE
# home-dns   abc123       192.168.1.53    true    5m

Security Note: Using plain DNS (DNS protocol) exposes your NextDNS profile ID in unencrypted traffic. Use DoT or DoH for privacy in untrusted networks.

Multus CNI Integration

For advanced networking scenarios, you can attach CoreDNS pods to additional networks using Multus CNI. This is useful for exposing DNS services directly on a VLAN or dedicated network interface.

Example: CoreDNS on a VLAN with primary and secondary IPs

First, create a NetworkAttachmentDefinition for your VLAN:

apiVersion: k8s.cni.cncf.io/v1
kind: NetworkAttachmentDefinition
metadata:
  name: dns-vlan
  namespace: default
spec:
  config: |
    {
      "cniVersion": "0.3.1",
      "type": "macvlan",
      "master": "eth0.100",
      "mode": "bridge",
      "ipam": {
        "type": "static",
        "addresses": [
          { "address": "192.168.100.53/24" },
          { "address": "192.168.100.54/24" }
        ],
        "routes": [
          { "dst": "0.0.0.0/0", "gw": "192.168.100.1" }
        ]
      }
    }

Then reference it in your NextDNSCoreDNS resource:

apiVersion: nextdns.io/v1alpha1
kind: NextDNSCoreDNS
metadata:
  name: vlan-dns
spec:
  profileRef:
    name: my-profile

  upstream:
    primary: DoT

  deployment:
    mode: DaemonSet
    podAnnotations:
      k8s.v1.cni.cncf.io/networks: dns-vlan

  service:
    type: ClusterIP  # Internal only; clients use Multus IPs directly

The CoreDNS pods will now have interfaces on both the cluster network and the VLAN, accessible at 192.168.100.53 and 192.168.100.54.

Drift Detection

The operator periodically reconciles all resources to detect and correct drift from manual changes made outside Kubernetes.

Configure via environment variable:

SYNC_PERIOD=30m ./nextdns-operator

Configure via command-line flag:

./nextdns-operator --sync-period=30m

Disable periodic syncing:

SYNC_PERIOD=0 ./nextdns-operator

Default: 1h (60 minutes)

Behavior:

  • Syncs include ±10% jitter to prevent all resources from hitting the API simultaneously
  • Each profile makes ~1 API call per sync period
  • List resources (allowlist, denylist, tldlist) sync status but don't call the NextDNS API directly
  • Setting to 0 disables periodic syncing (event-driven only)

Development

# Run tests
make test

# Build
make build

Acknowledgements

This project stands on the shoulders of giants:

  • bjw-s - For the excellent helm-charts library and app-template that powers the Helm chart for this operator. The common library pattern has been invaluable.

  • amalucelli - For creating the original nextdns-go client library that this operator's fork is based on. The solid foundation made building this operator possible.

License

Apache 2.0

Directories

Path Synopsis
api
v1alpha1
Package v1alpha1 contains API Schema definitions for the nextdns v1alpha1 API group +kubebuilder:object:generate=true +groupName=nextdns.io
Package v1alpha1 contains API Schema definitions for the nextdns v1alpha1 API group +kubebuilder:object:generate=true +groupName=nextdns.io
internal
coredns
Package coredns provides utilities for generating CoreDNS Corefile configurations for use with NextDNS profiles.
Package coredns provides utilities for generating CoreDNS Corefile configurations for use with NextDNS profiles.

Jump to

Keyboard shortcuts

? : This menu
/ : Search site
f or F : Jump to
y or Y : Canonical URL