Skip to content
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
14 changes: 10 additions & 4 deletions README.md
Original file line number Diff line number Diff line change
Expand Up @@ -81,7 +81,7 @@ documents for different readers.
the Makefile, the scripts, the workflow and the runbooks resolves its image
from `compose.yaml` too, so an image that is not pinned there cannot be run
at all.
- **Documented decisions and runbooks.** 33 ADRs covering what was chosen
- **Documented decisions and runbooks.** 34 ADRs covering what was chosen
and what was rejected — including the costs accepted knowingly; 20
runbooks for the operations that are easy to get wrong at 1am, one of which
is the handover page a successor reads first.
Expand Down Expand Up @@ -325,16 +325,22 @@ Open work is tracked in
[`docs/roadmap.md`](docs/roadmap.md) is the narrative — what is outstanding and
why it is in that order.

The current top items: rack the shelf switch, and buy the spare ProDesk that
turns the firewall's restore runbook from a hypothesis into something rehearsed.
The current top items: rack the shelf switch, rehearse the firewall restore on
the ProDesk bought on 2026-09-08, and then build the sensitive tier on that same
box ([#404](https://github.com/Gerrrt/HomeLab/issues/404), [ADR-0034](adr/0034-run-the-sensitive-tier-on-the-prodesk-and-make-it-the-spare-hardware.md)). **Every purchase still outstanding, in one place:** a
second drive for that box sized to the photo library, and the NAS
([#95](https://github.com/Gerrrt/HomeLab/issues/95)). A dedicated firewall
spare is deferred, not on the list. This sentence used to name three purchases
coupled to the UPS work and omit the tier's host entirely, which is how one
ProDesk came to be bought for two jobs.
The UPS is finished — a pack went into `mjolnir` on 2026-08-28, passed its
self-test, and the card is set to test itself every fortnight
([#93](https://github.com/Gerrrt/HomeLab/issues/93)) — but the switch between
the monitoring host and the network still has no battery at all, so both laptops
stay running and go deaf on a mains cut
([#110](https://github.com/Gerrrt/HomeLab/issues/110), reopened on 2026-09-08
after a commit message had closed it by accident); and the config export
itself now leaves the monitoring host nightly, so the spare is what is left
itself now leaves the monitoring host nightly, so the rehearsal is what is left
([#92](https://github.com/Gerrrt/HomeLab/issues/92)).

## License
Expand Down
Original file line number Diff line number Diff line change
@@ -0,0 +1,114 @@
# ADR-0034: Run the sensitive tier on the ProDesk, and make it the spare hardware

**Status:** Accepted · 2026-09

## Context

[ADR-0008](0008-place-services-by-data-trust.md) put the sensitive tier —
Vaultwarden, Immich, Paperless-ngx, Home Assistant, behind Caddy and step-ca,
with AdGuard Home, ntfy and Homepage alongside — on a mini PC on Winterfell,
and said in its consequences: *"New hardware is required … Two purchases where
the plan originally assumed zero."* Separately,
[#92](https://github.com/Gerrrt/HomeLab/issues/92) asked for a cold spare for
the firewall: the same ProDesk 600 G4 model as `morpheus`, so a pfSense restore
goes straight through, racked on a shelf and **left powered off** so that a
spare on the network is not exposed to whatever took the primary.

Those are two machines. Only one of them was ever on the shopping list.
`README.md`'s "current top items" sentence named the UPS pack, the shelf
switch and the spare ProDesk, and every session that answered "what should I
buy" answered from it. The tier's host lived in ADR-0008's consequences and,
from 2026-09-04, in one roadmap paragraph;
[#102](https://github.com/Gerrrt/HomeLab/issues/102) closed that day by
splitting into one issue per service, and the box itself got none. No spec
was ever written beyond "low-power mini PC" and, twice in passing,
"N100-class".

On 2026-09-08 one ProDesk 600 G4 was bought — i5-8500T, 32 GB, 512 GB SSD —
as the spare, because that was the only ProDesk anyone had been told to buy,
and in the belief that it would also host the tier. This ADR decides what it
is for, rather than treating a second purchase as the default.

**What the tier's workload actually is**, read from its issues rather than
from the phrase "low-power": Immich's machine learning is the most
memory-hungry thing that will run in the estate
([#132](https://github.com/Gerrrt/HomeLab/issues/132)); Paperless OCR takes
every core it is given for minutes at a time
([#133](https://github.com/Gerrrt/HomeLab/issues/133)); Postgres with the
vector extension, Redis and Home Assistant sit beside them; and seven more
services have been proposed for the same box since. Six cores and 32 GB fit
that. Four cores and 16 GB, which is what "N100-class" means in practice, is
the box on which #132 already expects to disable the machine learning on day
one.

**What the cold spare actually protects against.** A dead `morpheus`, restored
in twenty minutes at 1am rather than in an hour. The config it would restore
is exported nightly, encrypted, verified and copied to `oracle`
([ADR-0015](0015-give-oracle-the-off-host-jobs.md)); the restore path exists
without the spare, onto any hardware, with an interface-assignment dialogue in
it. And the drill that #92 exists for — proving the runbook is not a
hypothesis — needs the box on a bench once, not in a drawer for a year.

## Decision

**The ProDesk bought on 2026-09-08 is the sensitive tier's host.** It is
rehearsed on first, as the firewall spare, and it is the firewall's spare
hardware for as long as there is no other.

1. **Rehearse the firewall restore on it before it holds anything.**
[`restore-the-firewall.md`](../runbooks/restore-the-firewall.md)'s bench
procedure, on this box, closes the rehearsal half of #92 on exactly the
hardware that would be the spare in a disaster. That is a better-tested
restore path than a powered-off box nobody has booted.
2. **Then wipe it and build the tier**, under
[#404](https://github.com/Gerrrt/HomeLab/issues/404), which is the tracker
the host lost when #102 split. The order there is the one
[ADR-0022](0022-expire-the-sso-deferral-when-the-tier-holds-real-data.md)
and [ADR-0023](0023-keep-the-household-recovery-path-outside-the-estate.md)
require: disk encryption decided, the stack built empty, the off-estate
copy proven, TOTP enrolled, and only then the first real photo.
3. **In a disaster the tier box is the spare hardware.** If `morpheus` dies,
the tier box is wiped and the newest export restored onto it — same model,
so the interface names match and the restore goes straight through. The
tier is down until a replacement ProDesk arrives. ADR-0023 already says one
mini PC cannot be made highly available and nothing the household needs in
an emergency may run through it, so "the tier is allowed to be down" is a
property this estate has already accepted, not a new one.
4. **The cold spare is deferred, not rejected.** #92's objection to a
powered-on spare — a box holding the firewall's config, reachable on the
network — does not apply to a box running Immich. What is given up is the
twenty-minute restore. A dedicated spare is bought when the tier holding
real data makes an hour of firewall downtime, and the household services
down with it, unacceptable; that is a judgement to make then, with the data
in hand, not now.

The 512 GB disk is enough for everything on the tier except the photo library.
The G4 has a free bay; a second drive is sized when the library's size is
known, under #404, and is the only purchase this decision leaves outstanding
for the host.

## Consequences

- **One box does two jobs, and the second job destroys the first.** A firewall
restore onto this box is a wipe of the tier. That is the whole trade, and it
is written into `restore-the-firewall.md`'s *Afterwards* section: order a
replacement ProDesk the same day, because until it arrives the estate has no
password manager, no photo library and no Home Assistant.
- **#92 narrows to the rehearsal.** The purchase half is done by this box; the
"racked on the shelf, powered off" half is withdrawn.
[`fit-the-ups-battery.md`](../runbooks/fit-the-ups-battery.md) step 2, item
4 no longer applies; the shelf carries the switch and nothing else until
#404 decides where the host lives — which is also where
[#134](https://github.com/Gerrrt/HomeLab/issues/134)'s USB radio question
is answered, since a rack in a closet is a poor place for one.
- **The shopping sentence in `README.md` names every outstanding purchase**,
not the three coupled to the UPS work. A sentence that answers "what should
I buy" and omits a machine is how this decision came to be needed, and it is
the same defect class [ADR-0026](0026-check-the-documents-where-the-truth-is.md)
describes: prose about what is outstanding that nothing checks.
- **ADR-0008 is not superseded.** Its placement and its "two purchases" hold;
this ADR decides which machine one of them is and defers the other.
- **Reopened by:** the tier holding real data and a firewall failure costing
more than an hour being judged unacceptable — buy the dedicated spare and
restore #92's shelf paragraph; or the tier outgrowing this box, which is a
second tier host and this box becoming the spare after all.
7 changes: 7 additions & 0 deletions docs/hardware.md
Original file line number Diff line number Diff line change
Expand Up @@ -80,6 +80,13 @@ revisions of this repository treated `shiva` as the hypervisor itself.
the unmanaged switch that feeds `prometheus` and `oracle`. It is not in the
rack table above because it is not yet in the rack
([#110](https://github.com/Gerrrt/HomeLab/issues/110))
- HP ProDesk 600 G4 Micro — i5-8500T, 32 GB, 512 GB SSD, the same model as
`morpheus` — ordered 2026-09-08, in transit. The sensitive tier's host and
the firewall's spare hardware in a disaster
([ADR-0034](adr/0034-run-the-sensitive-tier-on-the-prodesk-and-make-it-the-spare-hardware.md)).
It enters the Compute table when
[#404](https://github.com/Gerrrt/HomeLab/issues/404) builds it, after the
firewall restore has been rehearsed on it.
- USB stick holding the pfSense installer — **in transit; it belongs in the rack
beside the KVM once it arrives**, and is not there yet.
[`restore-the-firewall.md`](runbooks/restore-the-firewall.md) lists it as
Expand Down
33 changes: 22 additions & 11 deletions docs/roadmap.md
Original file line number Diff line number Diff line change
Expand Up @@ -318,11 +318,16 @@ what left this one unfireable for months.
converge in one run from any divergence. The far side's login shell is zsh,
where an unmatched glob is fatal rather than literal, so the prune deletes by
explicit basename and sends no pattern over the wire at all.
What remains is the spare — the same ProDesk model, racked on the #110
shelf, powered off — and the rehearsal, which is what turns
What remains is the rehearsal, which is what turns
[`restore-the-firewall.md`](runbooks/restore-the-firewall.md) from a
hypothesis into a runbook; it now carries the bench procedure to follow and
what to record. Writing that procedure found the runbook's own decrypt
what to record. **The box to rehearse on is bought**, 2026-09-08 — the same
ProDesk 600 G4 model, i5-8500T, 32 GB — and [ADR-0034](adr/0034-run-the-sensitive-tier-on-the-prodesk-and-make-it-the-spare-hardware.md)
decides it is not a cold spare on a shelf: it is rehearsed on first, then
wiped and built as the sensitive tier's host ([#404](https://github.com/Gerrrt/HomeLab/issues/404)), and it is the
firewall's spare hardware in a disaster at the cost of the tier being down
until a replacement arrives. The powered-off shelf spare is deferred to the
day that cost is unacceptable. Writing that procedure found the runbook's own decrypt
command had never been run: it passed `--input-type binary`, which sops
rejects on the first byte of a real export, so a restore following the
runbook would have stopped at step one. Fixed, and it is the kind of thing
Expand All @@ -340,8 +345,9 @@ what left this one unfireable for months.
battery at all — the pack in #93 protects the rack, not the monitoring path.
**The shelf is on hand; what is left is the rack visit**, to the spec measured
at the rack on 2026-08-21: 4-post, square holes, full 1U with rear support
rather than a cantilever. The spare ProDesk from
[#92](https://github.com/Gerrrt/HomeLab/issues/92) racks here too, powered off.
rather than a cantilever. The shelf carries the switch and nothing else:
the ProDesk from [#92](https://github.com/Gerrrt/HomeLab/issues/92) is the
sensitive tier's host ([ADR-0034](adr/0034-run-the-sensitive-tier-on-the-prodesk-and-make-it-the-spare-hardware.md)), and [#404](https://github.com/Gerrrt/HomeLab/issues/404) decides where that lives.
**Reopened 2026-09-08.** GitHub had closed the issue on 2026-08-27, when the
commit that wrote the runbook said the switch's power move "is the one that
closes #110" and the phrase was read as a close keyword. Nothing was racked;
Expand All @@ -359,13 +365,17 @@ what left this one unfireable for months.
664. The pages survive a disk failure because Wiki.js syncs from the
Lemmiwinks repository; the accounts, history and configuration do not.
- **[#102](https://github.com/Gerrrt/HomeLab/issues/102) Build ADR-0008's
sensitive tier on VLAN 99.** A low-power mini PC running Vaultwarden, Immich,
sensitive tier on VLAN 99.** One box running Vaultwarden, Immich,
Paperless-ngx and Home Assistant behind Caddy and step-ca, with AdGuard Home,
ntfy and Homepage alongside. Nothing is bought and nothing is built. The
placement is not the outstanding part — ADR-0008 settled it, and
ntfy and Homepage alongside. **The box is bought and nothing is built.** It
is the ProDesk 600 G4 of 2026-09-08, by [ADR-0034](adr/0034-run-the-sensitive-tier-on-the-prodesk-and-make-it-the-spare-hardware.md)
— the one purchase this tier needed, made under #92's name because the
tier's host had no issue and no place in the shopping sentence after this
issue split; [#404](https://github.com/Gerrrt/HomeLab/issues/404) is the tracker it lost. The placement is not the
outstanding part — ADR-0008 settled it, and
[ADR-0010](adr/0010-keep-the-resolver-on-the-gateway.md) has since been
decided on top of it. What is outstanding is a purchase, a stack, and four
firewall rules the ADR counted as two.
decided on top of it. What is outstanding is the build under #404, a stack,
and four firewall rules the ADR counted as two.

**ADR-0010 costs more to implement than it reads, measured 2026-09-04.**
Unbound on `morpheus` is recursive and DNSSEC-validating with zero
Expand Down Expand Up @@ -609,7 +619,8 @@ with nothing tracking it is indistinguishable from a rejected one after six
months.

- **[#102](https://github.com/Gerrrt/HomeLab/issues/102)** ADR-0008's sensitive
tier — the mini PC, its nine services and the four firewall rules. Under
tier — its host (#404, the ProDesk of ADR-0034), its nine services and the
four firewall rules. Under
**Infrastructure** above, because it has a shape now rather than only a
decision.
- **[#103](https://github.com/Gerrrt/HomeLab/issues/103)** The SSO deferral
Expand Down
9 changes: 5 additions & 4 deletions docs/runbooks/fit-the-ups-battery.md
Original file line number Diff line number Diff line change
Expand Up @@ -146,10 +146,11 @@ the cases that genuinely need the wire, and reads the credential from SOPS.
closes #110. A switch that has been relocated onto a shelf but left on a wall
socket is tidier and no better protected — the laptops still go deaf on a
mains cut.
4. **Rack the cold-spare ProDesk from
[#92](https://github.com/Gerrrt/HomeLab/issues/92) beside it**, cabled for
its cold-spare role and **left powered off**. A spare that is plugged in and
on the network is exposed to whatever took the primary.
4. **Nothing else racks here.** This step used to rack the cold-spare ProDesk
from [#92](https://github.com/Gerrrt/HomeLab/issues/92) beside the switch,
powered off; [ADR-0034](../adr/0034-run-the-sensitive-tier-on-the-prodesk-and-make-it-the-spare-hardware.md)
makes that box the sensitive tier's host instead, and
[#404](https://github.com/Gerrrt/HomeLab/issues/404) decides where it lives.
5. **Fit the APCRBC115 pack** last, per the Smart-UPS front-bezel procedure, and
confirm the card comes back with the battery-replacement date reset.

Expand Down
29 changes: 21 additions & 8 deletions docs/runbooks/restore-the-firewall.md
Original file line number Diff line number Diff line change
Expand Up @@ -171,6 +171,14 @@ different hardware drops you into the interface-assignment dialogue at the
console, at whatever hour this is happening. `morpheus` also uses a USB NIC for
the switch-management LAN, so the spare needs one too.

**The spare is the sensitive tier's host**, by
[ADR-0034](../adr/0034-run-the-sensitive-tier-on-the-prodesk-and-make-it-the-spare-hardware.md):
the same model, running Immich and the rest. Step 0 is therefore wiping it,
and everything on it is gone until a replacement ProDesk arrives — order one
the same day (§5). The rehearsal below is done on this box before it holds
anything ([#404](https://github.com/Gerrrt/HomeLab/issues/404), step 1); until
it has been, this section is still a hypothesis.

1. Install the same pfSense version the backup came from. **Restoring a config
onto an older build can fail silently**; check the `<version>` field, which
`make backup-firewall` prints on every verify.
Expand Down Expand Up @@ -264,8 +272,12 @@ And once the denials are verified, verify the thing that watches them.
## 5. Afterwards

- Take a fresh backup from the restored box — the old one is now historical.
- If a spare was consumed, order another. A spare used once and not replaced is
a spare you no longer have.
- If the spare was consumed, order another ProDesk the same day. Since ADR-0034
the spare is the sensitive tier's host, so consuming it took the password
manager, the photo library and Home Assistant down with the firewall, and
they stay down until the replacement is built. A spare used once and not
replaced is a spare you no longer have — and here it is also a tier you no
longer have.
- Record what happened in [`roadmap.md`](../roadmap.md) if the cause is
something the design should prevent.

Expand Down Expand Up @@ -314,9 +326,10 @@ and to write the answers back into §3.
power-on to verified, and everything that asked a question. Put it in
[`roadmap.md`](../roadmap.md) under #92, fix §3, and delete the hypothesis
sentence above.
6. Shred the plaintext, power the spare off, and rack it on the U4 shelf
([#110](https://github.com/Gerrrt/HomeLab/issues/110)) beside the switch —
**off**. A restored spare on the shelf turns §3 into "move the cables and
power on", at the cost of carrying a config that ages from the day it was
restored; on the day, still restore the newest export from `oracle` over it
before trusting it.
6. Shred the plaintext and hand the box to
[#404](https://github.com/Gerrrt/HomeLab/issues/404): it is wiped and built
as the sensitive tier's host (ADR-0034). Nothing on it survives the
rehearsal, which is why the rehearsal comes first. The powered-off shelf
spare that used to be this step is deferred by that ADR; if it is ever
bought, it racks on the U4 shelf beside the switch, **off**, and on the day
the newest export from `oracle` is still restored over whatever it carries.