Skip to content
Oznog

Node0, as it stands

Inside a self-hosted infrastructure site: two rooms, four racks, 71 hosts, a storage cluster, a hypervisor cluster, GPU hosts behind one model gateway, and the agents that help run it. Its architecture, its decisions, what broke, and what it can carry, captured on 20260920 and re-measured on 20260921.

Four unnoticed failures on one day in September drove the monitoring build. Since then every alert names its runbook, the inventory is the source of truth, and backups are proven by restoring them. That is how the enterprise systems its architect built for Fortune 500 companies are run, at the size of one person.

The private site keeps changing; this capture does not. Figures name their source and date, and estimates state their assumptions. The capture was taken on 20260920 and its figures re-measured on 20260921; two things found and fixed on the capture day are marked as such. Sanitized 20260921: no addresses, credentials or serials; hosts keep their names; the finance host is described by shape only.

Published so that many others can deploy a Node of their own: as much as can be shared without compromising this one.

On this page: the layers · in use, and capacity · how it came to be · what runs on it · running models locally · what is shared · why we chose it · state at capture

Two rack fronts side by side: the storage servers with their drive bays, and the fan trays of the GPU hosts
Racks 2 and 3: the storage and compute wall, and the DI servers.

The layers #

Eleven pages, in the order the site depends on itself: the container everything runs in, then the boundary, the data plane, what must exist before anything else can be trusted, and up through the services a person touches. Each page has the same six parts: what the layer is for, how it is built, the decisions with their trade-offs, what it cost to replace, what broke, and its state on the day.

The eleven layers, and what rests on whatThe eleven layers of Node0 drawn as a stack: site as the frame, power under everything, operations beside everything, and the layers that rest on each other in bands from the edge and fabric up to services, agents and observability.1Site: two rooms, four racks, the inventory11Operationsdeploy branch, CI,the inventoryas authority7Serviceswhat a person touches8Agents and devwho operates it; thesandboxes; the rules9Observabilityis it working, right now5Storagehub, replica, cluster, offsite6Computehypervisors, GPUs, one gateway4Bootstrapnames, time, secrets, rebuild2Edgeone fibre, a firewall pair3Fabricsix switches in three pairs10Power and environmentseven UPS, nine ATS, the room. Everything above is fed by it; the shutdown design is its own layer's.rests on: read upward. Generated from data/diagrams/stack.yaml.
Read upward: each band rests on the one below. Site is the frame, power feeds everything, operations runs across every layer. Every layer page carries this drawing with its own layer lit.
1

Site

The container every other layer runs inside: two rooms, four racks, the cable plant, and the conventions that find one thing among many.

185 active devices · 4 racks in 2 rooms · 407 cables, 270 carrying a colour
2

Edge

The boundary between Node0 and the internet: one fibre, a firewall pair that survives losing one of itself, and an outside watcher.

2 firewalls, active and passive · 9 CARP groups, one master · 1 fibre, no second provider
3

Fabric

The switches, VLANs and bonds that decide what can reach what inside Node0.

6 Arista switches · 19 active VLANs · 135 hosts migrated in a day
4

Bootstrap

The services that must exist before anything else comes up: names, time, power signals, secrets, and a way to rebuild a host.

3 resolvers, 3 platforms · 3 NTP sources, 1 GPS · 3-member vault
5

Storage

Four tiers that each cover a different way to lose data, and the nightly habit that proves they work.

916 TiB Ceph raw · 493 TiB hub pool · 171 OSDs on nine hosts
6

Compute

The hypervisor cluster, the GPU hosts and the model gateway: the layer that turns rack space into work.

4 hypervisors, 224 threads / 112 cores · 9 accelerators on 7 hosts · 1 gateway address
7

Services

The layer a person actually touches: the names, the proxy in front of them, and the applications behind them.

53 containers on one host · 18,791 documents · 105,873 photos and 21,284 videos
8

Agents and dev

The machines the agents and the developers run on, the sandboxes the agents are allowed to break, and the rules that say what an agent may change without asking.

six agent machines · 2,069 commits, 11 by a human · one shared account, one key per agent
9

Observability

Answers one question honestly: is Node0 working right now, and if not, does a human need to know.

296 targets, 0 down · 387 rules, 357 alerting · 15 generated dashboards
10

Power and environment

Keeps every host fed through a blip, lands the fleet cleanly if an outage outlasts the batteries, and watches the room.

4 UPS at 240 V · 6,395 W measured · 103% rack 2 failover load
11

Operations

The habits that let more than one actor change the site without the history, the credentials or the inventory drifting.

2,069 commits since 20260810 · 140 runbooks · one branch between written and running

In use, and capacity #

Measured on 20260921 by read-only queries over the inventory export, the configuration repository and the live systems; nothing is a hand count. Each figure is what is in use today against what the site can carry, because the point of the build is the second number. The whole file of figures, with a source and date on every row, is published beside these pages. Inventory detail (cables, VLANs, interfaces) is on the layer pages.

7 of about 190virtual machines running, against room for about 190 at 8 GB and 2 vCPU with one node held in reserve (1511 GiB usable across three nodes; CPU at about 2.3 to 1 over the remaining 168 threads). That is arithmetic, not a tested limit.hypervisor API, 20260921
224 threads / 112 cores · 2015 GiBhypervisor CPU and memory across four nodes of 56 threads / 28 cores and 503.75 GiB each.hypervisor API, 20260921
43.2 of ~608 TiBCeph: used, against usable on 916 TiB raw (1007 TB) across 9 hosts and 171 drives: 5+2 erasure coding on the disk tier, three-way replication on flash; host is the failure domain.live cluster status, 20260921; usable is an estimate
53.8 of 493 TiBthe storage hub's main pool, allocated against raw (542 TB) across three raidz3 groups of ten; usable is about 70% of raw.live pool list, 20260921
987 TiB usable · 1606 TiB in diskswhat the three storage tiers can hold after their protection schemes (Ceph by arithmetic from the pool layouts, the hub and the replica as used plus available from ZFS), and every disk in every one of the 71 hosts as its operating system reports it, 356 disks; the storage tier is 95% of the second figure.zfs list, ceph df and lsblk, 20260922
10 GPUs · 369 GiB for modelsseven discrete cards on five DI hosts (136 GiB of VRAM), one more in a workstation (12 GiB, not behind the gateway), and two docked laptops serving from unified memory (128 GiB on the MacBook Pro, 93 on the Framework), both in full use; the laptops share that memory with the OS. The largest model served is gpt-oss-120b, on the MacBook Pro serving laptop. Built to expand: the rack space, power and transfer-switch capacity for more GPU hosts are already in place.live driver query, 20260921
6395 W of 19200 WUPS output against four units rated 4,800 W each at 240 V. Rack 2's pair draws 4928 W, which is 102.7% of one unit on failover, accepted by decision with the arithmetic recorded.NUT on the core host, 20260921
1235 threads / 735 cores · 8.39 TiBCPU threads, physical cores and memory across all 71 hosts, the storage servers and the Pi nodes included; the seven guests sit inside the hypervisors' share and are not counted twice.read-only query of each host, four from the record, 20260921
71 hosts · 185 devicesevery machine running an operating system we operate, including the 21 Pi and cluster nodes, and everything the inventory manages including them: switches, power gear, sensors, shelves.inventory export, 20260920
296 targets · 357 rulesmonitoring targets and alerting rules, none down at capture; every rule names its runbook and who acts on it.live metrics API, 20260921
25.9 / 32.7 °Crack inlet and hot aisle at capture, from 11 sensors; the room's summer ceiling is on the power page.live metrics, 20260921

Who typed the history #

2,069 commits since 20260810, counted 20260921: 1,834 by Rigger, 163 by Bosun, 27 by Claude, 34 by two unattended jobs, and 11 by Christoph. Christoph decided each thing and the agents did most of the typing. That is not the same as operating it, so here is one operation with evidence.

One agent operation, evidenced #

20260920, afternoon. The capture’s audit found that the hypervisor cluster had no scheduled guest backups: the backup server’s housekeeping ran green every night around an empty datastore.

What the agent could change. Bosun, under its written permissions, created the nightly job (all guests except the two test VMs, so a new guest is covered the day it exists), ran it by hand on both nodes, and wrote the monitoring: a rule that pages within an hour if the job ever disappears again.

What needed approval. Nothing in that list; promotion to the deploy branch did, and waited for Christoph.

How it was checked. A real guest restored from the new archive to a scratch machine, booted isolated to a login prompt with its database up, then destroyed. Recorded in the runbook and the audit row the same evening.

How it came to be #

It began as a laptop doing everything. An agent machine followed, because work that has to keep running cannot live on a machine that closes and travels. An all-flash storage box became the hub, and the only copy of years of documents and photos, which was named as the risk it was. Then, in a little over a month, the site went from a flat consumer network to what this page describes. The longer arc, from the first hardware in March 2024 through the period when Node0 was hardware much like the seed’s, is the build log .

datewhat
20240320The first hardware purchased: servers, switches, storage. It waited.
20251227 to 20251231Five days of building: the storage hub, the first DI servers, the network gets a name.
20260630Online: the racks powered and running.
20260810The repository that now holds everything opens with Rigger’s first commits.
20260818 to 20260820A firewall pair on a routed public block, cut over after a two-day diagnosis of the provider’s edge. The switch fabric goes live: three pairs, twenty-two VLANs.
20260828Every host migrated onto its VLAN in one day.
20260902 to 20260903A Ceph cluster of nine used Supermicro servers bootstrapped from bare metal in a day and a half.
20260904A new storage hub, with thirty-eight containers moved onto it in one day.
20260906A single day in which four separate failures went unnoticed. The monitoring stack is built in phases from that day.
20260910 to 20260913Five GPU hosts behind one model gateway; a four-node hypervisor cluster; a secrets vault.
20260913Production-ready for development, incubation and pre-production: built, monitored, backed up, documented. Guest-disk backups were found missing and closed on 20260920; the power-outage rehearsal is still pending.
20260917Bosun, an agent, moved in-fabric to watch it all.
20260920This capture.
20260922Shared and made public, so others can benefit and build their own.

What runs on it, day to day #

The site exists for the work that runs on it. Each flow below gets its own page as it is documented, with the one constraint that shaped it; together they are the data the business agents can reference, which is why each one is worth the setup.

Running local AI models. Every agent and process asks one gateway address; behind it, models loaded on demand on the GPU hosts and the two laptops, with hosted vendors in the same list for what local cannot do yet. Detail below. 7 GPUs + 2 laptops · 1 gateway · keys per consumer.

Documents. Every paper that arrives is scanned, OCR’d, tagged and searchable; the agents answer questions against it. 18,791 documents · auto-tagging.

Photos and video. A lifetime of photographs and footage, referenced in place, faces and places indexed, backed up under the same rules as everything else. It is the archive that content creation and the production studio draw from. 105,873 photos · 21,284 videos, on 20260921.

Finance, for a holding company and the companies under it. Every account, card and payment processor feeds one ledger on its own host. The morning question, where do we stand in each company and across them, is answered from a dashboard rather than a login tour. Books per entity, rebuilt from statements, close on their own numbers. The agents answer against the ledger. One rule a business owner will recognise: the site’s monitoring may know the books are fresh, never what is in them. 1 host · several entities · fresh daily.

Code and deployment. The forge, the runners, the deploy branch: every NixOS host converges to one branch; the storage hub and the firewalls are configured by hand and backed up by script. 36 repositories · 4 runners.

The rooms. Temperature, humidity, door and leak sensors, smart outlets and the thermostat for the server and network rooms, through one hub that survives the storage box: monitoring for Node0 today, and the basis for its automations later. 11 sensors · 1 hub.

Running models locally #

One gateway address, and behind it every model the site can serve, with hosted models as further entries in the same list.

The gateway. LiteLLM on a guest of the hypervisor cluster, so it fails over with the cluster rather than dying with one box; we design single points of failure out wherever the layer allows. One address for every agent and process, a key per consumer, spend and latency metered, thinking and tool-use options normalised across backends.

The backends. llama-swap on each GPU host loads and unloads models on demand from a shared archive; two laptops serve as full-time backends; hosted vendors sit in the same list for what local cannot do yet.

What it enables. An agent chooses local or hosted per task by policy, not habit. A key can be limited to local backends, so a workflow that must not leave the site is held by the gateway rather than by good intentions. The bill is one number a day. A new model is a registry entry, not a project.

The compute page carries the client profiles, the placement rules, the model archive, and the traps (a gateway that is up and a backend that is not look identical from outside).

What is shared, and why #

The reason is simple. We want many others to deploy a Node of their own, so we share as much as we can without compromising the security of this one. Selected documentation and reusable tools are published from the private site through a boundary. The public repository holds everything on these pages, the figures they are drawn from, the drawings’ data files, and the tools that made them. The private repository holds the site itself.

Public. The seed, this capture, the lessons, and the reusable tools with generic names, at github.com/oznog-holdings/node0-public (a mirror of the site’s own forge). Each tool page says input, output, and what it needs. The publication gate refuses addresses outside documentation ranges, credential shapes, credential-store names, and images that still carry metadata. Writing, diagrams, photographs and the figures file are CC BY 4.0; the tools are MIT. Both ask only for attribution.

Private, on the site. The configuration that rebuilds every box, the runbooks, the inventory, the credentials’ locations. Everything public is derived from it through a checklist, never edited in place, and every page names the checklist version it passed. Never mirrored.

Why we chose it #

The technologies, named and linked, and the reason each one is here. We chose open source wherever it could carry the job, because software we can read, run and rebuild is the only kind that fits a sovereign site; the two exceptions, Unraid and the Arista switches, are named below with their reasons. Someone replicating this can take the same choices or their commercial equivalents, on their own values, capabilities and needs. We are grateful to every one of these projects and the people behind them; this site is built on their work. Please support them if you are able to. Then the decision ledger: what was decided, when, and the layer page that carries the long form with its trade-offs.

NetBox . The inventory as source of truth: every device, cable, address and VLAN, and the monitoring targets are discovered from it. At 71 hosts and 185 devices a spreadsheet stops being honest, and it stopped well before that.

NixOS . Every NixOS host, 29 of the 71, is one file in one repository; a dead one comes back from git, and a new one is the same file with a different role. The Macs, the Debian Pis and the storage hub are managed by hand and backed up by script. The agents are fluent in NixOS.

Forgejo . The site’s own git forge and CI runners, because the repository that rebuilds every box should not live on a service that can change its terms.

OpenBao . A three-node secrets vault, so a machine can fetch what it needs without a human ever having pasted it.

OPNsense . Two firewalls with failover over the WAN, on a routed public block; rules that can be read, backed up and monitored.

Arista . Used data-centre switches in three pairs, because a host should survive a switch, and because the fabric is where a provider diagnosis, a VLAN and a bond can all be read from one console. The other exception: proprietary hardware, chosen used because EOS is documented in depth and the agents know it well, so a switch is something they can read, diagnose and change with the same fluency as a Linux host.

OpenWrt . The one access point inside the site, an OpenWrt One run as a dumb AP: no DHCP, no DNS and no routing of its own, each SSID mapped to a segment on a trunk, so a wireless client lands where its trust puts it and the fabric and firewalls decide the rest. Chosen because its configuration is a file we can read, version and restore, and because lesson 4.6 records what a default access point does to a network until it is told otherwise.

Headscale and Tailscale . Remote access as a WireGuard mesh, with the coordination server run on the site itself, so that who may reach what is decided here and not by a hosted control plane; the site’s subnets are routed by both firewalls independently, after the outage in lesson 4.13.

Technitium . Authoritative DNS as a three-member cluster with zone transfers, after the simple resolver stopped being enough. The deployed primary is still a container on the storage hub, with the two small always-on boxes as secondaries; moving the primary to the box that never reboots is the design the bootstrap page argues for and the seed follows.

Caddy . Both reverse proxies, public and internal, and so every name the site answers to: one configuration in git, certificates renewed by DNS challenge without a hand touching them, and a configuration a person can read in one sitting. Every service depends on it, which is why it is on this list and not the services page.

ZFS . Checksums, snapshots and send-and-receive, which is the whole replication and consistent-backup story.

Unraid . The storage hub: ZFS pools with a UI, containers and VMs on one box, and a control surface a person can run before there is a repo. The classic mixed-drive array is not why it is here; ZFS is. It is licensed software, one of the two exceptions, kept because the hub predates the repo and a person can operate it without one.

Ceph . Storage that survives a whole host, grows by adding a host, and gives the hypervisors and the model archive one place to live. Proven in a lab first.

restic , Backrest , Proxmox Backup Server . File-level backups to an append-only bucket and a rest-server, and disk-level guest backups, with the rule that a destination never holds a backup that came from itself.

Proxmox . The hypervisor cluster, using Ceph as an external client rather than hyperconverged, so storage and compute fail separately.

LiteLLM and llama-swap . One gateway address for every model, local or hosted, metered per key; models loaded on demand on each GPU host from a shared archive.

Prometheus , Grafana , Loki , ntfy . Metrics, dashboards as generated code, logs, and notifications that leave through a box other than the one being watched.

herdr . The fleet session manager the agents live in: one sidebar across every agent and development host, with each remote session mirrored in and controllable from the operator’s own machine, and the session state carried on the host so a session survives the laptop that opened it closing. It is the piece that makes a fleet of agent machines feel like one desk, and it is pinned to one version fleet-wide because the agents depend on it staying still.

Matrix on tuwunel . The site’s own chat: people and agents in the same rooms, on a server we run, over an open federated protocol, so the running record of how the site is operated belongs to the site and can reach other sites without a hosted intermediary. tuwunel because it is one Rust binary a small site can run and back up as one more database, and it is the maintained successor to the homeserver it replaced.

Two services outside the building carry the parts of the design that must not be inside it, both chosen for their reputation, their reliability and their values, which line up with ours, and both named here with thanks. Backblaze B2 holds the offsite bucket: the small irreplaceable tier, written nightly under a rule that hides rather than deletes, so a stolen writer key cannot take the history with it. Hetzner rents the one machine off the property, the outside-in vantage point that scans the site’s public surface with no credential to it, in a datacentre in Germany.

The choices that belong to one service rather than to the site, the document, photo, media, finance, automation and home stacks, are listed the same way, with links and reasons, on the services page .

The decision ledger #

datedecisionlong form
20260815The first NixOS host, to prove an agent can operate NixOS without imperative drift. Every new x86 box after it is NixOS.operations
20260816Ceph proven in a lab (failure domains, disk replacement, total power loss, upgrade) before any production disk.storage
20260816CI/CD: a runner validates every push, hosts converge to a deploy branch, promotion is one push.operations
20260817Fabric: management on its own VLAN; switch pairs in-rack, not across racks; every host bonds to a pair.fabric
20260817DNS moves from a simple resolver to an authoritative server with three members, the second on a small always-on box the same day.bootstrap
20260820The provider rebuilds the circuit as a transparent LAN service; firewall failover over the WAN becomes the production design.edge
20260821Everything moves off the first hub to a new one; the first takes a lighter second role and leaves the site in 2027.storage
20260824PDU and ATS management stays on an isolated VLAN with per-card rules; the boundary is the VLAN, not the transport.power
20260901The hypervisor cluster uses Ceph as an external client, not hyperconverged.compute
20260903Label everything, front and back, both ends of every cable, before a box goes in a rack.site
20260904UPS low-battery raised to fifteen minutes and made the sole shutdown trigger; storage and hypervisors shut down and return as one unit.power
20260905If rotating a credential requires editing the repository, the design is wrong. Enforced in CI.operations
20260905A destination never holds a backup that originated from itself. Enforced in code.storage
20260906Notifications leave through a box that is not the one being watched, on their own public address, with per-host write-only tokens.observability
20260906The inventory system goes live as the fleet’s single source of truth: every device, cable, address and VLAN, with monitoring targets discovered from it. At this scale it stopped being optional.site
20260909Rack 2 accepted at 103% of one UPS on failover, by decision, with the arithmetic recorded.power

State at capture: running, and unresolved #

Running is what the pages above describe. Unresolved is the list Christoph set on 20260920 as the remaining distance; the next capture is taken when the last box is ticked, not by editing this one. Closed on the capture day itself, and marked so above: the hypervisor guest backups. Closed since, on 20260922: Bosun on the in-fabric agent host, watching every notification and managing the site; its move to internal models waits on the last item below.

  • The OpenBao secrets vault: full deployment, the security sweep and clean-up.
  • Firewall rules tightened to actual need without becoming restrictive.
  • Fuller deployment and use of the internal AI models.
  • Power-outage configuration: power-on return, the walk-in and the return order, tested by causing the condition.
  • Spare hardware and parts inventory.
  • Current RMAs processed and received.
  • A second wallboard, and the display on top of rack 1; racks 2 and 3 have theirs.
  • The hypervisors moved to on-board SATA; the RAID cards removed.
  • Additional smart outlets: the network room’s air conditioner, two server room fans.
  • Monitoring refinements over the next few weeks.

Beyond the list, the four things that would change what the site is rather than finish it, none of them scheduled: more GPU compute, staged in as the work demands it, into rack space and power already waiting; a whole-site generator, so an outage becomes a fuel question rather than a battery one; a second provider with BGP over the site’s own address space, so one line and one provider stop being the single points of failure the landing page admits to; and the 34,000 BTU mini-split the power page prices, dedicated cooling for the server room, which the GPU growth would bring forward.

Still to come on these pages: the bill of materials by layer with replacement costs, researched before publication.

Source: node0 as-built v0.1, sections 1, 2, 4 and 8. Sanitized: checklist v0.1, 20260921; voice pass 20260921. Capture of 20260920; the private site keeps changing, this page does not. Part of oznog.com/node0.