Add native DNS-over-TLS (DoT) on dot.nook.family:853

- ddclient.tf: dynamic DNS daemon that keeps dot.nook.family A record
  pointing at the home public IP via Cloudflare API (updates every 5m)
- adguard.tf: cert-manager Certificate for dot.nook.family via DNS-01,
  updated TLS config block with DoT paths and port 853
- apps/adguard.yaml: mount adguard-dot-tls secret, expose port 853,
  init container enforces TLS/DoT settings on every restart
- adguard.tf: fix stale neuralplatform.dev → neuralplatform.ai rewrite

Android Private DNS: set to dot.nook.family
Router: forward TCP 853 → 192.168.68.77
This commit is contained in:
Will Anderson
2026-03-24 09:27:21 -05:00
parent 3518620360
commit 087c5a79f4
3 changed files with 131 additions and 4 deletions
+29 -2
View File
@@ -1,4 +1,4 @@
# AdGuard Home — household DNS with ad blocking, local resolution, and DoH via dns.nook.family
# AdGuard Home — household DNS with ad blocking, local resolution, DoH via dns.nook.family, and DoT via dot.nook.family:853
resource "kubernetes_namespace" "dns" {
metadata {
@@ -89,6 +89,11 @@ resource "kubernetes_config_map" "adguard_defaults" {
name: EasyPrivacy
id: 5
tls:
enabled: true
server_name: dot.nook.family
port_dns_over_tls: 853
certificate_path: /etc/adguard/tls/tls.crt
private_key_path: /etc/adguard/tls/tls.key
allow_unencrypted_doh: true
filtering:
filtering_enabled: true
@@ -96,13 +101,35 @@ resource "kubernetes_config_map" "adguard_defaults" {
- domain: '*.nook.family'
answer: ${var.legion_ip}
enabled: true
- domain: '*.neuralplatform.dev'
- domain: '*.neuralplatform.ai'
answer: ${var.legion_ip}
enabled: true
EOT
}
}
# TLS certificate for DoT — issued via cert-manager DNS-01 (Cloudflare)
resource "kubernetes_manifest" "adguard_dot_cert" {
manifest = {
apiVersion = "cert-manager.io/v1"
kind = "Certificate"
metadata = {
name = "adguard-dot-tls"
namespace = kubernetes_namespace.dns.metadata[0].name
}
spec = {
secretName = "adguard-dot-tls"
issuerRef = {
name = "letsencrypt-prod"
kind = "ClusterIssuer"
}
dnsNames = ["dot.nook.family"]
}
}
depends_on = [kubernetes_manifest.cluster_issuer_prod]
}
# Deployment + Service managed by Argo CD — see servers/legion/apps/adguard.yaml
resource "kubernetes_ingress_v1" "adguard" {
+21 -2
View File
@@ -57,8 +57,15 @@ spec:
else:
cfg.setdefault("filters", []).append(df)
# Enforce allow_unencrypted_doh
cfg.setdefault("tls", {})["allow_unencrypted_doh"] = True
# Enforce TLS / DoT settings
cfg.setdefault("tls", {}).update({
"enabled": True,
"server_name": "dot.nook.family",
"port_dns_over_tls": 853,
"certificate_path": "/etc/adguard/tls/tls.crt",
"private_key_path": "/etc/adguard/tls/tls.key",
"allow_unencrypted_doh": True,
})
# Fix/ensure rewrites
cfg.setdefault("filtering", {})
@@ -77,6 +84,9 @@ spec:
mountPath: /opt/adguardhome/conf
- name: defaults
mountPath: /opt/adguard-defaults
- name: tls
mountPath: /etc/adguard/tls
readOnly: true
containers:
- name: adguard
image: adguard/adguardhome:latest
@@ -87,6 +97,9 @@ spec:
- name: dns-udp
containerPort: 53
protocol: UDP
- name: dot
containerPort: 853
protocol: TCP
- name: http
containerPort: 3000
protocol: TCP
@@ -95,6 +108,9 @@ spec:
mountPath: /opt/adguardhome/conf
- name: data
mountPath: /opt/adguardhome/work
- name: tls
mountPath: /etc/adguard/tls
readOnly: true
resources:
requests:
memory: 128Mi
@@ -112,6 +128,9 @@ spec:
- name: defaults
configMap:
name: adguard-defaults
- name: tls
secret:
secretName: adguard-dot-tls
---
apiVersion: v1
kind: Service
+81
View File
@@ -0,0 +1,81 @@
# ddclient — dynamic DNS daemon that keeps dot.nook.family pointing at the home public IP
# Updates Cloudflare A record every 5 minutes; required for DoT (port 853) which can't use Cloudflare proxy
resource "kubernetes_secret" "ddclient_config" {
metadata {
name = "ddclient-config"
namespace = kubernetes_namespace.dns.metadata[0].name
}
data = {
"ddclient.conf" = <<-EOT
daemon=300
syslog=yes
pid=/var/run/ddclient/ddclient.pid
use=web, web=https://api.ipify.org
protocol=cloudflare
zone=nook.family
ttl=120
login=${var.cloudflare_email}
password=${var.cloudflare_api_key}
dot.nook.family
EOT
}
}
resource "kubernetes_deployment" "ddclient" {
metadata {
name = "ddclient"
namespace = kubernetes_namespace.dns.metadata[0].name
labels = { app = "ddclient" }
}
spec {
replicas = 1
selector {
match_labels = { app = "ddclient" }
}
template {
metadata {
labels = { app = "ddclient" }
}
spec {
container {
name = "ddclient"
image = "ghcr.io/linuxserver/ddclient:latest"
env {
name = "PUID"
value = "1000"
}
env {
name = "PGID"
value = "1000"
}
volume_mount {
name = "config"
mount_path = "/config/ddclient.conf"
sub_path = "ddclient.conf"
read_only = true
}
resources {
requests = { memory = "32Mi", cpu = "10m" }
limits = { memory = "64Mi" }
}
}
volume {
name = "config"
secret {
secret_name = kubernetes_secret.ddclient_config.metadata[0].name
}
}
}
}
}
depends_on = [kubernetes_namespace.dns]
}