This repository has been archived on 2026-09-17. You can view files and clone it, but you cannot make any changes to its state, such as pushing and creating new issues, pull requests or comments.
nixos-config/hosts/pinix/localServices/unbound.nix

75 lines
2.9 KiB
Nix

{ config, ... }:
let
# Split-horizon fuer die internen Namen *dieses* Stacks, also unter
# config.domain2. Erreichbar im gemeinsamen pinix-Tailnet.
# Traefiks websecure-Entrypoint lauscht auch auf der Tailnet-Adresse.
# 0ff.space und dessen AdGuard-Rewrites bleiben auf blunix.
internalNames = [
"dex"
"head"
"lldap"
];
in
{
# Rekursiver Resolver im gemeinsamen pinix-Tailnet auf pinix -- die Rolle,
# die AdGuardHome auf blunix fuer 0ff.space haelt und dort auch behaelt.
# Zwei bewusste Unterschiede zu jenem Aufbau:
#
# 1. Dieser rekursiert selbst, statt auf 1.1.1.1 und 8.8.8.8 zu
# forwarden. Internes DNS haengt damit nicht an Cloudflare und
# Google -- dieselbe Richtung wie der Cloudflare-Ausstieg.
# 2. Overrides sind Nix-`local-data`, das kein Enable-Flag pro Eintrag
# kennt. Die in CLAUDE.md dokumentierte AdGuard-Falle (jeder Rewrite
# braucht explizit `enabled = true`, alle neun hatten es nicht) kann
# hier nicht wiederkehren.
#
# AdGuardHomes `safe_search` wird nicht uebernommen (erzwang gefilterte
# Suchmaschinen-Varianten fuer jeden Client dieses Resolvers). Mit
# local-data-CNAMEs auf forcesafesearch.google.com o.ae. rekonstruierbar.
services.unbound = {
enable = true;
# Must stay false. The module would otherwise point /etc/resolv.conf at
# localhost, and pinix' own resolution depends on Mango's DNS64: reaching
# any IPv4-only host (blunix, Forgejo) happens through NAT64, which needs
# the resolver to synthesise AAAA from A. A plain recursive resolver
# returns the real A record instead and pinix loses that path silently.
# Same reasoning as bind.nix, verified across a reboot in
# docs/pinix-reboot-probe.md.
resolveLocalQueries = false;
settings.server = {
# Tailnet addresses only. Loopback belongs to the authoritative BIND
# (bind.nix), and binding both daemons to it would fail.
interface = [
config.tailnetIPs.pinix
"fd7a:115c:a1e0:96::4"
];
# tailscale0 appears later in boot than unbound, so without this the
# bind fails outright on a cold start.
ip-freebind = true;
# Open resolvers get abused for reflection. Only the Tailnet may query.
access-control = [
"100.96.0.0/24 allow"
"fd7a:115c:a1e0:96::/64 allow"
"0.0.0.0/0 refuse"
"::/0 refuse"
];
# `transparent` haelt den Rest der Zone rekursiv: nur die oben
# gelisteten Namen werden lokal beantwortet, alles andere unter
# config.domain2 loest normal oeffentlich auf. 0ff.space ist hier
# bewusst nicht genannt -- dafuer ist blunix zustaendig.
local-zone = [ ''"${config.domain2}." transparent'' ];
local-data = map
(name: ''"${name}.${config.domain2}. A ${config.tailnetIPs.pinix}"'')
internalNames;
hide-identity = true;
hide-version = true;
prefetch = true;
};
};
}