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
Helm (Recommended)
# 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:
- 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"
- 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
- Apply the resources:
kubectl apply -f secret.yaml
kubectl apply -f profile.yaml
- 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