apiVersion: apps/v1 kind: Deployment metadata: name: adguard namespace: dns labels: app: adguard spec: replicas: 1 strategy: type: Recreate selector: matchLabels: app: adguard template: metadata: labels: app: adguard spec: hostNetwork: true dnsPolicy: ClusterFirstWithHostNet initContainers: - name: apply-config image: python:3.12-alpine command: ["sh", "-c"] args: - | pip install -q pyyaml && python3 - <<'EOF' import yaml, os, shutil CONFIG = "/opt/adguardhome/conf/AdGuardHome.yaml" DEFAULT = "/opt/adguard-defaults/AdGuardHome.yaml" with open(DEFAULT) as f: desired = yaml.safe_load(f) if not os.path.exists(CONFIG): # First run — seed from defaults shutil.copy(DEFAULT, CONFIG) print("First run: seeded config from defaults") else: with open(CONFIG) as f: cfg = yaml.safe_load(f) # Enforce bind_hosts cfg.setdefault("dns", {})["bind_hosts"] = ["0.0.0.0"] # Enforce upstream + bootstrap DNS cfg["dns"]["upstream_dns"] = desired["dns"]["upstream_dns"] cfg["dns"]["bootstrap_dns"] = desired["dns"]["bootstrap_dns"] # Ensure desired filter lists are all present and enabled existing = {f["url"]: f for f in cfg.get("filters", [])} for df in desired.get("filters", []): if df["url"] in existing: existing[df["url"]]["enabled"] = True else: cfg.setdefault("filters", []).append(df) # 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", {}) existing_rw = {rw["domain"]: rw for rw in cfg["filtering"].get("rewrites", [])} for rw in desired.get("filtering", {}).get("rewrites", []): if rw["domain"] in existing_rw: existing_rw[rw["domain"]]["answer"] = rw["answer"] else: cfg["filtering"].setdefault("rewrites", []).append(rw) with open(CONFIG, "w") as f: yaml.dump(cfg, f, default_flow_style=False, allow_unicode=True) print("Config patched: DNS upstreams, filter lists, rewrites enforced") volumeMounts: - name: config 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 ports: - name: dns-tcp containerPort: 53 protocol: TCP - name: dns-udp containerPort: 53 protocol: UDP - name: dot containerPort: 853 protocol: TCP - name: http containerPort: 3000 protocol: TCP volumeMounts: - name: config mountPath: /opt/adguardhome/conf - name: data mountPath: /opt/adguardhome/work - name: tls mountPath: /etc/adguard/tls readOnly: true resources: requests: memory: 128Mi cpu: 100m limits: memory: 512Mi cpu: 500m volumes: - name: config persistentVolumeClaim: claimName: adguard-config - name: data persistentVolumeClaim: claimName: adguard-data - name: defaults configMap: name: adguard-defaults - name: tls secret: secretName: adguard-dot-tls --- apiVersion: v1 kind: Service metadata: name: adguard-ui namespace: dns spec: selector: app: adguard ports: - name: http port: 3000 targetPort: 3000 type: ClusterIP