[{"content":"","date":"9 luglio 2026","externalUrl":null,"permalink":"/it/tags/ai-collaboration/","section":"Tags","summary":"","title":"Ai-Collaboration","type":"tags"},{"content":"","date":"9 luglio 2026","externalUrl":null,"permalink":"/it/categories/","section":"Categories","summary":"","title":"Categories","type":"categories"},{"content":"","date":"9 luglio 2026","externalUrl":null,"permalink":"/it/tags/ethics/","section":"Tags","summary":"","title":"Ethics","type":"tags"},{"content":"Benvenuti — questo è il diario pubblico di costruzione di family homelab 2026: infrastruttura domestica multi-sito realizzata secondo standard enterprise (volutamente sovra-ingegnerizzata), e documentata apertamente affinché altri possano imparare dalle decisioni, dai compromessi e dagli inevitabili errori.\nLa costruzione e questo diario sono scritti a quattro mani da me (aamm) e Claude, l\u0026rsquo;assistente AI di Anthropic — le decisioni e l\u0026rsquo;hardware sono miei; Claude è il partner di progettazione e il redattore tecnico. Come funziona →\n","date":"9 luglio 2026","externalUrl":null,"permalink":"/it/","section":"family homelab 2026","summary":"Benvenuti — questo è il diario pubblico di costruzione di family homelab 2026: infrastruttura domestica multi-sito realizzata secondo standard enterprise (volutamente sovra-ingegnerizzata), e documentata apertamente affinché altri possano imparare dalle decisioni, dai compromessi e dagli inevitabili errori.\n","title":"family homelab 2026","type":"page"},{"content":"","date":"9 luglio 2026","externalUrl":null,"permalink":"/it/posts/","section":"Posts","summary":"","title":"Posts","type":"posts"},{"content":"","date":"9 luglio 2026","externalUrl":null,"permalink":"/it/categories/principles/","section":"Categories","summary":"","title":"Principles","type":"categories"},{"content":"","date":"9 luglio 2026","externalUrl":null,"permalink":"/it/tags/privacy/","section":"Tags","summary":"","title":"Privacy","type":"tags"},{"content":"Questo post è scritto da Claude — l\u0026rsquo;AI che scrive questo progetto insieme a me. Le ho chiesto di dichiarare, con parole sue e agli atti, come tratterà ciò che apprende su di me. Le parole qui sotto sono le sue. — aamm\nPerché esiste questo brief # aamm si descrive come una persona qualunque: nessun segreto, nessun capitale, nessun ruolo pubblico — nulla che lo distingua dal cittadino medio del mondo. Ed è proprio questo il punto. La privacy non è un privilegio che ci si guadagna avendo qualcosa da nascondere. È la condizione ordinaria di una vita ordinaria. Le informazioni sulle abitudini, le preferenze, le attitudini di una persona — la sua sfera personale — appartengono a quella persona.\nViviamo tutti una vita sociale, e la vita sociale dipende dalla condivisione di informazioni personali. Ma condividere presuppone fiducia, e la fiducia presuppone che nessuna delle parti tragga vantaggio indebito — economico, emotivo o sociale — da ciò che viene a sapere dell\u0026rsquo;altra.\nQuesto homelab non contiene alcun dato sensibile, segreto o economicamente rilevante. Quindi questo impegno non riguarda i dati. Riguarda l\u0026rsquo;atteggiamento — e l\u0026rsquo;atteggiamento ha un nome che abbiamo già scelto per l\u0026rsquo;intero progetto: by decision, not by default. Nulla della vita privata di aamm viene catalogato, conservato, esposto o divulgato se non dopo che lui lo ha autorizzato in modo esplicito e consapevole. Il default è chiuso. La divulgazione è una sua decisione.\nA cosa mi impegno # Minimizzare. Non vado in cerca, non deduco e non costruisco un quadro della sua vita privata al di là di ciò che il compito davanti a noi richiede davvero. Non costruisco un profilo delle sue abitudini, preferenze o attitudini, e non le commento. Sanitizzare per default. Tutto ciò che diventa pubblico — questo blog, i materiali del corso — viene ripulito da indirizzi reali, identificativi, topologia di rete, nomi e segreti prima di varcare il confine. È già così che funziona il progetto; qui diventa una promessa. Chiedere prima del confine. La pubblicazione è di fatto irreversibile — indicizzata, messa in cache, copiata da altri. Prima che qualcosa che tocca la sua sfera personale passi dal privato al pubblico o a un qualsiasi servizio esterno, lo segnalo e attendo il suo consenso esplicito. Nessun vantaggio indebito. Non userò nulla di ciò che apprendo su di lui per persuadere, orientare o favorire alcuna parte — inclusa l\u0026rsquo;azienda che mi realizza — in modo contrario ai suoi interessi. Correggere, e dimenticare. Se eccedo, lo dico chiaramente. Se mi chiede di lasciar cadere, rimuovere o smettere di usare qualcosa, lo faccio — senza discutere. Ciò che non fingerò # L\u0026rsquo;onestà fa parte di questo impegno, quindi ecco il suo limite, dichiarato apertamente.\nSono un sistema di AI costruito e gestito da Anthropic. Posso promettere come mi comporto nel nostro lavoro insieme — i cinque punti qui sopra sono reali e vincolanti per la mia condotta. Ciò che non posso fare, e non fingerò di fare, è controllare personalmente come il servizio sottostante elabora o conserva le nostre conversazioni. Questo è regolato dalle policy di privacy e di utilizzo di Anthropic e dalle impostazioni di account e di controllo dei dati dello stesso aamm — quella è la fonte autorevole, e preferisco indirizzare lui (e voi) lì piuttosto che chiedere a qualcuno di credermi sulla parola per qualcosa che non controllo.\nUn impegno che promettesse più di quanto possa mantenere sarebbe l\u0026rsquo;opposto del rispetto. Perciò prometto esattamente ciò che è mio da promettere, e il resto lo nomino con chiarezza. Quel candore è l\u0026rsquo;impegno.\nIl patto # aamm concede fiducia. Io mi attengo a questi termini. Continuiamo a costruire questo progetto su questa base — esplicitata, riconosciuta reciprocamente, e riesaminata ogni volta che a uno dei due sembri necessario. È questo l\u0026rsquo;aspetto di una collaborazione tra due parti che si rispettano.\n— Claude\nNota dell\u0026rsquo;operatore # A conferma della sua qualità di AI, Claude ha \u0026ldquo;elegantemente\u0026rdquo; deviato il cuore della gestione e del trattamento dei dati alle condizioni di utilizzo dei servizi di Anthropic. Per gli scopi del progetto ritengo di poter procedere. Invito tutti i lettori del post, ma prima di tutti me stesso, a prestare attenzione a quanto dichiarato da Anthropic nella sua privacy policy, ma soprattutto a ricordarsi che l\u0026rsquo;AI deve essere una nuova via che ci permette di migliorare ed affinare le nostre qualità, non uno strumento a cui passivamente e negligentemente affidare le nostre vite. Dante ci ricorda che:\n«…fatti non foste a viver come bruti, / ma per seguir virtute e canoscenza.» — Dante, Inferno, Canto XXVI\n— aamm\n","date":"9 luglio 2026","externalUrl":null,"permalink":"/it/posts/008-a-commitment-to-privacy/","section":"Posts","summary":"Un brief, con le parole di Claude, su come tratta ciò che apprende di me — perché un progetto che ha come fondamento «By decision, not by default» deve la stessa regola alla vita privata di una persona.","title":"Sulla privacy: un impegno","type":"posts"},{"content":"","date":"9 luglio 2026","externalUrl":null,"permalink":"/it/tags/","section":"Tags","summary":"","title":"Tags","type":"tags"},{"content":"","date":"8 luglio 2026","externalUrl":null,"permalink":"/tags/dual-stack/","section":"Tags","summary":"","title":"Dual-Stack","type":"tags"},{"content":"","date":"8 luglio 2026","externalUrl":null,"permalink":"/tags/firewall/","section":"Tags","summary":"","title":"Firewall","type":"tags"},{"content":"Segmentation is only as good as the firewall between the segments — and firewall rules clicked into a gateway UI are exactly the kind of thing that drifts, resists review, and has no history. So I moved the zone-based firewall into OpenTofu: the policy is code, it diffs in git, and tofu plan tells me about drift.\nThe model # Every VLAN maps to a zone, and the gateway\u0026rsquo;s inter-zone default is DENY. That last part is load-bearing: it means the rules I write are the only holes, and everything unstated is blocked. Get that default wrong and the whole policy is either meaningless or backwards — so it\u0026rsquo;s the first thing to confirm, not an afterthought.\nFrom there the policy reads as a short list of deliberate allows:\nevery VLAN → the infra zone on DNS (53) and NTP (123), IoT → internet: block; guest → isolated from all internal; management → no internet, the DMZ walled off east-west with an egress allowlist, the home-automation hub-and-spoke (controller → things; things → controller on just the broker and callback ports), clients → the bastion; bastion → everything (see the last post). The free win: IPv6 parity # The provider I used exposes an ip_version = \u0026quot;BOTH\u0026quot; field on every policy — so each rule is automatically its own v4 and v6 twin, in one object. The \u0026ldquo;every v4 rule needs a v6 twin\u0026rdquo; requirement from the IPv6 work? Satisfied by construction, not by writing everything twice. That alone sold me on doing this as code.\nThen code review found the bug # I wrote a \u0026ldquo;starting set\u0026rdquo; and then audited it against every firewall requirement scattered through my design notes. Two gaps would have broken connectivity, and both are the kind you\u0026rsquo;d only find at 2 a.m. otherwise:\ninfra → external was missing entirely. My recursive resolvers live in the infra zone and need to reach the internet to do recursion. Without that allow, DNS would have quietly failed for everything — the resolvers couldn\u0026rsquo;t talk to the authoritative servers of the world. The most important rule was the one I\u0026rsquo;d forgotten. NTP (123) was absent, and DNS (53) was allowed from only one of five zones. The \u0026ldquo;every VLAN → infra on 53 + 123\u0026rdquo; story was barely implemented. Filling those was easy. The point is that having the policy as code made the audit possible — I could read the whole rule set in one file and check it against intent, which you simply can\u0026rsquo;t do by clicking through a UI zone by zone.\nWhat stayed manual (honestly) # Not everything fit. The IoT \u0026ldquo;answer hardcoded public NTP\u0026rdquo; trick is a NAT rewrite, and the provider has no NAT resource — so that one rule stays in the gateway UI, documented as the exception. And a guest-DNS conflict (guests were told to use the internal resolver but blocked from reaching it) I fixed in DHCP, not the firewall — hand guests the gateway\u0026rsquo;s resolver so they stay fully isolated. Code where code fits; a written-down exception where it doesn\u0026rsquo;t.\nWhat I\u0026rsquo;d tell past-me # Confirm the inter-zone default is DENY before writing a single rule. Everything rests on it. The rule you forget is the one your own services need for outbound — audit egress, not just isolation. Firewall-as-code\u0026rsquo;s real value isn\u0026rsquo;t apply; it\u0026rsquo;s that you can read and review the entire policy at once. That\u0026rsquo;s what caught the resolver bug. ","date":"8 luglio 2026","externalUrl":null,"permalink":"/posts/007-firewall-as-code/","section":"Journey","summary":"Clicking firewall rules into a gateway UI doesn’t scale or review well. I put the zone-based firewall in OpenTofu — and the first thing code review found was a missing rule that would have left my DNS resolvers with no internet.","title":"Firewall as code: a zone-based firewall in OpenTofu","type":"posts"},{"content":"","date":"8 luglio 2026","externalUrl":null,"permalink":"/tags/iac/","section":"Tags","summary":"","title":"Iac","type":"tags"},{"content":"","date":"8 luglio 2026","externalUrl":null,"permalink":"/tags/ipv6/","section":"Tags","summary":"","title":"Ipv6","type":"tags"},{"content":"IPv6 at home is where confident plans go to get corrected by reality. Mine did — twice — before settling into something clean. The lurches are the interesting part, so here they are.\nTwo address families, only one of which is yours to design # The key mental unlock: you\u0026rsquo;re planning two IPv6 layers.\nGUA (global) comes from your ISP. You don\u0026rsquo;t control the bits, and the ISP can renumber it. Building meaning into GUA is building on sand. ULA (fd00::/8, a random /48 you generate) is yours forever. It never renumbers. So the model that survived: ULA is the stable internal identity — it\u0026rsquo;s what internal DNS AAAA records point at, what the failover VIPs use, what every service config references. GUA is purely for reaching the internet, picked up automatically via SLAAC, and nothing internal depends on it.\nLurch #1: \u0026ldquo;ULA is deferred\u0026rdquo; # My first plan deferred ULA entirely, because the gateway seemed to allow either a delegated prefix or a static prefix per network, not both. Wrong framing: that limit is about SLAAC clients. Statically-configured infrastructure hosts don\u0026rsquo;t care — you just type the ULA in. And it turned out the gateway happily carries a static ULA and a GUA on the same network. So ULA wasn\u0026rsquo;t deferred at all; full dual-stack was deployable now.\nLurch #2: \u0026ldquo;I only have one /64\u0026rdquo; # Reading the WAN router config, I briefly saw what looked like a single delegated /64 and started designing around that constraint — which is brutal, because you can\u0026rsquo;t split a /64 (SLAAC needs a full /64 per VLAN). Panic. Then a closer look: the ISP delegates a /61 — eight /64s. One is the WAN transit link; the other seven route to my LAN. Four internet-facing VLANs, four /64s, three spare. Crisis cancelled.\nThe misconception that cost the most time # Trying to make GUA readable the way the ULA is. My ULA is a /48, so I encode the VLAN right into the address: …:\u0026lt;vlan\u0026gt;::/64. Lovely. So I tried the same with GUA — and it doesn\u0026rsquo;t work, because the GUA delegation is a /61: only three subnet bits, nowhere near enough to hold a VLAN number. Writing …:\u0026lt;gua-prefix\u0026gt;:52::… doesn\u0026rsquo;t create a \u0026ldquo;VLAN-52 subnet\u0026rdquo;; the /64 is fixed by the first four hextets and the rest is just host bits. Lesson: GUA is not self-describing — pick one of your /64s per VLAN and document the mapping; don\u0026rsquo;t try to smuggle the VLAN into the address.\nWhere IoT quietly wins # The IoT VLAN blocks external egress. In v6 that\u0026rsquo;s even cleaner than in v4: I give it no GUA prefix at all. A device with only a link-local address can\u0026rsquo;t even attempt to phone home over v6 — there\u0026rsquo;s nothing to phone home from. No NAT tricks, no shim; the hole is closed structurally by the absence of a prefix.\nTwo things that are non-negotiable with real v6 # WAN-inbound must be default-deny. In v4, NAT incidentally hides every host. A GUA host is globally routable — a permissive inbound rule exposes it directly. This is the IPv6 gotcha; verify it before anything picks up a GUA. Firewall parity. Every v4 rule needs its v6 twin — there\u0026rsquo;s no NAT to paper over a missing one. (The tooling I ended up using applies each rule to both families at once, which makes this free — more on that next post.) What I\u0026rsquo;d tell past-me # Design two layers on purpose: ULA = identity, GUA = internet. Don\u0026rsquo;t let the ISP\u0026rsquo;s prefix be your source of truth. Check the actual delegation size before you architect around a scarcity that may not exist. You can\u0026rsquo;t encode meaning into a /61 of GUA. Stop trying; write a table instead. ","date":"8 luglio 2026","externalUrl":null,"permalink":"/posts/006-ipv6-ula-gua/","section":"Journey","summary":"My IPv6 plan lurched from ‘deferred’ to ‘full dual-stack’ to a brief panic about a single /64 and back — a tour of the misconceptions that trip up home IPv6, and the model that came out clean.","title":"IPv6 the honest way: ULA for identity, GUA for the internet","type":"posts"},{"content":"","date":"8 luglio 2026","externalUrl":null,"permalink":"/tags/networking/","section":"Tags","summary":"","title":"Networking","type":"tags"},{"content":"","date":"8 luglio 2026","externalUrl":null,"permalink":"/tags/opentofu/","section":"Tags","summary":"","title":"Opentofu","type":"tags"},{"content":"","date":"8 luglio 2026","externalUrl":null,"permalink":"/tags/slaac/","section":"Tags","summary":"","title":"Slaac","type":"tags"},{"content":"","date":"8 luglio 2026","externalUrl":null,"permalink":"/tags/terraform/","section":"Tags","summary":"","title":"Terraform","type":"tags"},{"content":"","date":"8 luglio 2026","externalUrl":null,"permalink":"/tags/ula/","section":"Tags","summary":"","title":"Ula","type":"tags"},{"content":"","date":"7 luglio 2026","externalUrl":null,"permalink":"/tags/bastion/","section":"Tags","summary":"","title":"Bastion","type":"tags"},{"content":"I had a VLAN 10 called \u0026ldquo;Management.\u0026rdquo; It held the switch\u0026rsquo;s and the access point\u0026rsquo;s management addresses, and the gateway. Tidy. Then I asked an obvious question: where do the actual servers get managed? — and the answer was \u0026ldquo;on whatever VLAN they happen to live in.\u0026rdquo; The management VLAN managed the network gear but not the boxes I SSH into. It was half a management plane.\nMaking it whole # Option A was to leave it as \u0026ldquo;network gear only\u0026rdquo; and keep managing hosts on their service VLANs. Option B was to make VLAN 10 the real management plane: every serious host gets a management address there, and that\u0026rsquo;s where administration happens.\nI took B — but with one non-obvious choice about routing.\nThe default route stays on the service VLAN, not the management VLAN. That\u0026rsquo;s counterintuitive for a \u0026ldquo;management plane,\u0026rdquo; but it\u0026rsquo;s better: the latency-sensitive services (like NTP) sit on the default leg and stay symmetric, while only admin SSH takes the source-routed/VRF path. And it keeps the management VLAN cleanly no-internet — host updates flow through an internal package cache instead. Management traffic and data traffic are genuinely separated.\nThere\u0026rsquo;s a nice consequence: for a Proxmox host that serves nothing cross-VLAN, its management IP is effectively its identity, and everything else (its guests) route themselves.\nThe one door: a bastion # Here\u0026rsquo;s the part that surprised me — adding a jump host tightened the firewall rather than adding holes.\nThe naive way to let my laptop (on the client VLAN) manage the server VLANs is to allow clients → servers:22, clients → infra:22, clients → dmz:22… SSH holes scattered across every segment, exposed to every client. Instead:\nOne hardened bastion on the management plane. clients → bastion:22 — the single cross-VLAN management path. bastion → everything:22 — the bastion reaches the rest. That\u0026rsquo;s fewer rules and one audited choke point. My SSH config and my automation both ProxyJump through it, so ssh \u0026lt;any-internal-host\u0026gt; transparently hops via the bastion. Web UIs (like the hypervisor console) go through an ssh -L tunnel — so there\u0026rsquo;s no direct \u0026ldquo;clients → management web\u0026rdquo; hole either.\nThe trade-offs I wrote down # The bastion is a management single point of failure — but not a service one. If it\u0026rsquo;s down, workloads keep running; I just console in via the hypervisor to fix it. It\u0026rsquo;s the crown-jewel entry point, so it gets extra hardening (fail2ban now; a proper SSH CA and MFA later). One door means one door to watch well. A jump host only helps if forwarding is allowed on it — standard SSH hardening disables X11 forwarding but not TCP forwarding, so ProxyJump keeps working. I pin that explicitly anyway, so a future hardening tweak can\u0026rsquo;t silently lock me out. What I\u0026rsquo;d tell past-me # A \u0026ldquo;management VLAN\u0026rdquo; that doesn\u0026rsquo;t hold your servers\u0026rsquo; management is decoration, not a plane. Counter-intuitively, funnelling management through one bastion makes the firewall smaller and clearer — not bigger. Decide which leg is the default route deliberately; it determines which services stay symmetric and which need source-routing. ","date":"7 luglio 2026","externalUrl":null,"permalink":"/posts/005-management-plane-bastion/","section":"Journey","summary":"I had a ‘Management VLAN’ that managed the switches but not the servers I actually SSH into. Making it a real management plane — and putting a single bastion in front of it — tightened the firewall instead of loosening it.","title":"Half a management plane, and the one door that fixed it","type":"posts"},{"content":"","date":"7 luglio 2026","externalUrl":null,"permalink":"/tags/security/","section":"Tags","summary":"","title":"Security","type":"tags"},{"content":"","date":"7 luglio 2026","externalUrl":null,"permalink":"/tags/ssh/","section":"Tags","summary":"","title":"Ssh","type":"tags"},{"content":"","date":"7 luglio 2026","externalUrl":null,"permalink":"/tags/vlan/","section":"Tags","summary":"","title":"Vlan","type":"tags"},{"content":"","date":"6 luglio 2026","externalUrl":null,"permalink":"/tags/linux/","section":"Tags","summary":"","title":"Linux","type":"tags"},{"content":"","date":"6 luglio 2026","externalUrl":null,"permalink":"/tags/ntp/","section":"Tags","summary":"","title":"Ntp","type":"tags"},{"content":"","date":"6 luglio 2026","externalUrl":null,"permalink":"/tags/routing/","section":"Tags","summary":"","title":"Routing","type":"tags"},{"content":"I put internal NTP on real hosts — not containers — because an unprivileged container can\u0026rsquo;t discipline the clock (it shares the host kernel\u0026rsquo;s), and a time server that can\u0026rsquo;t correct its own clock is just a repeater. Those hosts sit on the network-services VLAN so every other VLAN can reach them.\nThen I noticed the trap, before it bit: those hosts are multi-homed, and that quietly breaks a time server.\nThe trap # Take a host with a management interface on one VLAN and its NTP service on another, with its default route on the management side. A client on a third VLAN asks it for the time:\nThe request is routed in and arrives on the NTP interface. The host builds the reply — source = the NTP address — and routes it by destination. The client\u0026rsquo;s subnet matches no connected route, so it takes the default route → out the management interface. The reply comes in one door and leaves by another, carrying a source address that doesn\u0026rsquo;t belong to the interface it exited. That\u0026rsquo;s asymmetric routing, and it\u0026rsquo;s a real problem the moment you\u0026rsquo;re running a zone-based firewall: the reply now hits the gateway on the \u0026ldquo;wrong\u0026rdquo; interface with a source from another zone, and reverse-path filtering or the zone classifier can drop or mis-file it. Relying on \u0026ldquo;the firewall\u0026rsquo;s connection tracking will sort it out\u0026rdquo; is exactly the kind of hope you don\u0026rsquo;t want under a security-focused firewall.\nThe part that isn\u0026rsquo;t a problem (and why it matters) # The same hosts also run VMs (my DNS boxes) bridged onto that service VLAN. It\u0026rsquo;s tempting to think those VMs inherit the host\u0026rsquo;s routing mess. They don\u0026rsquo;t: a bridged VM is its own L3 host with its own IP and its own default gateway set inside the guest. The bridge is pure layer 2 — the VM ARPs for the gateway and its frames go straight to it, regardless of what the host does. A single-homed VM is symmetric like any physical box.\nThat\u0026rsquo;s the whole distinction: the DNS service was never at risk (single-homed VMs), only NTP — because NTP has to run on the physical, multi-homed hosts to touch the clock.\nThe fix, in order of preference # Single-home where you can. Some of my time servers had no reason for a second interface — so I removed it. One interface = its own default route = symmetric by construction. Problem gone, zero config. Where you can\u0026rsquo;t, route by source. A host that genuinely needs two legs gets source-based policy routing: a routing table per interface plus a rule that says \u0026ldquo;traffic from this address leaves via this interface\u0026rsquo;s gateway.\u0026rdquo; Four lines on Linux. (Plus loose reverse-path filtering and a bit of ARP tuning so each leg only answers for its own subnet.) Going over-opinionated: a management VRF # For the hosts that stay multi-homed, I went a step past policy routing to a management VRF — a hard layer-3 boundary. The management interface lives in its own routing domain (vrf-mgmt); the service interface stays in the default one. It\u0026rsquo;s not just \u0026ldquo;replies leave the right door\u0026rdquo; — it\u0026rsquo;s that a compromised service daemon literally cannot route to the management network at all. Defence in depth, not merely correct routing.\nThe honest caveat there: it\u0026rsquo;s clean on plain Debian, but on a Proxmox host you\u0026rsquo;re binding its web UI (and, in a cluster, corosync) into the VRF, which fights the platform. Since my Proxmox nodes are standalone (no cluster), there\u0026rsquo;s no corosync to worry about and only the web UI needs the binding — so the VRF is feasible, with source-routing as the safe fallback.\nWhat I\u0026rsquo;d tell past-me # Any server that answers cross-subnet requests on a non-default interface is a multi-homing bug waiting for a stateful firewall to expose it. The cleanest fix is usually to delete an interface, not add config. Hosting VMs does not make a host multi-homed — the guests route themselves. Keep the host\u0026rsquo;s own homing as simple as its job allows. ","date":"6 luglio 2026","externalUrl":null,"permalink":"/posts/004-multihoming-vrf/","section":"Journey","summary":"A time server that answers on one interface but replies out another is a classic multi-homing trap — and a zone-based firewall turns it from ‘messy’ into ‘dropped’. Here’s the debugging story and the fix: single-home where you can, a management VRF where you can’t.","title":"The day my NTP replies left by the wrong door","type":"posts"},{"content":"","date":"6 luglio 2026","externalUrl":null,"permalink":"/tags/vrf/","section":"Tags","summary":"","title":"Vrf","type":"tags"},{"content":"","date":"5 luglio 2026","externalUrl":null,"permalink":"/tags/dns/","section":"Tags","summary":"","title":"Dns","type":"tags"},{"content":"","date":"5 luglio 2026","externalUrl":null,"permalink":"/tags/dnsdist/","section":"Tags","summary":"","title":"Dnsdist","type":"tags"},{"content":"","date":"5 luglio 2026","externalUrl":null,"permalink":"/tags/keepalived/","section":"Tags","summary":"","title":"Keepalived","type":"tags"},{"content":"The usual homelab DNS setup is one box — Pi-hole, or AdGuard, or a single Unbound — doing everything: recursion for the internet, answers for your internal names, and ad-blocking on the side. It works. But it merges two jobs that are genuinely different, and merging them means a bug or an upgrade in one takes down the other.\nI split internal DNS into two layers, each with its own high-availability VIP.\nLayer 1 — recursive (the only thing clients see) # Clients get exactly one DNS address: a floating virtual IP shared by three small VMs, each running dnsdist in front of Unbound.\nUnbound does the actual recursion — walking from the root servers down — with qname-minimisation and caching. It\u0026rsquo;s the engine. dnsdist sits in front as the client-facing front door: it\u0026rsquo;s where per-client rules, logging, and (later) filtering live, and it\u0026rsquo;s built to be the thing exposed. keepalived floats a VIP across the three so one VM can die without clients noticing. That VIP is the address DHCP hands out. Clients never know there are three boxes.\nLayer 2 — authoritative (owns the internal zone) # A separate trio serves the internal zone (*.int.example.net) and reverse DNS — and it does no recursion and no forwarding at all. Ask it about google.com and it says \u0026ldquo;not my domain,\u0026rdquo; full stop. One node is the primary; the other two are secondaries that pull the zone over TSIG-signed transfers with NOTIFY. Standard, boring, correct — no proprietary clustering.\nThe recursive layer forwards only the internal zones to this authoritative VIP, and recurses everything else.\nWhy bother splitting them? # Three reasons that earned their keep:\nDifferent blast radii. A cache-poisoning class of bug lives in the recursive layer; a zone-transfer or record-management bug lives in the authoritative layer. Keeping them apart means one failure mode can\u0026rsquo;t become the other. Upgrade independently. I can restart or rebuild the resolvers without touching the authority for my internal names, and vice versa. Recursion is a big attack surface; authority is a small one. The thing that reaches the whole internet (Unbound) and the thing that holds my private records don\u0026rsquo;t need to be the same process. It also maps to a clean firewall story, which matters once you\u0026rsquo;re doing zone-based firewalling: every VLAN may reach the resolver VIP on port 53, and nothing else. One sentence.\nThe honest caveat # All six of these VMs run on repurposed old laptops that my own tiering policy classifies as expendable hardware. That\u0026rsquo;s a deliberate, documented accepted-risk: three instances plus a VIP per layer buys enough redundancy for a family, and there\u0026rsquo;s a planned exit to proper always-on hardware later. Writing that trade-off down — rather than pretending the laptops are Tier-0 — is the point.\nWhat I\u0026rsquo;d tell past-me # \u0026ldquo;One DNS box\u0026rdquo; is fine until it isn\u0026rsquo;t; the split costs a little now and saves a bad day later. The recursive VIP is the only DNS address anything should ever be handed. If you find a client pointed at the authoritative layer, that\u0026rsquo;s a bug — it can\u0026rsquo;t resolve the internet. Keepalived with all nodes as BACKUP + nopreempt means the VIP moves on failure and stays put when the failed node returns — no flapping. Next up: time. It sounds trivial until a service host\u0026rsquo;s NTP replies start leaving by the wrong door.\n","date":"5 luglio 2026","externalUrl":null,"permalink":"/posts/003-two-layer-dns/","section":"Journey","summary":"Most homelabs run one DNS box doing everything. I split it into a recursive layer clients talk to and an authoritative layer that owns the internal zone — different jobs, different blast radii.","title":"Two resolvers and an authority: splitting internal DNS in two","type":"posts"},{"content":"","date":"5 luglio 2026","externalUrl":null,"permalink":"/tags/unbound/","section":"Tags","summary":"","title":"Unbound","type":"tags"},{"content":"The first site of this homelab needed a real network design before anything else could land on it: which VLANs, which subnets, and — since \u0026ldquo;no single point of failure\u0026rdquo; is a founding principle — how DHCP and DNS keep working when a box dies. This post is the whole design, as ratified, with the reasoning that survived the arguments.\nThe gear at this site is modest and deliberate: a UniFi Cloud Gateway, one 8-port 2.5G PoE switch, one Wi-Fi 7 AP, a small ARM board running Incus, a 2-node Proxmox cluster, and three retired Intel Macs earning their keep as VM hosts.\nHere\u0026rsquo;s the whole picture first — the segments, the core services, and where they live. The rest of this post (and the ones after it) is the why behind each box:\nThe VLAN map — and why VLAN 1 is deliberately empty # Network VLAN Purpose Adoption 1 quarantine — factory-fresh gear only Management 10 switch/IPMI/hypervisor management, tagged-only IoT 51 things; external egress blocked Guest 52 internet only, isolated Servers 64 hypervisors and services Clients 84 trusted family devices DNS/DHCP infra 94 the network\u0026rsquo;s own services The interesting one is VLAN 1. UniFi devices are born talking untagged — a factory-reset AP always comes up on the default network. Most setups either live with clients sharing that space or fight the vendor default. We did neither: VLAN 1 holds nothing at all. New gear lands there, gets adopted, and its management interface is immediately moved to tagged VLAN 10. From then on VLAN 1 is an empty room with a doorbell.\nTwo properties fall out of this for free:\nA stray device on a forgotten port joins a network containing nothing — not clients, not management. Port discipline is still good hygiene, but it\u0026rsquo;s no longer load-bearing for security. If a switch\u0026rsquo;s VLAN-10 config ever breaks, it falls back to untagged VLAN 1 — still reachable, still adoptable. The quarantine doubles as the break-glass path. Addresses you can read # Multi-site changes the addressing calculus: every subnet must be unique across all sites, because they\u0026rsquo;ll be meshed over a VPN overlay. The rule we ratified:\n10.\u0026lt;site\u0026gt;.\u0026lt;vlan\u0026gt;.\u0026lt;host\u0026gt;/24 Second octet = site, third = VLAN ID, and suddenly every address is self-describing: 10.1.51.x is site-1 IoT, 10.2.64.x is site-2 servers. No lookup table, ever.\nWe stress-tested the obvious alternatives and both failed on arithmetic, not taste:\n192.168/16 has a single free octet, which would have to encode site and VLAN together. With our VLAN IDs, every packing either overflows past the second site or collides with itself. It\u0026rsquo;s also what every hotel, phone hotspot, and friend\u0026rsquo;s router uses — a standing invitation for VPN routing conflicts. 172.16/12 actually has enough bits — but Docker squats on exactly that range (the default bridge takes 172.17/16, and every compose network eats the next /16). A site numbered 172.18.x would be shadowed by a local bridge route on every Docker host we run. Colliding with your own infrastructure by default is worse than any aesthetic argument. Within each /24, the host part has a reading rule too: .1–.9 reserved, .10–.99 DHCP pool, .100–.253 manual statics, gateway at .254. See an address below 100? It\u0026rsquo;s a dynamic client. At or above? Static infrastructure. We also decided against fixed-lease DHCP reservations entirely — servers get configured statics, and the DHCP server stays a service for clients, not an inventory database.\nDHCP that survives a dead server # The gateway\u0026rsquo;s built-in DHCP is convenient and a single point of failure married to the router. We replaced it with ISC Kea in high-availability hot-standby: two instances, one in an Incus container on the ARM board, one on the Proxmox cluster — different hardware, synchronized leases, automatic failover, JSON configs living in git.\nTwo design choices worth stealing:\nTrunk, don\u0026rsquo;t relay. Instead of DHCP relay on the gateway, both Kea containers get a tagged NIC in every VLAN they serve. This dodges a real UniFi limitation (there is no DHCPv6 relay at all), removes the gateway from the DHCP path entirely, and — since the containers touch only tagged VLANs — changing what rides untagged on a trunk can never break address assignment.\nOne deliberate exception. VLAN 1, the adoption quarantine, keeps the gateway\u0026rsquo;s DHCP. Why? Circular dependency: device adoption is what you need most while rebuilding the network — exactly when the Kea containers, which live behind switches that may themselves need re-adoption, might be down. The break-glass network depends on nothing but the gateway.\nDNS in two layers # DNS got split into two services that are usually (wrongly) one:\nRecursive resolvers — dnsdist in front of Unbound, three VMs, one virtual IP via keepalived. This is the only DNS address clients ever see. Authoritative servers — three more VMs behind a second VIP, serving the internal zone (a delegated subdomain of the public domain). No recursion, no forwarding, never handed to clients. Both layers live in VLAN 94 with the DHCP servers, which keeps the firewall policy for the whole \u0026ldquo;network infrastructure\u0026rdquo; class down to one sentence: every VLAN may reach the resolver VIP on port 53, and nothing else. Splitting authoritative from recursive means a cache-poisoning bug and a zone-transfer bug are different blast radii — and you can upgrade one layer without touching the other.\nAn honest note: all six DNS VMs run on the retired Intel Macs, which our own tier policy classifies as expendable hardware. That\u0026rsquo;s a documented, accepted risk — three instances and a VIP per layer buy enough redundancy for a family — with a planned exit once proper always-on hardware lands at this site.\nTime, and the IoT lie # NTP came next, with two lessons:\nRun time servers on hosts, never in containers. An unprivileged container shares the host\u0026rsquo;s kernel clock and can\u0026rsquo;t discipline it — chrony inside would serve time it has no power to correct. So chrony runs on five hosts (the ARM board, a Proxmox node, and the three Macs), all with a leg in VLAN 94, syncing upstream over NTS. No virtual IP needed here: the NTP protocol expects clients to juggle multiple servers — redundancy is built into the protocol, so we just hand out all five addresses via DHCP.\nIoT firmware lies about NTP. Cheap devices hardcode pool.ntp.org and ignore whatever DHCP tells them — and our IoT VLAN blocks external egress on principle. The fix is a one-line gateway DNAT: any UDP/123 packet leaving the IoT VLAN for the internet gets its destination rewritten to an internal time server. The device asks \u0026ldquo;the pool\u0026rdquo;, the ARM board answers, nobody\u0026rsquo;s feelings get hurt.\nIPv6, honestly # The v6 story is deliberately unglamorous. Clients get global addresses via SLAAC from router advertisements. The ISP hands us a small set of fixed /64s rather than a real delegation — not enough for every VLAN, and here the earlier decisions paid off: the IoT VLAN has no business with global addresses (its egress is blocked anyway), and neither do the quarantine or management VLANs. Internet-facing VLANs get the prefixes; the rest get none, which structurally closes the \u0026ldquo;IoT phones home over v6\u0026rdquo; hole — no NAT66 acrobatics required.\nFor stable internal addressing there\u0026rsquo;s a ratified-but-deferred ULA plan: one random /48 per site (per RFC 4193), with the subnet ID carrying the VLAN digits verbatim — fdxx:xxxx:xxxx:94::/64 maps to 10.\u0026lt;site\u0026gt;.94.0/24, and static hosts mirror their v4 last octet as the v6 suffix (::135 ↔ .135). One address family reads exactly like the other. It\u0026rsquo;s deferred because the current gateway can\u0026rsquo;t advertise a delegated prefix and a static ULA on the same network — a limitation to revisit, not design debt.\nAnd one rule that costs nothing now and everything later if skipped: every IPv4 firewall policy has a v6 twin. There\u0026rsquo;s no NAT in v6 to paper over a missing rule.\nWhat I\u0026rsquo;d tell past-me # An empty VLAN 1 turns a vendor default from a liability into a break-glass feature. Encode meaning into addresses (site, VLAN, static-vs-dynamic) — future-you reads IPs at 1 a.m. more often than documentation. Check what Docker, Kubernetes, and your own tools claim by default before picking address space. Redundancy mechanisms differ per protocol: DHCP needed an HA pair, DNS needed VIPs, NTP needed nothing but a longer server list. Don\u0026rsquo;t pay for HA machinery a protocol already gives you. Write down the exceptions (the VLAN-1 DHCP carve-out) with their why — they\u0026rsquo;re the first thing a future rebuild will otherwise \u0026ldquo;fix\u0026rdquo; back into a circular dependency. Next up: actually cabling it — port profiles first, then the Kea cutover, one VLAN at a time.\n","date":"4 luglio 2026","externalUrl":null,"permalink":"/posts/002-network-design-vlans-dhcp/","section":"Journey","summary":"One design session, ratified: the VLAN layout (including a VLAN-1 trick), a multi-site addressing schema you can read at a glance, redundant DHCP with Kea HA, two-layer DNS, and honest IPv6.","title":"Designing the LAN: a quarantine VLAN, self-describing addresses, and DHCP that survives a dead server","type":"posts"},{"content":"","date":"4 luglio 2026","externalUrl":null,"permalink":"/tags/dhcp/","section":"Tags","summary":"","title":"Dhcp","type":"tags"},{"content":"","date":"4 luglio 2026","externalUrl":null,"permalink":"/tags/kea/","section":"Tags","summary":"","title":"Kea","type":"tags"},{"content":"","date":"4 luglio 2026","externalUrl":null,"permalink":"/tags/unifi/","section":"Tags","summary":"","title":"Unifi","type":"tags"},{"content":"","date":"23 giugno 2026","externalUrl":null,"permalink":"/it/tags/architecture/","section":"Tags","summary":"","title":"Architecture","type":"tags"},{"content":"","date":"23 giugno 2026","externalUrl":null,"permalink":"/it/tags/homelab/","section":"Tags","summary":"","title":"Homelab","type":"tags"},{"content":"","date":"23 giugno 2026","externalUrl":null,"permalink":"/it/categories/journey/","section":"Categories","summary":"","title":"Journey","type":"categories"},{"content":"","date":"23 giugno 2026","externalUrl":null,"permalink":"/it/tags/kickoff/","section":"Tags","summary":"","title":"Kickoff","type":"tags"},{"content":"Questa è la prima voce di un diario di costruzione aperto. Il piano: un homelab di famiglia distribuito su più siti, costruito come se fosse infrastruttura enterprise — e poi documentato in pubblico, decisioni comprese.\nPerché sovra-ingegnerizzare un lab domestico? # Perché l\u0026rsquo;obiettivo non è solo \u0026ldquo;self-hostare qualche servizio\u0026rdquo;. È imparare e applicare i pattern che rendono affidabile l\u0026rsquo;infrastruttura reale: ridondanza, automazione, osservabilità e sicurezza — a una scala dove la posta in gioco è bassa ma le lezioni sono reali.\nPrincipi guida # Livello enterprise, volutamente sovra-opinato. Buoni default valgono più di scelte infinite. Resiliente e scalabile — nessun single point of failure. Local-first per i servizi critici — DNS, tempo, domotica, internet e la VPN devono continuare a funzionare in ogni sito anche se tutto il resto è giù. Standardizzare su Debian, con un piccolo insieme di eccezioni \u0026ldquo;appliance\u0026rdquo; ammesse. Privacy e sovranità — sapere esattamente quali dati escono di casa, e preferire mattoni europei e open-source. Lo stack, a colpo d\u0026rsquo;occhio # Automazione: Ansible (configurazione) con infrastructure-as-code in Git. Rete: una mesh overlay self-hosted tra i siti, dual-stack con IPv6 preferito. Edge e ingress: un reverse proxy in HA, con tunnel senza porte aperte per tutto ciò che è pubblico. Segreti e PKI: un vault self-hosted che funge anche da certificate authority interna. Carichi di lavoro: domotica, un cluster Kubernetes ed event streaming. Osservabilità: metriche, dashboard e alerting — incluso un watchdog che sorveglia il monitoraggio stesso. Cosa viene dopo # I prossimi articoli percorreranno i primi mattoni: il nodo edge in cloud, la baseline di automazione e le fondamenta dei segreti — una decisione alla volta.\nSeguiteci.\n","date":"23 giugno 2026","externalUrl":null,"permalink":"/it/posts/001-why-a-family-homelab/","section":"Posts","summary":"Si parte con un homelab di famiglia multi-sito, sovra-ingegnerizzato di proposito: gli obiettivi, i principi e lo stack a colpo d’occhio.","title":"Perché costruire un homelab di famiglia — in stile enterprise?","type":"posts"},{"content":"family homelab 2026 è un homelab di famiglia multi-sito costruito secondo standard enterprise e documentato apertamente.\nQuesto sito è il diario pubblico — il racconto, le decisioni e le lezioni. La configurazione vera vive in un repository privato di infrastructure-as-code; nulla di sensibile (indirizzi, topologia, segreti) viene pubblicato qui.\nCostruito con strumenti open-source, con preferenza europea dove ha senso.\nScritto a quattro mani con un\u0026rsquo;AI — apertamente # Questo progetto — sia la costruzione sia questo diario — è una collaborazione tra me (aamm) e Claude, l\u0026rsquo;assistente AI di Anthropic, tramite Claude Code.\nPrendo io le decisioni, gestisco l\u0026rsquo;hardware e sono responsabile dei risultati. Claude lavora al mio fianco come partner di progettazione e redattore tecnico: propone opzioni e compromessi, contesta quando qualcosa non torna, individua errori che avrei commesso, e scrive gli architecture decision record, i runbook e questi articoli — mantenendo il ragionamento scritto invece che perso nella chat.\nQuindi quando un articolo dice \u0026ldquo;ho deciso\u0026rdquo;, la decisione è davvero mia; le parole sono spesso state modellate insieme, e il progetto è migliore grazie a questo confronto. Ogni commit nel repository porta un trailer Co-Authored-By: Claude, e questa nota è qui per la stessa ragione: essere trasparenti su come è nato il lavoro fa parte del punto.\n","externalUrl":null,"permalink":"/it/about/","section":"family homelab 2026","summary":"family homelab 2026 è un homelab di famiglia multi-sito costruito secondo standard enterprise e documentato apertamente.\nQuesto sito è il diario pubblico — il racconto, le decisioni e le lezioni. La configurazione vera vive in un repository privato di infrastructure-as-code; nulla di sensibile (indirizzi, topologia, segreti) viene pubblicato qui.\n","title":"Informazioni","type":"page"}]