From 22ef2a38b2e9aaf092b484be6d68e7c78c2959ba Mon Sep 17 00:00:00 2001 From: Roger Oriol Date: Sun, 28 Jun 2026 09:34:43 +0200 Subject: [PATCH] pihole unbound --- pihole/pihole.yaml | 140 ++++++++++++++++++++++++++++++++++-- pihole/unbound/unbound.conf | 40 +++++++++++ 2 files changed, 176 insertions(+), 4 deletions(-) create mode 100644 pihole/unbound/unbound.conf diff --git a/pihole/pihole.yaml b/pihole/pihole.yaml index 945673a..39ee1a6 100644 --- a/pihole/pihole.yaml +++ b/pihole/pihole.yaml @@ -5,6 +5,66 @@ metadata: name: pihole --- apiVersion: v1 +kind: ConfigMap +metadata: + name: unbound-config + namespace: pihole +data: + unbound.conf: | + server: + # Listen only on loopback so only the co-located pihole can query it + interface: 127.0.0.1 + port: 5335 + + # IPv4 only for simplicity + do-ip4: yes + do-udp: yes + do-tcp: yes + do-ip6: no + prefer-ip6: no + + # Recursive resolver: do not use any forwarders, start from the root servers + root-hints: "/opt/unbound/etc/unbound/root.hints" + + # DNSSEC / hardening + harden-glue: yes + harden-dnssec-stripped: yes + harden-referral-path: yes + + # Performance / privacy + prefetch: yes + prefetch-key: yes + qname-minimisation: yes + aggressive-nsec: yes + edns-buffer-size: 1232 + num-threads: 1 + so-rcvbuf: 1m + + # RFC1918 / link-local addresses should never come back from the internet + private-address: 10.0.0.0/8 + private-address: 172.16.0.0/12 + private-address: 192.168.0.0/16 + private-address: 169.254.0.0/16 + private-address: fd00::/8 + private-address: fe80::/10 + + # Hide identity / version + hide-identity: yes + hide-version: yes +--- +# Pi-hole config that points dnsmasq at the local unbound sidecar. +# Mounted into /etc/dnsmasq.d so it is read on (re)start. +apiVersion: v1 +kind: ConfigMap +metadata: + name: pihole-dnsmasq-config + namespace: pihole +data: + 99-unbound.conf: | + # Use the recursive unbound sidecar as the only upstream DNS + server=127.0.0.1#5335 +--- +apiVersion: v1 kind: PersistentVolumeClaim metadata: name: pihole-pvc @@ -16,6 +76,18 @@ spec: requests: storage: 1Gi --- +apiVersion: v1 +kind: PersistentVolumeClaim +metadata: + name: unbound-pvc + namespace: pihole +spec: + accessModes: + - ReadWriteOnce + resources: + requests: + storage: 100Mi +--- apiVersion: apps/v1 kind: Deployment metadata: @@ -33,11 +105,31 @@ spec: labels: app: pihole spec: + # The pod itself still needs DNS to (e.g.) download blocklists on gravity + # updates. Use the cluster DNS / a public resolver for that - it is NOT + # used to answer client queries, which go through the unbound sidecar. dnsPolicy: "None" dnsConfig: nameservers: - 8.8.8.8 - 8.8.4.4 + initContainers: + - name: unbound-root-hints + image: curlimages/curl:8.12.1 + command: + - /bin/sh + - -c + - | + set -e + if [ ! -s /opt/unbound/etc/unbound/root.hints ]; then + echo "Downloading root hints..." + curl -fsSL https://www.internic.net/domain/named.root -o /opt/unbound/etc/unbound/root.hints + else + echo "Root hints already present, skipping download." + fi + volumeMounts: + - name: unbound-data + mountPath: /opt/unbound/etc/unbound containers: - name: pihole image: pihole/pihole:latest @@ -72,8 +164,9 @@ spec: volumeMounts: - name: pihole-data mountPath: /etc/pihole - #- name: pihole-dnsmasq - #mountPath: /etc/dnsmasq.d + - name: pihole-dnsmasq-config + mountPath: /etc/dnsmasq.d/99-unbound.conf + subPath: 99-unbound.conf resources: requests: memory: "256Mi" @@ -87,12 +180,51 @@ spec: - NET_ADMIN - SYS_TIME - SYS_NICE + - name: unbound + image: mvance/unbound:latest + ports: + - containerPort: 5335 + name: unbound-dns-tcp + protocol: TCP + - containerPort: 5335 + name: unbound-dns-udp + protocol: UDP + volumeMounts: + - name: unbound-config + mountPath: /opt/unbound/etc/unbound/unbound.conf + subPath: unbound.conf + - name: unbound-data + mountPath: /opt/unbound/etc/unbound + resources: + requests: + memory: "64Mi" + cpu: "50m" + limits: + memory: "256Mi" + cpu: "500m" + livenessProbe: + tcpSocket: + port: 5335 + initialDelaySeconds: 10 + periodSeconds: 30 + readinessProbe: + tcpSocket: + port: 5335 + initialDelaySeconds: 5 + periodSeconds: 10 volumes: - name: pihole-data persistentVolumeClaim: claimName: pihole-pvc - #- name: pihole-dnsmasq - #emptyDir: {} + - name: unbound-data + persistentVolumeClaim: + claimName: unbound-pvc + - name: unbound-config + configMap: + name: unbound-config + - name: pihole-dnsmasq-config + configMap: + name: pihole-dnsmasq-config --- apiVersion: v1 kind: Service diff --git a/pihole/unbound/unbound.conf b/pihole/unbound/unbound.conf new file mode 100644 index 0000000..1223d41 --- /dev/null +++ b/pihole/unbound/unbound.conf @@ -0,0 +1,40 @@ +server: + # Listen only on loopback so only the co-located pihole can query it + interface: 127.0.0.1 + port: 5335 + + # IPv4 only for simplicity + do-ip4: yes + do-udp: yes + do-tcp: yes + do-ip6: no + prefer-ip6: no + + # Recursive resolver: do not use any forwarders, start from the root servers + root-hints: "/opt/unbound/etc/unbound/root.hints" + + # DNSSEC / hardening + harden-glue: yes + harden-dnssec-stripped: yes + harden-referral-path: yes + + # Performance / privacy + prefetch: yes + prefetch-key: yes + qname-minimisation: yes + aggressive-nsec: yes + edns-buffer-size: 1232 + num-threads: 1 + so-rcvbuf: 1m + + # RFC1918 / link-local addresses should never come back from the internet + private-address: 10.0.0.0/8 + private-address: 172.16.0.0/12 + private-address: 192.168.0.0/16 + private-address: 169.254.0.0/16 + private-address: fd00::/8 + private-address: fe80::/10 + + # Hide identity / version + hide-identity: yes + hide-version: yes