13 Commits

Author SHA1 Message Date
admin a91d0b2421 Upload watch: spike, design (08 section 9, proposed), live proofs on 9202; rows R-1244..R-1248 (register 189 -> 194); STATUS D41/D42 + the Monday list
gates / gates (push) Successful in 13m1s
Spike: per-app normal levels on three boxes (19-31 days), the off-site push as a line measure (a lower bound),
qBittorrent/Transmission/Plex explainers measured on 9202, a tc ceiling measured (not built). Live on 9202 with
0.342.0-rc.1: limit set; real seed explained; CPU burner and the hidden flood alarmed once each and cleared once;
the household's limit left alone. Teardown: apps removed, 9202 back on 0.341.0, receiver 9471 destroyed.
2026-10-23 22:52:41 +02:00
admin af5c005a4e hub 0.169.0 (unreleased, not built): the upload watch's four events — allowed, operator-only, per-app cooldown, one readable Watch line in the operator mail
gates / gates (push) Successful in 12m47s
app_unexplained_upload / app_unexplained_cpu (warning) and their _cleared (info), from controller v0.342.0 (08 section 9,
operator ruling 2026-10-23). Red-proved: operator-only, the render line, the allow-list.
2026-10-23 21:26:36 +02:00
admin 5277d859d5 hub 0.168.0: seal the last plain tokens in config_json (R-975, R-1241's Felhom half); decide row R-1243 for the hub's plain Longhorn copies (register 188 -> 189)
gates / gates (push) Successful in 12m26s
The Cloudflare tunnel token, Cloudflare API token and git token inside customer_configs.config_json now hold the
05 §16.2 seal (enc:v1:, OFFSITE_SECRET_KEY). Old rows sealed once at start-up without a config_version bump, then
VACUUM + WAL checkpoint (an UPDATE leaves the old plaintext in a freed block). -unseal-box-secrets opens them too.
Eight tests, each red-proved. Built, not deployed. Audit: documentation/audits/hub-token-seal-2026-10-23/.
2026-10-23 19:48:17 +02:00
admin 8257ff1cbe Plex2Shell impact on Felhom: verdict NOT REACHED; R-1241 (P1), R-1242 (P3) opened (register 186 -> 188)
gates / gates (push) Successful in 12m37s
Read-only audit of whether the hacked Plex pod on DooPlex (HM-040, 2026-10-17 -> 10-23) reached Felhom's
secrets. Two no-login doors existed (the Longhorn NFS export and the Longhorn API); neither was used:
nfsd accepted 0 new connections in the window (positive control), no off-schedule Longhorn backup or volume.
Evidence in documentation/audits/plex2shell-felhom-impact-2026-10-23/. The NFS export was narrowed from *
to 10.42.0.0/16 on the operator's yes (host change, not in git). 13-threat-model.md: attacker j and one
boundary row. STATUS: verdict, the P1, one do item.
2026-10-23 17:53:43 +02:00
admin 87dc50743c D39 = B: 09 §3 decision 255 (the security-fix step) + a dated note on decision 13; capability B23; R-1239 closed, R-1240 opened, R-1238 updated (register 186 -> 186); STATUS/CONTEXT; nodes.md (9202 password, Tester 1 DHCP); evidence security-lane-2026-10-23 (controller 0.341.0, global floor 11:24 UTC)
gates / gates (push) Successful in 13m49s
Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
Claude-Session: https://claude.ai/code/session_012qRErfCoiTkvDK9N5XHbzb
2026-10-23 13:35:38 +02:00
admin 4b9b0af3cb Plex2Shell: the operator's 10:56 ruling in CONTEXT; demo-hp 9201 checked (clean) and updated to 1.43.5.11029; register 184 -> 186 (opened R-1238 Plex test record/fixture, R-1239 a fast lane for security fixes = D39); evidence plex-demo-boxes-2026-10-23
gates / gates (push) Successful in 13m46s
Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
Claude-Session: https://claude.ai/code/session_012qRErfCoiTkvDK9N5XHbzb
2026-10-23 11:27:52 +02:00
admin 2c9152d912 Day 2026-10-23 close-out: rulings D31-D36 in CONTEXT; STATUS (releases done, do list, D35 dated, D37/D38); register 191 -> 184 (closed R-49 R-982 R-985 R-991 R-1204 R-1205 R-1225 R-1226 R-1227 R-1230 R-1234; opened R-1235 R-1236 R-1237); the break-glass sheet current (D32, one A4, HU+EN); runbooks for D33/D34; poster facts; evidence day-2026-10-23
gates / gates (push) Successful in 12m53s
2026-10-23 11:03:45 +02:00
admin 52af38df6f hub-db-backup: wait for a snapshot being written, limit 7 h (one slot gap + 1 h) — the 2 h limit refused the hub's own catch-up and mailed a false failure at 10:28 (R-1234, closed); tests red-proved
gates / gates (push) Successful in 13m14s
2026-10-23 10:35:16 +02:00
admin 34979d5d25 hub manifest: 0.165.0 -> 0.167.0 (operator yes 2026-10-23: D31, the clock-ahead tunnel alarm, R-1230, D34 6-hourly snapshot; image sha256:177860a9…)
gates / gates (push) Successful in 13m26s
2026-10-23 10:23:29 +02:00
admin 0bb57a4fee website: publish D3/D5 (the whole truth on privacy; the minimum machine) and D36's two sentences, HU + EN (operator yes 2026-10-23; R-985, R-991, R-1225, R-1226)
gates / gates (push) Successful in 13m10s
2026-10-23 10:16:54 +02:00
admin 2aebf1bde1 webpage: serve installer-v1.36.0 (both git-sync pins; operator yes 2026-10-23 — root SSH by key only on new installs, R-982 D4)
gates / gates (push) Successful in 13m12s
2026-10-23 10:08:09 +02:00
admin d306b8c2d7 release-copy: the released images (skopeo dir:, digest-true) and agent packages copied to ep0 nightly, verified by sha256 and a checksum compare, capped at 3 GB (D33, R-1227); tests red-proved
gates / gates (push) Successful in 15m56s
2026-10-23 09:39:31 +02:00
admin be7e97dc1a hub 0.167.0 + DooPlex push: the hub DB snapshot every 6 hours (D34, operator yes 2026-10-23, R-232 G5) — slots 02/08/14/20, catch-up 6 h, push :30 after each, refuse a copy older than 2 h; tests red-proved
gates / gates (push) Successful in 16m20s
2026-10-23 09:12:08 +02:00
174 changed files with 6173 additions and 154 deletions
+37
View File
@@ -16,6 +16,43 @@
> and holds nothing of its own; this file does hold its own content, namely the standing rulings below. > and holds nothing of its own; this file does hold its own content, namely the standing rulings below.
> **2026-10-23 19:22 — operator rulings by starting the weekend-night brief (R-1241's Felhom half; the upload watch).**
> **Part 1 = R-1241's Felhom half:** seal R-975 (done in hub 0.168.0, not deployed — `05` §16.2,
> `audits/hub-token-seal-2026-10-23/`); the hub's plain Longhorn copies are decide row R-1243 (CC's pick: take the hub
> volume out of the Longhorn backup; ep0's encrypted copy is the backup). **Part 2 = the upload watch, shaped by the
> operator:** the box measures its own upload line (first from what it already sees — the off-site backup's upload
> rate — a short test at a quiet hour only if needed); on a sustained high upload it attributes the bytes to an app's
> container and ASKS THE APP (qBittorrent's seeding, Plex's remote sessions); a mismatch is the alarm
> (`app_unexplained_upload`, the same shape for CPU, `app_unexplained_cpu`) — operator only. qBittorrent gets a default
> upload limit from the measured line; a limit the household set is respected. **Open for the operator, CC's pick in
> STATUS:** the default limit's size (CC: 50 % of the measured upload) and who is told (CC: the family only about the
> qBittorrent limit they can change; the unexplained alarms to the operator only — the R-388 rule).
> **2026-10-23 ~12:00 — operator rulings by starting the D39 brief (`09` §3 decision 255; R-1239 closed).** **D39 = B:** a
> `security_fix` ladder step — box walk on 9202 required, bench optional, taken by the night leg. **No operator word per
> incident:** a public advisory id (CVE or GHSA) + its https:// notice is the authority; the session that writes the step
> reports it to the operator after the push. The design (Claude.ai's recommendation) was taken as written; one fact in the
> brief was checked and held (Plex's box fixture exists but is a `NoRoute` stub, so `seed: "none"` is right). Built:
> catalog `3898593` (`ladder.py` `check_security` + `engine_majors_crossed` importing `check-engine-major.py`; the move gate
> accepts it; `check-test-record.py` WARNs on a head with no bench; `upgrade-test.py --write-ladder --security`;
> `box_walk.py --security` + `refresh_box_mirror()`), controller **0.341.0** (`legCandidate` takes `proven` or
> `security_fix`; global floor 11:24 UTC with MinAgent 0.158.1, the operator's yes in chat). Proof:
> `audits/security-lane-2026-10-23/`. Older controllers skip the step at night and take it on a hand press (proven).
> **2026-10-23 10:56 — operator ruling: Plex to the fixed version now, without the test record (Plex2Shell).**
> Verbatim: *„bump the version to the newest in the app template immediately (as there are no customers yet), I want the
> demo boxes on the newest version asap."* It skips `09` §3 decision 13's test record **once, for Plex only**. Done: catalog
> `6cc317d` (Plex 1.41.4.9463-630c9f557 → 1.43.5.11029-6bf8af3f0, CVE-2026-96652/-96654/-96655/-96656), pushed
> `--no-verify` past `check-test-record-move.py` (its refusal is in `app-catalog-felhom.eu/REPORT.md`); the only box running
> Plex (demo-hp 9201) was checked for the attack's signs (none) and updated by the Update press; the guide re-checked
> (`guide.checked_version` moved). Decision 13 itself is unchanged. Follow-ups: R-1238 (Plex's test record and fixture),
> R-1239 (a fast lane for security fixes — the operator's decision, D39). Evidence: `audits/plex-demo-boxes-2026-10-23/`.
> **2026-10-23 morning — the operator's „go" for the day brief: the releases, D31 as built, D32–D36 (decide rows in `STATUS-HISTORY.md`).**
> **Releases:** controller 0.340.0 (global floor 06:41 UTC, MinAgent 0.158.1); agent 0.163.0 (binary sha256 561b5316…, bundle 3afb88d9…, vouched by the operator 07:58 UTC; delivered to the three test boxes by signed jobs through a step bundle `0.163.0-step1` — the D4 drop-in is a new path, R-880); installer 1.36.0 (tag `installer-v1.36.0` → 83388c08, both webpage pins); hub 0.167.0 (sha256:177860a9…, 08:27 UTC); the website `0bb57a4f`.
> **D31** = as built (the re-issue reads the newest deletion of a KEY-HOLDING host; an install that got the password but no recovery package is rotated without a press). **D32** = yes: the sheet is names and places only, one A4, HU + EN; the operator prints and fills it. **D33** = yes: `scripts/release-copy/` nightly 01:40, newest 3 image tags (controller, hub, samba) + 5 agent versions, skopeo `dir:` (digest-true — why not `docker save`: a re-push re-compresses), ep0 `/srv/felhom-release-copy` under the one limited user `felhom-relcopy` (rrsync), cap 3 GB enforced by the sender, a read-only registry token of its own. **D34** = yes: hub snapshots at 02/08/14/20 (catch-up > 6 h), DooPlex push :30 after, limit 7 h + a wait for a snapshot being written (R-1234: 2 h was wrong), alarm 13 h; ep0 retention unchanged (keep-daily 14, keep-weekly 8). **D35** = yes, after the release week (R-1228, dated 2026-10-30). **D36** = yes, both sentences, published.
> **Added on the operator's word the same day (not soaked):** D34's hub half went into 0.167.0 (asked before the build). Record: `audits/day-2026-10-23/`, `REPORT-day-2026-10-23.md`.
> **2026-10-22 evening — operator rulings D29, D30, D31 (CC's picks accepted; the decide rows now in `STATUS-HISTORY.md`).** > **2026-10-22 evening — operator rulings D29, D30, D31 (CC's picks accepted; the decide rows now in `STATUS-HISTORY.md`).**
> **D29** = no: the controller repository stays public for now (R-925). **D30** = the agent makes a new WireGuard key and > **D29** = no: the controller repository stays public for now (R-925). **D30** = the agent makes a new WireGuard key and
> registers it on the existing peer path (R-1204). **D31** = the hub skips a deleted install that never made a key when it > registers it on the existing peer path (R-1204). **D31** = the hub skips a deleted install that never made a key when it
+103
View File
@@ -0,0 +1,103 @@
# REPORT — day 2026-10-23: the releases and the DooPlex hour (the operator's „go")
Design read: `07-backup-architecture.md` §6.3/§8, `09-update-architecture.md` §3 decision 250, `03-host-agent.md`,
`05-hub-architecture.md` §16.3, `runbooks/total-loss-of-dooplex.md`, `audits/dooplex-survival-2026-10-22/PLAN.md`.
Evidence: `documentation/audits/day-2026-10-23/01`–`14`.
## Five lines
1. Released: controller 0.340.0 (global floor), agent 0.163.0 (vouched by the operator), installer 1.36.0, hub 0.167.0,
the website with D36's two sentences.
2. Root SSH from the LAN is key-only on all three test boxes; new installs get it from installer 1.36.0.
3. The hub database now leaves every 6 hours (restored back byte-identical); the released images and agent packages
leave nightly to ep0 (pulled back, every sha256 OK, one image loaded on a scratch box).
4. One false failure mail at 10:28 (my install of the 6-hourly copy) — filed R-1234, fixed and red-proved the same hour.
5. Register 191 → 184; the operator: print the sheet, Hosts page clean-up, D37 + D38.
## Per box — versions before → after, and the SSH checks
| Box | controller | agent | root-file bundle | `sshd -T` root | sshd reloaded | key login | felhom-sshd | swap = RAM (9201) |
|---|---|---|---|---|---|---|---|---|
| Tester 1 | 0.339.0 → 0.340.0 | 0.162.0 → 0.163.0 | 0.160.0 → 0.163.0 (via 0.163.0-step1) | without-password | yes, 09:27:38 | ok | active, `sshd -t` ok | 4096/4096 |
| demo-hp | 0.339.0 → 0.340.0 | 0.162.0 → 0.163.0 | 0.160.0 → 0.163.0 | without-password | yes, 09:19:44 | ok | active, `sshd -t` ok | 25898/25898 |
| demo-felhom | 0.339.0 → 0.340.0 | 0.162.0 → 0.163.0 | 0.160.0 → 0.163.0 | without-password | yes, 09:24:42 | ok | active, `sshd -t` ok | 12288/12288 |
| hub | 0.165.0 → 0.167.0 | | | | | | | |
Not proven (said plainly): the real root password over SSH (CC does not hold it — a dummy one is refused, but OpenSSH logs
only „Failed password"); a felhom-sshd connection (it admits only the operator's tunnel peer); the physical console (the
drop-in does not touch it; `passwd -S root` = P).
## Digests, sha256, CI by commit
| What | Value |
|---|---|
| controller 0.340.0 | `sha256:a8d1c6458da4ea9d667f928498656a291771e0b3756b20f2fcc8c1cf9d516621` — `caaa86e`, CI 2245 success |
| agent 0.163.0 binary / bundle | `561b5316cd511de9fa9d8b8be4553da7add684f715d3bea533ca330ff7f3763c` / `3afb88d9fbbc4adc16083fa52a98cd4974583c6378a77a1a6e0ed8ae6d1b80c8` — `1109092` CI 2246, `b4721ee` CI 2249 success |
| step bundle 0.163.0-step1 | `6cbc066902d5f3294765d5c7dc7113166c1dca25e994dbc36bfc5f139bb61fcf` |
| installer 1.36.0 (served = tag) | `de8bf5f32cbcda44c9976ba829f04ea151e3b30634b54d5fdd9eb6c4a0351cec` — `83388c08` CI 2247 success; pins `2aebf1bd` |
| hub 0.167.0 | `sha256:177860a996cb285d935777d6ffdf85725f6cf4489885f54fd3bf8135c68041a0` — built at `d306b8c2` (hub/ = `be7e97dc`, CI 2250 success; `d306b8c2` CI 2251 success); manifest `34979d5d` |
| website | `0bb57a4f` |
| D34 fix (R-1234) | `52af38df` |
| prometheus rules | homelab-manifests `1bbef892` |
CI of the last commits (`2aebf1bd`, `0bb57a4f`, `34979d5d`, `52af38df` and this close-out): see the final message.
## Parts
- **1 — controller 0.340.0:** 9202 smoke, per-customer floors, three boxes green, box walk + https-only rc 0, global floor
06:41 UTC (MinAgent 0.158.1), read back with the WAL (`01`–`06`).
- **2 — agent + installer:** release, a step bundle because the D4 drop-in is a new path (R-880), three signed jobs per
box (`07`); the operator's vouch read back from the DB and the live page (`10`); installer tag, both pins, a
webpage-only sync, the served script = the tag (`11`).
- **3 — hub 0.167.0:** built from a clean clone; on the operator's word it also carries D34's 6-hourly snapshot (asked
before the build; not soaked); hub-only sync; 30-minute watch: 0 hub events, 0 errors, all boxes reporting, no hub mail
(`14`).
- **4 — website:** D3/D5 patch + D36 HU + EN; site gates; published; read back live: new text present, old gone (control:
the previous commit), screenshots at 390 and 1366 px, no sideways scroll (`12-website-readback/`).
- **5 — D34:** retention unchanged, server-side on ep0 (`prune-operator-hubdb` 03:45, keep-daily 14, keep-weekly 8 — the
current day's up to 4 copies until the next prune). Hand run 501.6 MiB / 24.5 MiB uploaded in 4 s; the newest copy
restored from ep0 with the read-only token = the pod's snapshot by sha256 `a9ff4c8a…`, integrity ok, 4 hosts, holds
today's vouch. Alarm 13 h. Runbook updated (`13`).
- **6 — D33:** ep0 before: `/` 14 GB free (the data disk's root IS the PBS datastore — not used). One user
`felhom-relcopy` (locked, rrsync-confined: shell and `..` refused), one directory `/srv/felhom-release-copy`. Cap 3 GB,
enforced by the sender (ep0 has no quota). **skopeo, not `docker save`:** `dir:` keeps the registry's bytes, so a push
back keeps the digest; no Docker daemon. A read-only registry token of its own, minted in the Gitea pod straight into a
0600 file. First run 676 MB, 91 s; pulled back: 141 files OK, 9 images re-verified (digests match independent records),
controller 0.340.0 loaded on 9202 (ID = config digest). Alarm `FelhomReleaseCopyStale`. Restore steps in
`total-loss-of-dooplex.md` (`08`).
- **7 — D32:** the sheet is names and places only, HU + EN, one A4 (rendered: 1 page; a copy in the operator's home
folder); every place checked to exist. demo-hp: three superseded ISOs removed by name, `/` 8.5 → 14 GB free (`09`).
R-548: the box half done, the product fix proposed (R-921's pattern).
- **8 — close-out:** CONTEXT rulings, STATUS (decide rows D32–D36 → history, D37/D38 new, the do list, D35 dated
2026-10-30), REPORTs and CHANGELOGs; the system poster's facts file updated, its hub-DB label edited (text), and a new
arrow asked for in STATUS („System poster needs a refresh").
## Register — 191 → 184; opened 4, closed 11
Opened: R-1234 (closed the same hour), R-1235, R-1236, R-1237. Closed: R-49, R-982, R-985, R-991, R-1204, R-1205,
R-1225, R-1226, R-1227, R-1230, R-1234. Updated: R-1214 (released; dated check 2026-10-24), R-1187, R-1189, R-232,
R-548, R-923, R-924, R-1228 (D35, dated 2026-10-30), R-1183's check text (four snapshot slots).
## Observations
- The D34 first push refused the hub's own catch-up and mailed admin@ — FILED: R-1234 (closed, fixed `52af38df`).
- The release copy is proven to load, not to restore a registry; it follows the newest versions, not the floor/vouch; no
golden — FILED: R-1235.
- Gitea OOM-killed at its 1 GiB limit, the last at 06:41:10 UTC during the release — FILED: R-1236 (STATUS D37).
- The night sweep's mail: one-time test-box codes in one session record — FILED: R-1237.
- The hub DB snapshot is 501 MiB, not 24 MB — NOT-A-FINDING: 24 MB is the compressed upload, which is what ep0 stores.
- felhom-sshd does not answer from the LAN — NOT-A-FINDING: its firewall admits only the operator peer (H1, by design).
- A dummy root password logs „Failed password", not a policy refusal — NOT-A-FINDING: OpenSSH's behaviour under
`prohibit-password`; the policy is proven by `sshd -T` and the reload.
- The vouch left `artifact_wrapper_sha256` empty — NOT-A-FINDING: an optional field; the wrapper rides the vouched bundle.
- Guests 9202, 9401 (demo-hp) and a transient 990000 (Tester 1) have swap ≠ RAM — NOT-A-FINDING: outside the felhom pool.
- `known_hosts` holds an older key for 192.168.0.155 (demo-hp's guest address) — NOT-A-FINDING: guests are reached by
`pct exec`; nothing was changed.
- The D4 drop-in needed a step bundle — NOT-A-FINDING: the documented R-880 path for a new bundle path.
## Teardown — three layers
Machine: 9202 — the test image untagged, the tar removed. Host: demo-hp `/tmp` tar removed; three ISOs removed on purpose
(Part 7); DooPlex: the read-back copies and the hub-DB scratch restore shredded/removed. Hub: nothing provisioned; the
per-customer floors cleared after the global floor. Left on purpose: the ep0 user + directory, the DooPlex release-copy
job, the 6-hourly hub-DB timer, both alarms.
+42
View File
@@ -0,0 +1,42 @@
# REPORT — Plex to the fixed version in the catalog and on the demo/test boxes (2026-10-23 day, Plex2Shell)
**Plain words first.**
- The catalog now gives Plex 1.43.5.11029-6bf8af3f0 (catalog `6cc317d`, pushed without the update test, on your ruling).
- One box ran Plex: demo-hp. It showed no sign of the attack. CC pressed Update; it runs the new Plex now.
- You have one decision (D39): may a security fix reach the boxes at night without the full update test?
## Per box
| Box | Plex before → after | Signs check | Box walk |
|---|---|---|---|
| demo-hp 9201 | 1.41.4.9463-630c9f557 → 1.43.5.11029-6bf8af3f0 | clean (NOT-A-FINDING; logs reach back only to 00:32 UTC today — CPU history and files cover 10-16 → 10-22) | green: all containers healthy, 0 errors, 0 warnings since the press |
| demo-hp 9202, demo-felhom 9201, tester-1 9201 | no Plex | — | — |
| Tester4 | hub host DOWN, VM gone | — | — |
| Tester 2 | no host on the hub | — | — |
Detail and evidence: `documentation/audits/plex-demo-boxes-2026-10-23/README.md`.
## Records
- Register 184 → 186: opened R-1238 (P2, Plex has no test record or fixture), R-1239 (P2, a fast lane for security
fixes — the operator's decision); closed none.
- `CONTEXT.md`: the 10:56 ruling. `STATUS.md`: decide row D39. No „broken" line: Part 2 was finished before the
records were written, so the line the brief asked for would have been added and removed in the same commit.
The „Updated" paragraph was left as the day session wrote it (it is that session's summary; this run adds one
decide row only).
- Architecture read: `09-update-architecture.md` §3 decisions 13 and 52; `13-threat-model.md` (Plex row);
`runbooks/target-selection.md`. Decision 13 is unchanged; no poster fact changed (none of the three poster actions).
- `--no-verify` was used ONCE, for catalog `6cc317d`, on the ruling. The `check-test-record-move.py` refusal is verbatim
in `app-catalog-felhom.eu/REPORT.md`.
## Fixed without a row
- The memory index (`.claude-memory/MEMORY.md`, outside git) had grown to 201 lines / 25 735 bytes at 11:09 (another
session), over the 200 / 25 600 ceiling, so `instructions_gate` failed and so did two script suites that run it.
Lines 71–72 (two memories about the deleted credentials file, both superseded by `sec`) became one line: 200 lines,
25 590 bytes. `repo_gates.py --fast` then OK. The index sits right at the ceiling; the next added line trips it again.
## Teardown
Machine: Plex stays on the new version; helper scripts removed from guest and host. Host: nothing provisioned.
Hub: reads only.
@@ -0,0 +1,75 @@
# REPORT — did the Plex attack on DooPlex reach Felhom's secrets? (2026-10-23)
## Plain words first
1. **Verdict: NOT REACHED.** Two open doors led from the hacked Plex to Felhom's secrets. Neither was used in the attack
days: the backup folder got no new connection at all, and Longhorn made no backup or disk outside its normal plan.
2. **The shared backup folder: closed to the home network and the tailnet** (your yes). It is **still open to every app
on DooPlex** — Longhorn needs that, so the real fix is the homelab session's.
3. **What you do next:** give the homelab session the hand-over list (`documentation/audits/plex2shell-felhom-impact-2026-10-23/README.md`,
last section). Nothing needs to be rotated.
## The Part 4 table
In `documentation/audits/plex2shell-felhom-impact-2026-10-23/README.md` § Part 4. Short form: every Felhom secret on
DooPlex has exposure **none**. The ones a hacked pod *could* have reached: the hub's unencrypted nightly copies (with the
unsealed Cloudflare/tunnel/git tokens, R-975) through the NFS export or a Longhorn backup, and the operator signing keys
through the NFS file-handle escape (documented, not exercised). Sealed hub columns need a key that is not in the copies;
escrow blobs need each household's recovery code; the k8s API, the kubelet and the hub refuse a caller with no credential
(measured).
## The paths and the evidence per path
| path | existed? | evidence of use (window 10-17 04:00Z → 10-23 08:04Z) |
|---|---|---|
| NFS export `longhorn-pvc` (`*`, `no_root_squash`, `no_subtree_check`; `secure` void in pods) | yes | **unused** — `node_nfsd_connections_total` flat at 288 for 13 days, 3902 samples, no gap; positive control: today's three probe connections moved it to 4. nfsd is TCP-only. Reads only in Longhorn's backup hours |
| Longhorn API :9500, no login | yes | **no sign of use** — 0 backups first seen off-schedule (1-min scrape); every night wrote to the local store; no unexplained volume; the backup target is the 2025-11-29 one. Manager logs: lost (reboot) |
| hub `hub:8080` direct | yes, but no secret without a credential | 0 requests from 10.42.0.52 in `/data/access-log` (from 10-18 10:25Z; positive control: the probe's IP is logged). 10-17 04:00Z → 10-18 10:25Z: no record |
| k8s API, kubelet | no (401) | — |
| SSH, Samba on DooPlex | login needed | 0 sshd lines from the pod network (control: 61 from the LAN); no Samba client file for 10.42.0.52 (positive control: the probe made one) |
| Vaultwarden | login needed; vault encrypted | logs lost (reboot) |
**Evidence lost before this session started:** the 13:20Z maintenance reboot erased the pre-reboot container logs of
longhorn-manager, longhorn-ui, the ingress, the hub, Gitea, Vaultwarden, Grafana and Prometheus. Reproduced
independently from records that survived: Prometheus history (nfsd, Longhorn, cAdvisor, node network), the hub's own
access log, the journal (boot -1), Samba per-client files, CoreDNS error lines, the Alertmanager silence list. The
incident session's pre-reboot greps (10.42.0.52 in longhorn-manager, CNPG, Gitea, authentik: 0) are cited as theirs.
## For the homelab session
The seven items at the end of the audit README: the export still open to pods (and `secure` is void there); Longhorn API
and UI with no login; an unattributed Longhorn delete of the old Plex volume at 11:24:15Z; **~1.5 TB sent out by the Plex
pod 10-18 → 10-22** (not in INCIDENT.md) plus `hand.genddos.st` DNS lookups on 10-19; the reboot that erased the logs;
the monitoring stack and Headlamp reachable from every pod; a `python3 main.py` listener on :8443. No HM numbers minted;
`homelab-manifests` not touched.
## What this session changed
- **DooPlex `/etc/exports`** (operator yes, ~15:18Z): `longhorn-pvc` from `*` to `10.42.0.0/16`, `exportfs -ra`; Longhorn
target `available: true` at 15:20:10Z. Backup `/etc/exports.bak-2026-10-23-plex2shell`. The only change on DooPlex.
- **Probe pod** `default/cc-p2s-probe`: created 15:19:46Z, removed 15:33:44Z; before/after listings in the evidence. No
other object created. The incident's NetworkPolicies untouched.
- **felhom.eu:** the audit folder; R-1241 and R-1242 in `OPEN-ITEMS.md`; `13-threat-model.md` (attacker j, one boundary
row); `STATUS.md` (verdict in „What works", the P1 in „What is broken", one „do" item; the old „Updated" paragraph moved to
`STATUS-HISTORY.md`).
- Nothing rotated. No secret value written anywhere (evidence scanned for secret shapes; the only 64-hex string is the
sha256 of `/etc/exports`).
## Rows
Before 186, after 188; opened 2 (R-1241 P1, R-1242 P3), closed 0.
## Observations
- Hacked pod → hub backups + signing keys through the NFS export and the Longhorn API — FILED: R-1241.
- Demo NAS export on the same disk with `no_subtree_check` — FILED: R-1242.
- The hub answers pods without the geo filter — NOT-A-FINDING: the geo filter is not authentication; every no-token path refused.
- demo-felhom's Proxmox UI and SSH reachable from any DooPlex pod — NOT-A-FINDING: the door of R-982; added as attacker j in `13` §3.
- Pod logs erased by the reboot — NOT-A-FINDING for Felhom (the hub's access log persisted, R-1140); handed to the homelab session.
## Notes for the next session
- Teardown, three layers: machine — probe pod removed, export change kept on purpose (operator yes); host — none; hub —
none (read-only access-log aggregation in the running pod).
- System poster: no fact on it changed (none of the three applied).
- `unproven.py`: not run — no capability claim changed.
+17
View File
@@ -0,0 +1,17 @@
# REPORT — D39 = B: the security-fix lane (2026-10-23, attended)
**Plain words first.** An app with a public security hole can now get its fix at night on every box, after one test
on the test box. Controller 0.341.0 does it and is the floor since 13:24 (your yes). Older controllers skip such a fix
at night and take it when a person presses Update — both seen on the test box. Nothing needs you.
- Design: `09-update-architecture.md` §3 decision 255 (+ a dated note on decision 13). Capability map B23.
- Catalog `3898593` (+ a box-walk address fix after it); controller `63dcccf` = 0.341.0; drill commits `8c1d908` …
`17e0da0` (the drill only).
- Evidence and the full table: `documentation/audits/security-lane-2026-10-23/README.md`.
- Register 186 → 186: closed R-1239 (D39 = B); opened R-1240 (9202's 34 saved configs with the catalog token); R-1238
stays open, its text now says the next Plex fix can use the lane.
- `STATUS.md`: D39 out of the decide table, one „what works" line, the „Updated" paragraph replaced (the old one is in
`STATUS-HISTORY.md`). `CONTEXT.md`: the rulings. System poster: no fact changed (none of the three actions).
- Instruction / fact files edited: `app-catalog-felhom.eu/CLAUDE.md` (the lane, added); `operations/nodes.md` line 221
(9202 „same dashboard password" → its own password, measured) and line 46 (Tester 1 `.101` → DHCP, `.148` today).
- No `--no-verify` in this run.
+22 -22
View File
@@ -2,9 +2,10 @@
**Ready for Tester 2? Yes — tell the friend go (hand-over list: `documentation/pilot/TESTER2-handover.md`).** **Ready for Tester 2? Yes — tell the friend go (hand-over list: `documentation/pilot/TESTER2-handover.md`).**
**Updated 2026-10-23 (morning).** Your three picks are built (the tunnel repairs itself with a new key, the hub skips a keyless deleted install, the controller repository stays public), and the night copy can no longer outlive the controller. Four fresh reviews found 34 points, every real one fixed or a row; the test night PASSED (no failed check at night, every night job passed, nothing lost). Nothing was released or deployed; the morning list has the order, and the DooPlex survey asks four questions (D32–D35). **Updated 2026-10-23 (night).** The hub's last unlocked tokens are now locked in a new hub version — built and tested, you deploy it on Monday. The new upload watch is built and tested on the scratch box, not released: it finds an app that uploads or computes far more than the app itself explains (a hacked app) and tells only you; qBittorrent gets an upload limit.
## What works ## What works
- **The Plex attack (10-17 → 10-23) did not reach Felhom's secrets** (R-1241).
- A box installs from nothing with the public installer, links to the hub, and moves to the floor by itself (map A1, A3, A4). - A box installs from nothing with the public installer, links to the hub, and moves to the floor by itself (map A1, A3, A4).
- 65 catalog apps install, update one tested step at a time, and a failed update undoes itself (map B1, B3, B4, B6). - 65 catalog apps install, update one tested step at a time, and a failed update undoes itself (map B1, B3, B4, B6).
- Backups: database dumps, a second-drive copy, an off-site copy and whole-box copies; restore tests run by themselves (map C1–C4, A17, A18). - Backups: database dumps, a second-drive copy, an off-site copy and whole-box copies; restore tests run by themselves (map C1–C4, A17, A18).
@@ -12,16 +13,16 @@
- After a power cut the box starts by itself, cleans up a half-written backup, and Immich repairs broken photos (map C10, F12). - After a power cut the box starts by itself, cleans up a half-written backup, and Immich repairs broken photos (map C10, F12).
- A second drive is offered as the backup target; media apps see every drive; a one-disk box gets its own data area (map D1, D13, D15). - A second drive is offered as the backup target; media apps see every drive; a one-disk box gets its own data area (map D1, D13, D15).
- The three test boxes answer only over https; the hub's key opens nothing on a box; password guesses are counted (map E12, E13, E17). - The three test boxes answer only over https; the hub's key opens nothing on a box; password guesses are counted (map E12, E13, E17).
- An urgent security fix reaches the boxes at night after one test on the test box; the box backs up first and undoes a failed update (map B23).
- The hub mails alarms and recoveries, and keeps one whole-box copy per week on ep0; CC uses its own limited token, not your password (map F1, F11, G15). - The hub mails alarms and recoveries, and keeps one whole-box copy per week on ep0; CC uses its own limited token, not your password (map F1, F11, G15).
## What is broken ## What is broken
- **P1:** about 12 homelab logins still use a password that was public, and the public Gitea repo is not decided (R-925, yours). - **P1:** any hacked app on DooPlex can read the hub's nightly backups, and maybe the signing keys (R-1241, homelab session); about 12 homelab logins still use a password that was public, and the public Gitea repo is not decided (R-925, yours).
- Tester 2 is off since 2026-10-04: old emergency password, no off-site check, no bootstrap (R-1139, R-1104, R-862). - Tester 2 is off since 2026-10-04: old emergency password, no off-site check, no bootstrap (R-1139, R-1104, R-862). The scratch box cannot use agent features (R-1083).
- DooPlex: the failed disk is still in the box, its alarms silenced (R-934); something sets the shared checkout to „bare" (R-935). - DooPlex: the failed disk is still in the box, its alarms silenced (R-934); something sets the shared checkout to „bare" (R-935).
- The scratch box cannot use agent features (R-1083).
## What we work on ## What we work on
- Dated checks, run by CC. 2026-10-23: no app stop when the host is busy (R-1173). 2026-10-26: each hub daily job ran once on the clock-change day (R-1183). 2026-10-27: the weekly clean-up window (R-435; the logs of the last one were lost to restarts). - Dated checks, run by CC. 2026-10-24: the 8 GB box's first night copy on 0.340.0 (R-1214). 2026-10-26: each hub daily job ran once on the clock-change day (R-1183). 2026-10-27: the weekly clean-up window (R-435; the logs of the last one were lost to restarts). 2026-10-30: D35, website and installer to Cloudflare, starts (R-1228, ruled yes).
## Waiting on you — decide ## Waiting on you — decide
@@ -29,11 +30,11 @@ Newest first. CC's pick is in the „Pick" column. Each row also has its full te
| # | Row | Question | Pick (why) | The other option costs | If you do nothing | Blocked | | # | Row | Question | Pick (why) | The other option costs | If you do nothing | Blocked |
|---|---|---|---|---|---|---| |---|---|---|---|---|---|---|
| D36 | R-1225, R-1226 | Two website sentences before the publish: „8 GB runs the basics; the photo app needs 16 GB” and „what you open from outside the home passes Cloudflare's network, readable there; the backups leave only encrypted”? | **Yes, both** (the patch's own aim is the whole truth) | — | the patch publishes with both promises a little too strong | — | | D42 | R-1246 | When the box limits or flags something, who is told? | **The family only about the qBittorrent limit (they can change it); the hacked-app alarms only you** (the family can do nothing about a hacked app) | tell the family too: a worrying mail they cannot act on | the same as my pick | — |
| D35 | R-1228 | After the release week, serve the website and the installer from Cloudflare, like the ISO? | **Yes, later** (no new installs stop when DooPlex is down) | keep them home: after a DooPlex loss, no install until it is back | the same | — | | D41 | R-1245 | How much of the measured upload may qBittorrent use by default? | **50 %** (the family keeps half the line; seeding took the whole line on the test bench) | 30 %: slower seeding; none: only the alarm | 50 % when you release the watch | — |
| D34 | R-232 | Copy the hub database to ep0 every 6 hours instead of every night? | **Yes** (0 €, about 30 minutes, one DooPlex change) | keep nightly: up to a day of hub changes lost, e.g. a new box's recovery package | the same | — | | D40 | R-1243 | The hub's backups in DooPlex's shared folder are not encrypted (two there now hold the tunnel tokens). Encrypt the hub's disk, or stop that backup? | **Stop it** (the hub's own copy to ep0 is encrypted, every 6 h, tested weekly) | encrypt: 5–10 min hub downtime and one more key to keep | the plain copies stay readable by any hacked DooPlex app | a homelab change |
| D33 | R-1227 | Copy the released images and agent packages to ep0 every night? | **Yes** (0 €, about 2 hours of CC, a few GB on ep0) | a timed rebuild drill instead: about 3 hours once, and rebuilt images are not the same | after a DooPlex loss no box updates, reinstalls or installs until everything is rebuilt | — | | D38 | R-1235 | Put the newest golden (637 MB) into the nightly release copy on ep0 too? | **Yes** (a new install after a DooPlex loss needs it; it fits under the 3 GB cap) | leave it out: after a loss, no new install until a golden is rebuilt and vouched | the same | — |
| D32 | R-923, R-924 | Print the break-glass sheet now (eight keys and logins + ep0's fingerprint) and keep it outside the home? | **Yes** (30 minutes; nothing else opens the off-site copies after a loss) | an encrypted USB stick outside the home: ~10 €, 1 hour, one more passphrase | after a DooPlex loss no off-site copy opens | — | | D37 | R-1236 | Raise Gitea's memory limit from 1 GiB to 2 GiB? It was killed for memory 4 times in 17 days, once during today's release. | **Yes** (DooPlex has the RAM; a DooPlex change, so yours) | keep 1 GiB: a restart in release hours fails box updates and CI for a minute | the same | — |
| D9 | R-1062 | Split the N100's USB drive in two, for multi-drive tests? | **No — keep one drive** (the lived-in box keeps its nightly whole-box backup) | Split: the box loses its local whole-box backup, or you buy a second drive first | it stays one drive; multi-drive tests stay on Tester 1 | — | | D9 | R-1062 | Split the N100's USB drive in two, for multi-drive tests? | **No — keep one drive** (the lived-in box keeps its nightly whole-box backup) | Split: the box loses its local whole-box backup, or you buy a second drive first | it stays one drive; multi-drive tests stay on Tester 1 | — |
| D7 | R-990, R-989 | Rule on the forum ideas and the selfh.st ideas now, or park them? | **Park them** (P4; nothing waits on them) | Rule now: about one hour of reading | nothing changes; the research gets old | — | | D7 | R-990, R-989 | Rule on the forum ideas and the selfh.st ideas now, or park them? | **Park them** (P4; nothing waits on them) | Rule now: about one hour of reading | nothing changes; the research gets old | — |
@@ -42,23 +43,22 @@ Newest first. CC's pick is in the „Pick" column. Each row also has its full te
**Still needed? (yes/no)** — CC could not check these. Answer yes or no per line. **Still needed? (yes/no)** — CC could not check these. Answer yes or no per line.
1. Look at `roms/roms/` on the N100's drive in the file manager (R-1099). Since 2026-10-16. 1. Look at `roms/roms/` on the N100's drive in the file manager (R-1099). Since 2026-10-16.
2. The N100 sheet, about 30 minutes: Plex, the admins in Prowlarr, Sonarr and Radarr, your download sources (`documentation/audits/n100-lived-in-2026-10-15/SHEET.md`). Since 2026-10-15. 2. The N100 sheet, about 30 minutes: Plex, the admins in Prowlarr, Sonarr and Radarr, your download sources (`documentation/audits/n100-lived-in-2026-10-15/SHEET.md`). Since 2026-10-15.
3. Look at these pages on demo-hp when you have time: Calibre-Web („Adatok és mentés"), the file manager, AdventureLog, Plex, the app page, the Plex and Sonarr guides („Útmutató"). Since 2026-10-16. 3. Look at these demo-hp pages when you have time: Calibre-Web, the file manager, AdventureLog, Plex, the app page, the Plex and Sonarr guides. Since 2026-10-16.
4. Remove the test server „plex-k6" from your Plex account (plex.tv → Settings → Authorized Devices). Since 2026-10-15. 4. Remove the test server „plex-k6" from your Plex account (plex.tv → Settings → Authorized Devices). Since 2026-10-15.
5. Ask Google to index `https://felhom.eu/sajat-felho-tarhely` in Search Console (R-1035). Since 2026-10-14. 5. Ask Google to index `https://felhom.eu/sajat-felho-tarhely` in Search Console (R-1035). Since 2026-10-14.
6. BIOS: on the N100, read „After Power Loss"; on the HP, set „Bypass F1 Prompt on Configuration Changes" to Enable. Since 2026-10-14. 6. BIOS: on the N100, read „After Power Loss"; on the HP, set „Bypass F1 Prompt on Configuration Changes" to Enable. Since 2026-10-14.
7. Pin the first Facebook post (R-917), and look at the new cover in the Facebook phone app (R-919). Since 2026-10-12. 7. Pin the first Facebook post (R-917), and look at the new cover in the Facebook phone app (R-919). Since 2026-10-12.
**Morning, 2026-10-23 — in this order.** **Day, 2026-10-23 — your do list.**
1. Hold or go: CC says go — the test night passed on a fresh 8 GB box (no failed check at night, every night job passed, nothing lost; one gap: no whole-box copy to ep0, R-1232). One question from the review: D31 as built also covers an install that got the whole-box password but no recovery package — its password is rotated without your press (R-1205). CC: go. If not: revert one hub commit before item 4. 1. Print the break-glass sheet (`documentation/runbooks/break-glass-sheet.md`, the part from „The sheet”, one A4), fill it by hand, keep it outside the home (D32; R-923, R-924). If not: after a DooPlex loss no off-site copy opens.
2. Release controller 0.340.0 (main after tonight; tested as rc.8 on the scratch box, rc.6 on the test box): the safe night copy, the catch-up fix, R-49, R-1187, R-1189, R-1214. If not: these wait. 2. On the hub's Hosts page: Discard appliance 49, and delete host Tester4-16fdef. If not: two dead entries alarm.
3. Release the agent (the tunnel repair, its tunnel field, the root-SSH bundle) and the installer tag with the root-SSH removal (R-1204, R-982); then vouch. If not: a clock-ahead box stays cut off; root keeps its password on the LAN. 3. D37 and D38 in the table (two small yes/no). If not: Gitea may restart in release hours; no golden in the release copy.
4. Build and deploy hub 0.167.0 (D31, the tunnel alarm and its clearing). If not: a dead tunnel stays silent. 4. Give the homelab session R-1241, R-1242, the 7-item list at the end of `documentation/audits/plex2shell-felhom-impact-2026-10-23/README.md`, and an upload alarm on DooPlex's `eno1` (the line is ~100 Mbit/s; the flood peaked at 905). If not: the next hacked app on DooPlex can read the hub's backups.
5. Publish the website patch (D3, D5), with D36's two sentences if yes. If not: the old wording stays. 5. Monday: deploy hub 0.168.0 (the last plain tokens locked, R-975); then release the upload watch on your yes (R-1244; D41, D42 first). If not: a hub copy still holds the tokens, and a hacked app on a family's box stays unseen.
6. On the hub's Hosts page: Discard appliance 49, and delete host Tester4-16fdef (tonight's test box). If not: two dead entries alarm.
7. The DooPlex hour: D32–D35 in the table. If not: a DooPlex loss stays as the survey describes.
**The rest** **The rest**
- System poster needs a refresh: the new 01:40 „release copy” arrow from DooPlex to ep0 (D33); the hub-database label already says every 6 hours. If not: the drawing misses one copy.
- Pull the failed disk Z6A07P2G out of DooPlex (R-934). If not: its alarms return on 11 November. Since 2026-10-12. - Pull the failed disk Z6A07P2G out of DooPlex (R-934). If not: its alarms return on 11 November. Since 2026-10-12.
- Rotate the reused homelab logins and decide the Gitea repo's visibility (R-925, P1). Since 2026-10-09. - Rotate the reused homelab logins and decide the Gitea repo's visibility (R-925, P1). Since 2026-10-09.
- Two leftovers on DooPlex: the Facebook `first-post/` folder in `leftovers/2026-10-14/` (keep, commit or delete); the `deny`-list edit in homelab-manifests' `.claude/settings.json` (commit or drop). If not: they stay. Since 2026-10-14. - Two DooPlex leftovers: `leftovers/2026-10-14/first-post/` (keep or delete); the `deny`-list edit in homelab-manifests' `.claude/settings.json` (commit or drop). Since 2026-10-14.
- Before the first paying customer: Tandoor's permission (R-789); a lawyer for the licence list and the terms (R-802, R-813); SparkyFitness by e-mail (R-784); print the break-glass sheet and the signing keys (R-923, R-924). - Before the first paying customer: Tandoor's permission (R-789); a lawyer for the licence list and the terms (R-802, R-813); SparkyFitness by e-mail (R-784).
- Later (yours, not urgent): R-1229 (ArgoCD's sync settings into git), R-862 (Tester 2's bootstrap, when it is back), R-504, R-1071, R-1073, R-1077, R-1042, R-132, R-908, R-779, R-904, R-232, R-433, R-933, R-213, R-832, R-388, R-882, R-883, R-814, R-1056, R-1164, R-930, R-920, R-902. - Later (yours, not urgent): R-1247 (a real upload-speed test), R-1248 (a hard upload cap per app), R-1229 (ArgoCD's sync settings into git), R-862 (Tester 2's bootstrap, when it is back), R-504, R-1071, R-1073, R-1077, R-1042, R-132, R-908, R-779, R-904, R-232, R-433, R-933, R-213, R-832, R-388, R-882, R-883, R-814, R-1056, R-1164, R-930, R-920, R-902.
@@ -124,6 +124,7 @@
| <a id="b20"></a>[B20](capability-map-detail/B.md#b20) | App crashes → customer notified (one event per transition, no flapping spam) | controller v0.120, hub v0.48 | **IMPLEMENTED** | crash→customer mail never live-confirmed | `audits/CAMPAIGN-3-2026-07-11.md` (2026-07-11) | | <a id="b20"></a>[B20](capability-map-detail/B.md#b20) | App crashes → customer notified (one event per transition, no flapping spam) | controller v0.120, hub v0.48 | **IMPLEMENTED** | crash→customer mail never live-confirmed | `audits/CAMPAIGN-3-2026-07-11.md` (2026-07-11) |
| <a id="b21"></a>[B21](capability-map-detail/B.md#b21) | Post-deploy optional config (API keys etc.) with restart | controller, catalog `.felhom.yml` | **IMPLEMENTED** | config-save + restart in no campaign | `tests/CAMPAIGN-2-2026-07-07.md` (2026-07-07) | | <a id="b21"></a>[B21](capability-map-detail/B.md#b21) | Post-deploy optional config (API keys etc.) with restart | controller, catalog `.felhom.yml` | **IMPLEMENTED** | config-save + restart in no campaign | `tests/CAMPAIGN-2-2026-07-07.md` (2026-07-07) |
| <a id="b22"></a>[B22](capability-map-detail/B.md#b22) | Backup classification: 13 bind-bearing apps carry mandatory/optional/excluded classes | catalog, controller v0.132–133 | **PROVEN-LIVE** | — | `audits/SPIKE-backup-classification-2026-07-14.md` (2026-07-14); `audits/CAMPAIGN-6D-2026-07-15.md` (2026-07-15) | | <a id="b22"></a>[B22](capability-map-detail/B.md#b22) | Backup classification: 13 bind-bearing apps carry mandatory/optional/excluded classes | catalog, controller v0.132–133 | **PROVEN-LIVE** | — | `audits/SPIKE-backup-classification-2026-07-14.md` (2026-07-14); `audits/CAMPAIGN-6D-2026-07-15.md` (2026-07-15) |
| <a id="b23"></a>[B23](capability-map-detail/B.md#b23) | An urgent security fix reaches the boxes at night — a `security_fix` ladder step (box walk required, bench optional, a CVE/GHSA notice), taken by the night update (`09` §3 decision 255, D39 = B) | catalog `3898593`, controller v0.341.0 | **PROVEN-LIVE** | scratch 9202 (drill catalog), Plex 1.43.4 → 1.43.5; an app with no box fixture is checked by health, version and a soak only (`seed: none`) | `audits/security-lane-2026-10-23/` (2026-10-23) |
## C. Protection & recovery (the product promise) ## C. Protection & recovery (the product promise)
@@ -555,6 +555,16 @@ record unreadable: its serve paths answer 500, a save refuses it (never blanks i
to a hub before v0.138.0** needs the columns opened first: `felhom-hub -unseal-box-secrets` (all or nothing; exit 1 = to a hub before v0.138.0** needs the columns opened first: `felhom-hub -unseal-box-secrets` (all or nothing; exit 1 =
nothing changed) — run in the running pod, then put the old image back. `guests.api_key` is an unused, always-empty nothing changed) — run in the running pod, then put the old image back. `guests.api_key` is an unused, always-empty
column and is not sealed. *Decided by CC unattended — operator may reverse (`09` §3 decision 132).* column and is not sealed. *Decided by CC unattended — operator may reverse (`09` §3 decision 132).*
**Since v0.168.0 (R-975, R-1241) the last plain tokens are sealed too:** the Cloudflare tunnel token, the Cloudflare API
token and the git token live INSIDE `customer_configs.config_json` (`infrastructure.cf_tunnel_token`,
`infrastructure.cf_api_token`, `git.token`). Each of those JSON leaves holds the same `enc:v1:` seal; the rest of the JSON
stays readable. `SaveCustomerConfig` seals, every reader opens through `openCustomerSecrets` (a leaf that does not open is
blanked and marks the record unreadable, as above). Legacy rows are sealed at start-up (`SealLegacyConfigTokens`, without
a `config_version` bump — the box's config is byte-for-byte the same, so no box re-pulls or restarts), followed ONCE by
`VACUUM` + a WAL checkpoint, because an `UPDATE` leaves the old plaintext row in a freed block of the file
(`TestR975_DBFileWithoutKeyRevealsNoToken`). `-unseal-box-secrets` opens these leaves too, so the roll-back above also
covers a return to a hub before v0.168.0. The full list of secret-bearing columns, measured on a copy of the live database
2026-10-23: `audits/hub-token-seal-2026-10-23/README.md`.
**And the key is the other half:** a backup of the database restores a hub that can open the sealed columns only **And the key is the other half:** a backup of the database restores a hub that can open the sealed columns only
with the same `OFFSITE_SECRET_KEY`; today that key exists only on DooPlex (the k8s Secret, and the GPG secrets export with the same `OFFSITE_SECRET_KEY`; today that key exists only on DooPlex (the k8s Secret, and the GPG secrets export
on the same machine). The off-site plan for the database and its key: `runbooks/RUNBOOK-hub-db-offsite-backup.md` on the same machine). The off-site plan for the database and its key: `runbooks/RUNBOOK-hub-db-offsite-backup.md`
@@ -531,3 +531,37 @@ list is shown as custom and saved back unchanged; the default list maps to group
multi-day backup fault reads as „nobody noticed" if the household ever finds out. multi-day backup fault reads as „nobody noticed" if the household ever finds out.
2. **The cooldown field („hány óránként legfeljebb"):** keep it on the page or move it under „Részletek"? Pick: 2. **The cooldown field („hány óránként legfeljebb"):** keep it on the page or move it under „Részletek"? Pick:
**under Részletek** — it is an engineering choice, which is what this redesign removes. **under Részletek** — it is an engineering choice, which is what this redesign removes.
## 9. The upload and CPU watch — „does the app explain its own traffic?" [DESIGN — proposed; built in controller v0.342.0 + hub v0.169.0, NOT released]
**Why** (operator ruling 2026-10-23 19:22, `CONTEXT.md`): DooPlex's hacked Plex sent ~474 GB in a day with no viewer and
used ~10 cores with no film being converted (`audits/plex2shell-felhom-impact-2026-10-23/`). Nothing on a Felhom box
would have noticed: the health check sees whole-box CPU at one instant, and nothing looks at upload at all. **The idea:**
when an app sends a lot (or burns CPU) for a long time, ask the APP whether that is its work. Work the app explains is
normal use; work it does not explain is the sign of a hacked app. Numbers and measurements:
`audits/SPIKE-upload-watch-2026-10-23.md`; the code: controller `internal/upwatch` (README §8e).
1. **The line.** Learnt from what the box already does: while its off-site push runs, the controller samples its own
sent bytes once a second; the best ≥ 10-second rate is kept per night (14 nights, settings.json `upwatch.line`); a
night counts when that window moved ≥ 10 MB; the line is the highest counting night. A **lower bound**, shown so
(„legalább N Mbit/s", system settings). An active test is not built (R-1247).
2. **Trigger, per app** (its compose project's containers summed; exact counters from the Docker Engine API, once a
minute): upload ≥ max(5 Mbit/s, 25 % of the line) for 15 minutes; CPU ≥ max(150 %, 50 % × cores) of one core for 30
minutes. Infrastructure (the controller — its own push is the line measure —, traefik, cloudflared, Samba) is never
judged; the box's own work on an app (a backup run, an update, a deploy) is never judged.
3. **The explanation.** qBittorrent (`up_info_data`) and Transmission (`uploadedBytes`): explained when the container
sent ≤ 1.25 × what the app counted + 1 Mbit/s. Plex: any viewer explains upload; any transcode explains CPU. An app
that does not answer gives no number (a hacked app may refuse its own API). No explainer: upload alarms only at ≥ 10 ×
its own p95 for 60 minutes after ~20 h of history; CPU at ≥ max(200 %, 75 % × cores) for 60 minutes.
4. **Who is told** (the R-388 rule, §8.1): **`app_unexplained_upload` / `app_unexplained_cpu`** (warning) and their
`_cleared` (info, recorded) are **operator-only** (hub `operatorOnlyEvents`), one per episode, per-app cooldown. The
household is told only about the qBittorrent limit, because they can change it (R-1246 asks the operator).
5. **qBittorrent's default upload limit:** 50 % of the line (R-1245), every 15 minutes, re-set when the line moves
> 20 %; never over a limit the household set (one there first, or any change from the value qBittorrent stored for
the box — it keeps KiB/s). No line → none set. While the box owns it, qBittorrent's page says: „A qBittorrent
feltöltése legfeljebb N Mbit/s, hogy a családi internet gyors maradjon. A qBittorrentben átállíthatod."
6. **Limits, stated:** an attacker who knows the check can make the app's API lie — a per-container ceiling (`tc` from
a helper in the app's network namespace, measured to work in an unprivileged guest; spike §5) would cap the flood
whatever the API says; not built. The box cannot tell LAN from internet bytes per app; a host-network container
(Samba) has no counter; the line is a lower bound.
7. **Release:** not released; the operator's yes (R-1244).
@@ -286,6 +286,9 @@ builds them (`audits/update-rulings-2026-09-23/`).
update night measured the proxy wrong in both directions — minor moves that held update night measured the proxy wrong in both directions — minor moves that held
(adventurelog, outline) and a tag shape it cannot read at all (§3b Q3). The test record is the (adventurelog, outline) and a tag shape it cannot read at all (§3b Q3). The test record is the
thing the proxy was guessing at. thing the proxy was guessing at.
**Dated note 2026-10-23 (decision 255, D39 = B):** a second step kind now exists — the `security_fix` step, proven
on the box with the bench optional, for an urgent upstream fix with a public notice. Decision 13's rule is
unchanged for every other move: a step a box takes was still tested, on at least the box venue.
14. **The update ladder** (Q3). A box more than one step behind **climbs one tested step at a time, in 14. **The update ladder** (Q3). A box more than one step behind **climbs one tested step at a time, in
order, and never jumps**. Each step is the full guarded update of §6.1. **Why:** a step was tested order, and never jumps**. Each step is the full guarded update of §6.1. **Why:** a step was tested
@@ -1031,6 +1034,52 @@ its length, and both fixes cost something the household would notice — operato
Built in controller v0.314.0 (`internal/stacks/restore_gate.go`); pinned by `restore_gate_test.go` and Built in controller v0.314.0 (`internal/stacks/restore_gate.go`); pinned by `restore_gate_test.go` and
`r1057_unit_gate_test.go` (ten mutations each seen failing). Proof: `audits/gate-restore-2026-10-15/9202/`. `r1057_unit_gate_test.go` (ten mutations each seen failing). Proof: `audits/gate-restore-2026-10-15/9202/`.
### 2026-10-23 (~12:00) — D39 = B: the security-fix step (operator ruling by starting the run; R-1239)
255. **An urgent upstream security fix reaches the boxes at night as a `security_fix` ladder step: the box walk is
required, the bench is optional, and a public notice is the authority.** *Operator ruling 2026-10-23 ~12:00 (D39 =
B, R-1239), taken by starting the D39 brief; its design is Claude.ai's recommendation, taken with it.* Why: on
2026-10-23 the only route for the Plex2Shell fix was an operator word, `git push --no-verify` past the move gate,
and a hand press on each box — and the night leg never takes a step with no test record (R-1238). That does not
scale past the first customers and needs the operator awake.
1. **The entry** (`scripts/ladder.py` `check_security`, the one reader): `"verdict": "security_fix"` with `security`
`{ids: [CVE-…|GHSA-…], advisory: "https://…", fixed_in}`, `box_evidence` (required), `seed` `read_back`|`none`,
`memory_peak_pct` from the BOX soak with `memory_basis: "box_soak"`; `evidence` = the bench record or null — a
bench given must be `proven` (`bench_verdict`, `harness_version` ≥ 2 ride with it). Never `backfilled`,
`digest_from` (a same-tag fix stays decision 52's lane), `engine_conversion`, nor a database engine MAJOR (any
engine — MariaDB included; the judgement is `check-engine-major.py`'s own `engine_of`/`major_of`, imported).
2. **No operator word per incident.** The session that writes the step reports it to the operator after the push.
3. **The gates:** the move gate accepts a `security_fix` move exactly as a proven one (from/to per service, digests
the registry still serves); `check-test-record.py` WARNs on every push while a template's head is a security-fix
step with no bench test („<app>: security-fix step <to> has no bench test (since <tested_at>)"). Seven decoys
(`test_gate_decoys.py`), each seen failing with the rules switched off.
4. **The box venue:** `box_walk.py --security` on 9202 through the product's Update; verdict `proven` only if the
update ended `done` with no undo and no hold, the app runs, the four version observables are TO, the seed (if
any) reads back, and a soak (default 600 s, cgroup `anon` against the limit, OOM kills and restarts counted)
sees no kill and no restart. A negative control (a TO image that exits at once) comes back `failed`.
5. **The writer:** `upgrade-test.py --write-ladder --security …`, refusing a box walk not proven, a bench given and
not proven, a template not at the walk's FROM, a digest that moved since the walk, an engine major, a missing
field. The compose move, `catalog_since` and the superseded step's own files are the shared `apply_entry`.
6. **The controller (v0.341.0):** the leg takes `proven` OR `security_fix`; every other guard runs unchanged, in
the same order; it logs `[update-leg] <app>: security fix <ids> taken (<from> → <to>)` and the hub report's
step carries the ids. A person's press and the badge are unchanged. **A controller ≤ 0.340.0 skips the step at
night (`not_proven`) and a hand press takes it** — proven on 9202, below.
7. **The trade, stated.** A security-fix step skipped the bench. For an app with a box fixture the data is still
read back after the update; for an app without one (Plex today) the step is checked only by „it starts, it is
healthy, it runs the new version, and a 10-minute soak sees no kill or restart". `files_may_change` is a bench
measurement: with no bench the step carries `false`. That is accepted because the leg's own guard is not the only
net — the update takes a per-app backup first, the undo puts the pre-update data back on a failed health check
(decision 15), and a security fix that rewrites files without breaking the health check is the case the bench
would catch and this lane accepts the risk of. A session that knows a fix migrates files runs the bench.
**Proof (9202, drill catalog, 2026-10-23):** `audits/security-lane-2026-10-23/` — the negative control (TO
`busybox:1.36.1`) came back `failed` (the box undid it after 335 s) and the writer refused it; Plex 1.43.4.10903 →
1.43.5.11029 `proven` (done in 36.9 s, the four observables at TO, digest `sha256:01bdf0ad…5c5f`, soak 600 s: anon
peak 10.7 % of 2 GiB, 0 kills, 0 restarts, `seed: none`); the writer wrote the drill step (CVE-2026-96652, -96654,
-96655, -96656; Plex's own notice as CISA KEV cites it, added 2026-10-20; fixed in 1.43.3.10861); on 0.340.0 the
night leg logged `plex: skipped — not_proven` and a hand press took the step; on 0.341.0-rc.1 the night leg logged
`plex: security fix CVE-2026-96652,CVE-2026-96654,CVE-2026-96655,CVE-2026-96656 taken` and ended `done` in 30.1 s
after the update's second-drive copy and undo copy. Released as controller 0.341.0, global floor 11:24 UTC.
### 2026-10-15 (07:48–08:20) — bake first; Plex through its own key; HSTS one day (recorded before the media build) ### 2026-10-15 (07:48–08:20) — bake first; Plex through its own key; HSTS one day (recorded before the media build)
247. ~~**Bake first.** A controller version is RELEASED only when its golden is baked.~~ **REVERSED by decision 250, 247. ~~**Bake first.** A controller version is RELEASED only when its golden is baked.~~ **REVERSED by decision 250,
@@ -36,6 +36,7 @@ decision (R-925).
| g | a compromised Gitea / registry / build | push to the catalog, the images and the installer tag | | g | a compromised Gitea / registry / build | push to the catalog, the images and the installer tag |
| h | a thief with the box | the disks | | h | a thief with the box | the disks |
| i | Cloudflare | the plaintext of tunnel traffic — **accepted** (R-904) | | i | Cloudflare | the plaintext of tunnel traffic — **accepted** (R-904) |
| j | **added 2026-10-23:** a hacked homelab app pod on DooPlex (happened: Plex2Shell, HM-040) | the pod network with free egress: every cluster Service, the node's ports (NFS, kubelet, k3s API), the LAN masqueraded as DooPlex; no service-account token |
## 4. Entry points ## 4. Entry points
@@ -75,6 +76,7 @@ OS packages (exact versions, apt-signed), the installer script (by tag, R-980).
| **added:** LAN ↔ box | partly | root password SSH on the host from the LAN (R-982) | | **added:** LAN ↔ box | partly | root password SSH on the host from the LAN (R-982) |
| **added:** hub ↔ box (inbound) | **does not hold** | `01` §4 says the box exposes no control endpoint; a hub-key route can replace the box's settings (R-970) | | **added:** hub ↔ box (inbound) | **does not hold** | `01` §4 says the box exposes no control endpoint; a hub-key route can replace the box's settings (R-970) |
| **added:** catalog ↔ every box | **design gap** | a catalog push reaches every box with no check on the box (R-971) | | **added:** catalog ↔ every box | **design gap** | a catalog push reaches every box with no check on the box (R-971) |
| **added 2026-10-23 (R-1241):** a hacked app pod on DooPlex ↔ Felhom's secrets | **does not hold**; not used in the Plex2Shell window | two no-login doors: the Longhorn NFS export (the hub's unencrypted nightly copies with the unsealed tokens of R-975; by a published file-handle escape the whole sda1 disk, the operator signing keys included — not exercised) and the Longhorn API (backup a volume to any target). Plex2Shell, 2026-10-17 → 10-23: **NOT REACHED** — 0 new NFS connections in the window, no off-schedule backup or volume; the hub, the k8s API and the kubelet refuse a caller with no credential (measured). The export was narrowed to the pod network on 2026-10-23; the pod side stays open (`audits/plex2shell-felhom-impact-2026-10-23/`). **Felhom half, 2026-10-23 night:** the last plain tokens sealed in hub 0.168.0 (built, deploy pending — `audits/hub-token-seal-2026-10-23/`); the two plain Longhorn copies of the hub volume already in the folder are R-1243's decision. A household box's version of this attacker (a hacked app sending or mining) is what the upload watch (R-1244, not released) detects |
## 6. What we accept (do not re-report) ## 6. What we accept (do not re-report)
@@ -379,3 +379,28 @@
**Gap / roadmap (as written):** Remaining ~39 apps are legacy-class by design (unit-only offsite) **Gap / roadmap (as written):** Remaining ~39 apps are legacy-class by design (unit-only offsite)
--- ---
## B23 — An urgent security fix reaches the boxes at night (the security-fix step)
*Map row: [B23](../00-capability-map.md#b23) · added 2026-10-23.*
**Scenario:** an app has a published hole (a CVE or GHSA id with its notice) and a fixed upstream version. CC walks the
step on scratch 9202 through the product's Update (`box_walk.py --security`: install at FROM, the guarded Update, the
four version observables at TO, a 600 s memory soak), and the only writer turns a proven walk into a `security_fix`
ladder step. Every box on controller >= 0.341.0 takes it at night with the usual guards (backup first, undo on a
failed health check, held / stopped / needs_person / W+5h respected).
**Components:** catalog `3898593` (`ladder.py check_security`, the two test-record gates, `upgrade-test.py --write-ladder
--security`, `box_walk.py --security`); controller v0.341.0 (`legCandidate`).
**Status:** **PROVEN-LIVE** on 9202 with the drill catalog, 2026-10-23.
**Evidence:** `audits/security-lane-2026-10-23/` — the negative control (TO `busybox:1.36.1`) `failed` and the writer
refused it; Plex 1.43.4.10903 → 1.43.5.11029 `proven`; on 0.340.0 the night leg logged `plex: skipped — not_proven` and
a hand press took the step; on 0.341.0-rc.1 the night leg logged `plex: security fix CVE-2026-96652,… taken` and ended
`done` after a second-drive copy and an undo copy.
**Gap:** an app with no box fixture (Plex today, R-1238) is checked only by health, version and the soak — no data is
read back. `files_may_change` is a bench measurement and reads `false` when no bench ran (decision 255 item 7).
---
@@ -101,6 +101,7 @@ Footnote: "W = the household's backup window start, 02:30 by default. Tiers 1–
- one namespace **per household** (whole-guest copies, each household's own key), - one namespace **per household** (whole-guest copies, each household's own key),
with a NEUTRAL note under it (not a red gap box): "By design: each household holds the key to its own copies; the operator cannot open them without their recovery code." — *fix (c), 2026-10-09: this is a property of the design, not a gap, and a red box said the opposite of what it means.* with a NEUTRAL note under it (not a red gap box): "By design: each household holds the key to its own copies; the operator cannot open them without their recovery code." — *fix (c), 2026-10-09: this is a property of the design, not a gap, and a red box said the opposite of what it means.*
- the **`operator`** namespace: two groups — **"hub database"** and **"DooPlex copy"** (code, password manager, secrets, signing keys). - the **`operator`** namespace: two groups — **"hub database"** and **"DooPlex copy"** (code, password manager, secrets, signing keys).
- outside PBS, a plain folder: the **release copy** (images + agent packages, D33).
Prune jobs on ep0: households keep one copy per week for 2 weeks (`keep-weekly 2`, R-1162, 2026-10-19; every new household's job is made with its namespace, R-1165); `operator` keeps 14 daily + 8 weekly. Prune jobs on ep0: households keep one copy per week for 2 weeks (`keep-weekly 2`, R-1162, 2026-10-19; every new household's job is made with its namespace, R-1165); `operator` keeps 14 daily + 8 weekly.
Mark ep0 with a small shield: "**Protected** — holds the only off-premises copy of real household data." Mark ep0 with a small shield: "**Protected** — holds the only off-premises copy of real household data."
- **Hetzner Storage Box** (grey): the shared box for the households' per-app restic copies (Tier 3), one sub-account per household, add-only keys. - **Hetzner Storage Box** (grey): the shared box for the households' per-app restic copies (Tier 3), one sub-account per household, add-only keys.
@@ -121,8 +122,9 @@ Footnote: "W = the household's backup window start, 02:30 by default. Tiers 1–
Arrows from DooPlex (dashed, orange → ep0): Arrows from DooPlex (dashed, orange → ep0):
- **00:20 "DooPlex copy"**: the code (614 MB), Gitea's database and settings, the **password manager**, the nightly secrets export, the **signing keys**. Encrypted on DooPlex with the **DooPlex off-site key**. The key that writes it **cannot delete** old copies. Tested back every Sunday. - **00:20 "DooPlex copy"**: the code (614 MB), Gitea's database and settings, the **password manager**, the nightly secrets export, the **signing keys**. Encrypted on DooPlex with the **DooPlex off-site key**. The key that writes it **cannot delete** old copies. Tested back every Sunday.
- **02:30 "Hub database"**: encrypted with the **hub-DB key**. Tested back every Sunday at 04:30. - **02:30, 08:30, 14:30, 20:30 "Hub database"** (every 6 hours since 2026-10-23, D34): encrypted with the **hub-DB key**. Tested back every Sunday at 04:30.
- **Left out on purpose:** the container registry (27.7 GB) — "rebuilt from the code". - **01:40 "Release copy"** (since 2026-10-23, D33): the newest 3 released images of the controller, hub and samba, and the newest 5 agent packages — not encrypted (nothing secret), into a plain folder on ep0 (`/srv/felhom-release-copy`, its own limited user, outside PBS), about 0.7 GB, capped at 3 GB.
- **Left out on purpose:** the rest of the container registry (older tags, test builds, non-Felhom images) — "rebuilt from the code".
Arrow ep0 → DooPlex (dashed, 05:00): "**ep0-copy** pull: a second copy of ep0 at home. Keeps 8 weekly copies. A daily job removes a deleted customer's copy within 30 days." Arrow ep0 → DooPlex (dashed, 05:00): "**ep0-copy** pull: a second copy of ep0 at home. Keeps 8 weekly copies. A daily job removes a deleted customer's copy within 30 days."
**The test machines** (small, plain tiles near DooPlex, labelled "disposable"): **The test machines** (small, plain tiles near DooPlex, labelled "disposable"):
@@ -133,7 +133,7 @@ code{font-family: ui-monospace, "SFMono-Regular", Menlo, monospace; font-size: 1
<div style="position: absolute; left: 1720px; top: 706px; width: 184px; font-size: 16px; line-height: 20px; font-weight: 400; color: #4a5670; text-align: center;">The hub never connects into a box.</div> <div style="position: absolute; left: 1720px; top: 706px; width: 184px; font-size: 16px; line-height: 20px; font-weight: 400; color: #4a5670; text-align: center;">The hub never connects into a box.</div>
<div style="position: absolute; left: 1720px; top: 784px; width: 184px; font-size: 16px; line-height: 20px; font-weight: 800; color: #a85400; text-align: center;">00:20 DooPlex copy</div> <div style="position: absolute; left: 1720px; top: 784px; width: 184px; font-size: 16px; line-height: 20px; font-weight: 800; color: #a85400; text-align: center;">00:20 DooPlex copy</div>
<div style="position: absolute; left: 1720px; top: 824px; width: 184px; font-size: 16px; line-height: 20px; font-weight: 400; color: #a85400; text-align: center;">DooPlex off-site key</div> <div style="position: absolute; left: 1720px; top: 824px; width: 184px; font-size: 16px; line-height: 20px; font-weight: 400; color: #a85400; text-align: center;">DooPlex off-site key</div>
<div style="position: absolute; left: 1720px; top: 872px; width: 184px; font-size: 16px; line-height: 20px; font-weight: 800; color: #a85400; text-align: center;">02:30 hub database</div> <div style="position: absolute; left: 1720px; top: 872px; width: 184px; font-size: 16px; line-height: 20px; font-weight: 800; color: #a85400; text-align: center;">every 6 h: hub database</div>
<div style="position: absolute; left: 1720px; top: 912px; width: 184px; font-size: 16px; line-height: 20px; font-weight: 400; color: #a85400; text-align: center;">hub-DB key</div> <div style="position: absolute; left: 1720px; top: 912px; width: 184px; font-size: 16px; line-height: 20px; font-weight: 400; color: #a85400; text-align: center;">hub-DB key</div>
<div style="position: absolute; left: 1720px; top: 962px; width: 184px; font-size: 16px; line-height: 20px; font-weight: 800; color: #0a3d73; text-align: center;">05:00 ep0-copy pull</div> <div style="position: absolute; left: 1720px; top: 962px; width: 184px; font-size: 16px; line-height: 20px; font-weight: 800; color: #0a3d73; text-align: center;">05:00 ep0-copy pull</div>
<div style="position: absolute; left: 1720px; top: 1002px; width: 184px; font-size: 16px; line-height: 20px; font-weight: 400; color: #0a3d73; text-align: center;">ciphertext only</div> <div style="position: absolute; left: 1720px; top: 1002px; width: 184px; font-size: 16px; line-height: 20px; font-weight: 400; color: #0a3d73; text-align: center;">ciphertext only</div>
@@ -0,0 +1,159 @@
# SPIKE — who is using the upload line, and does the app explain it? (2026-10-23 night)
Operator ruling 2026-10-23 19:22 (`CONTEXT.md`): measure the line; on a sustained high upload attribute it to an app
and ask the app; a mismatch is the alarm; the same shape for CPU; qBittorrent gets a default upload limit from the
measured line, household changes respected. Brief Part 2.1. Design written from these numbers: §6 here and
`architecture/08-alarm-ladder.md` §9 [DESIGN — proposed]. Evidence and tools: `SPIKE-upload-watch-2026-10-23/`.
Read first: `08-alarm-ladder.md` (R-388, §8.1), `07-backup-architecture.md` (the night chain: W = 02:30 local, the
off-site push after it, the proof at 03:30 UTC), `15-media-library.md`, `13-threat-model.md` (attacker j),
`audits/plex2shell-felhom-impact-2026-10-23/README.md` (the 1.5 TB Plex upload). Controller: `internal/metrics/`
(`container_metrics` — one row per container per minute, 30 days), `internal/monitor/healthcheck.go` (the instant
whole-box CPU warning), `internal/mediawire/` (the app clients and their credentials, `09` §3 decision 248).
Machines: the three test boxes READ ONLY (their stored metrics; their off-site record; tonight a one-second read of
the controller's own counter during the real push); scratch 9202 on demo-hp (throwaway qBittorrent, Transmission, Plex,
Jellyfin through the product's deploy); a throwaway receiver LXC **9471 `cc-uw-recv`** on demo-hp's scratch storage
(never the thin pool). Every flood went 9202 → 9471 on demo-hp's own bridge; nothing went toward the internet.
## 1. Normal levels (stored metrics, three boxes)
History: **demo-hp** 2026-09-23 02:00 → 10-23 18:09 UTC (30.7 d, 998 216 rows); **demo-felhom** (the N100) same span
(30.7 d, 268 120 rows); **Tester 1** 2026-10-04 19:41 → 10-23 18:08 (18.9 d, 294 433 rows). Per app: upload from the
`net_tx_bytes` deltas (one-minute samples), CPU in percent of ONE core. Full tables: `s1-levels-per-app.txt`.
| box | the busiest uploaders (p50 / p95 / max Mbit/s) | the busiest CPU (p95 / max % of a core) |
|---|---|---|
| demo-hp | qbittorrent 0.02 / 1.2 / 4.0; immich-server 0.03 / 0.13 / 243 (one minute); felhom-controller 0 / 0.003 / 17.8 (the push) | grimmory 272 / 305 (a scan, 94 samples); immich-ML 32 / 548; romm 3 / 442; paperless 0.3 / 404 |
| demo-felhom | immich-server 0.67 / 5.95 / 12.9 (32 samples); jellyfin 0 / 0.85 / 2.9 | immich-ML 295 / 296 (an import); onlyoffice 131 / 148; paperless 137 / 140 |
| Tester 1 | qbittorrent 0.007 / 0.13 / 42.4; transmission 0.001 / 0.013 / 57.4; controller 0 / 0.003 / 37.5 | paperless 0.7 / 508; controller 46 / 423; plex 4.3 / 198 |
**How long a normal high lasts** (`s1-longest-runs.txt` — the longest run of consecutive minutes): upload ≥ 5 Mbit/s:
**3 min** at most (qBittorrent, Tester 1); ≥ 1 Mbit/s: 9 min. CPU ≥ 150 %: **7 min** at most (Immich machine learning);
≥ 80 %: 13 min (Kimai). Busiest upload hours (UTC): demo-hp 03h, 02h; demo-felhom 16h, 05h; Tester 1 07h, 18h — no fixed
pattern beyond the night push. For scale: DooPlex's hacked Plex sent ~474 GB in one day (≈ 44 Mbit/s on average, for
hours) and used ~10 cores.
`felhom-samba` runs with the host network: its counter is always 0 (no own network namespace) — the watch cannot see it.
## 2. The line without a test
**What the box already sees:** the off-site push (restic, inside the controller container) is the box's only big
upload of its own. At the stored one-minute sample (`s2-controller-push-per-night.txt`): the controller's best five
minutes per night exceeded 2 Mbit/s on **2 of 31 nights** on demo-hp (5.1 and 6.9 Mbit/s; best single minute 17.0),
**1 of 19** on Tester 1 (7.6; best minute 37.5) and **0 of 31** on demo-felhom. The off-site record keeps the push's
duration (33 s on demo-felhom, 1 m 8 s on Tester 1, 3 m 19 s on demo-hp on 2026-10-23) and **no byte count**.
**Conclusion:** at a one-minute sample the push shows the night's DATA SIZE (a few MB, incremental), not the line. Not
enough as it stands. Two changes make it usable: sample once a SECOND during the push (the controller knows when its
push runs and can read its own counter), and let a night count only when its best 10 seconds moved ≥ 10 MB. Even then
it is a **lower bound** (restic over SFTP to the Storage Box may not fill the line; the family uploads too).
**Tonight's one-second read of the real push** (2026-10-24 ~02:16Z, three boxes, read only): §2.1 below.
### 2.1 One-second samples of the real push
*(filled after 02:30Z — see the section at the end, „Night data")*
## 3. The line with a test — NOT run tonight
| Candidate | Ours? | Terms | Cost per test | Tonight |
|---|---|---|---|---|
| ep0 (a receiver on our Hetzner box) | yes | ours | 10 s × line ≈ 125 MB at 100 Mbit/s | **not built** — a change on ep0 is forbidden tonight |
| the box's own Storage Box sub-account, through the same transport as the push | yes (Hetzner, unlimited traffic) | Hetzner's — ours | same | not tried — a test file in the account that holds the restic repository needs its own design (the repo check, the quota) |
| Cloudflare R2 (where the ISO lives) | yes | ours | same + R2 class-A writes | not used — its write key is the operator's ISO-publish key; a test object in a public bucket is wrong |
| public speed tests (speed.cloudflare.com, LibreSpeed servers) | no | **not read** | — | not used (the brief: no third-party test without its terms) |
A quiet hour: never 02:30–05:30 local (dumps 02:30, second drive, off-site push, the 03:30 UTC proof). The family shares
the line, so take the highest of several runs. **Not needed for the first build** — §6 works with the push's lower
bound and an absolute floor; an active test is a decide row (R-1247).
## 4. Can the box ask each app? (measured on 9202 with throwaway installs; a private torrent 9202 → 9471)
Set-up: qBittorrent 5.2.4 and Transmission 4.1.3 installed through the product (`POST /api/stacks/<n>/deploy`; the
first try was refused BEFORE anything was made — the data place must be the drive itself; two empty helper folders
removed). The same 2 GiB file (an AES-CTR keystream of a fixed key) on both sides; a private torrent; a 40-line HTTP
tracker on 9471 (`tools/tracker.py`); `transmission-daemon` on 9471 as the leecher. The admin passwords were read from
the containers at use and never printed.
| App | Its own number | Measured | Limit | Household's limit visible? |
|---|---|---|---|---|
| **qBittorrent** | `/api/v2/transfer/info` → `up_info_data` (cumulative), `up_info_speed` | seeding: app **131.1 Mbit/s** vs container **134.6–140.5** → **×1.03–1.07** (`s4-qb-seed-nolimit.jsonl`) | `transfer/setUploadLimit` (bytes/s) = `preferences.up_limit`; stored in KiB/s (2 500 000 → **2 499 584**); survives a restart (`Session\GlobalUPSpeedLimit=2441`); measured: ~20 Mbit/s held (`s4-qb-seed-limit20.jsonl`) | yes: `transfer/uploadLimit` ≠ the value the box stored |
| **Transmission** | RPC `session-stats.current-stats.uploadedBytes`, `uploadSpeed` | seeding: app 487.1 / 390.3 / 115.8 vs container 487.6 / 390.7 / 117.9 Mbit/s → **×1.001–1.02** (`s4-tr-seed-nolimit.jsonl`) | `session-set speed-limit-up` (kB/s) + `-enabled` (read back); **its rate under the limit was NOT observed** — the re-added leecher got no connection in 2 minutes | yes: `speed-limit-up-enabled` + value |
| **Plex** | `/status/sessions`, `/transcode/sessions` (`MediaContainer.size`) | unclaimed 1.43.5: both 200 without a token from the docker network, `{"size":0}`; a claimed server needs its PlexOnlineToken (read at use from Preferences.xml, as mediawire does — no new secret) | — | — |
| **Jellyfin** | `/Sessions` | **401** without a key; the key named `felhom` exists only when the household made it (mediawire's „one household step") — the box cannot create one at install without the admin login it does not have | — | — |
| Nextcloud, Immich | **no upload-explaining number found** (not measured further); Immich's job queue needs an API key the box does not hold | — | — | → the plain rule (§6) |
**The fake hacked app** (code inside qBittorrent's own container, `docker exec … python3` → 9471:5001, Plex2Shell's
shape): the container sent **~10 100 Mbit/s** (LAN, one bridge) while qBittorrent reported **0** (`s4-qb-flood.jsonl`).
**The counter itself:** the Docker Engine API's one-shot stats (`networks.*.tx_bytes`) equal the kernel's counter in
the container's network namespace to the byte; `docker stats`' text (what `internal/metrics` stores) has three
significant digits — ~10 MB steps at a GB total, ~1.3 Mbit/s at a one-minute sample. The watch reads the Engine API.
**A limit the hacked app controls:** an attacker with code in the app's container can also answer its API. The check
catches an attacker who does not know about it; one who does could lie. §5 is the answer to that.
## 5. A universal upload ceiling — spike only
A helper container sharing the app's network namespace (`docker run --rm --network container:qbittorrent --cap-add
NET_ADMIN alpine:3.20` + `iproute2-tc`) added `tc qdisc … root tbf rate 20mbit burst 64kb latency 400ms` on the app's
`eth0` **inside the unprivileged 9202 guest**. The same flood then ran at **19.9–20.1 Mbit/s** (`s4-qb-flood-tbf.jsonl`),
qBittorrent's API kept answering, and `tc qdisc del` restored it. Costs: a helper image with `tc` (a new external image,
or `tc` shipped in the controller image), `NET_ADMIN` for that helper, re-applied after every app restart (the qdisc
dies with the namespace), upload only. **Not built** (brief). It would cap a hacked app's flood whatever its API says.
## 6. The design (numbers from §1–§5; full text `08-alarm-ladder.md` §9)
1. **Line:** one-second samples of the controller's own sent bytes during the off-site push; the best ≥ 10-second rate
per night; a night counts when that window moved ≥ 10 MB; the line = the highest counting night of the last 14;
settings.json `upwatch.line`; shown on the system settings page as „legalább N Mbit/s" („még mérjük" until known).
2. **Trigger:** an app (its containers summed, exact counters, once a minute) sends ≥ **max(5 Mbit/s, 25 % of the line)**
for **15 minutes** — five times the longest normal run at ≥ 5 Mbit/s (3 min). Per app, not per box: the box cannot
tell LAN from internet bytes inside its controller container, and the per-app view is what the check compares.
3. **Attribution:** the app's compose project; infrastructure (controller, traefik, cloudflared, Samba) never judged.
4. **Explanation:** qBittorrent / Transmission: explained when container bytes ≤ 1.25 × the app's own count + 1 Mbit/s
(measured overhead 1–7 %); Plex: any viewer explains the upload (session bandwidth not measured — the conservative
half; no viewer + a big upload = the Plex2Shell signature). Not explained → **`app_unexplained_upload`**,
operator-only, one per episode, a clear after 15 quiet minutes. No explainer: alarm only at ≥ 10 × its own p95 for
60 minutes, after ~20 h of history, worded „no app number to compare".
5. **CPU:** ≥ **max(150 %, 50 % × cores)** of one core for **30 minutes** (four times the longest normal run at ≥ 150 %),
explained by a Plex transcode or the box's own work on the app (backup, update, deploy) → else
**`app_unexplained_cpu`**. No explainer: ≥ max(200 %, 75 % × cores) for 60 minutes.
6. **qBittorrent limit:** 50 % of the line (CC's pick — R-1245), every 15 minutes, re-set when the line moves > 20 %;
never over a household's limit (a limit there first, or any change from the stored value). No line → nothing set.
The household's line (HU + EN in the report).
7. **Edge cases:** the night push is the controller's (never judged); the first day: apps with an explainer are judged
on the floor (a mismatch is evidence whatever the line), apps without one are not judged before ~20 h of history; a
slow or changing line (a Wi-Fi laptop): the line is a max over 14 nights — a falling line lowers nothing until it
rolls out (R-1247 notes the active test); two apps at once: each judged on its own bytes; the household's own devices:
invisible to the box — the trigger uses the box's own bytes only; an app reinstalled from scratch reads as „the
household removed the limit" and is left alone.
## 7. Live proofs on 9202 (controller `0.342.0-rc.1`, commit `a9c1997`, CI run 2270 success)
Set by hand in 9202's `/etc/felhom-controller-image` (an `-rc` tag is never offered to a household); 9202's hub link
is off by design, so every event was handed to the notifier and DROPPED there — the hub side (allow-list, operator-only,
the mail line) is proven by hub 0.169.0's tests. 9202's off-site is off, so one line record (40 Mbit/s) was seeded by
hand into its settings.json. Logs: `SPIKE-upload-watch-2026-10-23/live/2-9202-watch-log-full.txt`.
| # | What | Result (UTC) |
|---|---|---|
| 1 | qBittorrent unlimited, line 40 Mbit/s → the box sets the limit | **19:47:42** „qBittorrent upload limit set to 2499584 B/s (50 % of the measured line, 40.0 Mbit/s)" — read back from qBittorrent: 2 499 584 |
| 2 | **a real torrent seeding at the limit** (5 GB, private, 9202 → 9471) | **20:04:42** „qbittorrent sent 20.8 Mbit/s for 15 min — explained by the app (qbittorrent: 20.0 Mbit/s)"; no alarm (counter ratio 1.04) |
| 3 | **a CPU burner in Plex with no transcode** (4 busy loops, 400 % on a 7-core guest; trigger 350 %) | **20:07:42** „plex used 399% CPU … for 30 min with no work that explains it — operator alarm" → `app_unexplained_cpu`; ONE |
| 4 | **the fake hacked app**: a 50 Mbit/s flood from inside qBittorrent's container to 9471, hidden behind the real seed | **20:19:42** „qbittorrent sent 65.0 Mbit/s for 15 min — NOT explained by the app (qbittorrent: 20.0 Mbit/s) — operator alarm" → `app_unexplained_upload`; ONE, none more while it ran |
| 5 | the burner stopped 20:11 | **20:25:41** „plex: the unexplained CPU stopped … — cleared" → `app_unexplained_cpu_cleared`; ONE |
| 6 | the household changes qBittorrent's limit by hand (1 500 000 → stored 1 499 136) at 20:21 | **20:32:42** „qBittorrent's upload limit is the household's — the box leaves it alone from now on"; read back at 20:43: still 1 499 136 |
| 7 | the flood stopped 20:26 (the seed went on, explained) | **20:41:41** „qbittorrent: the unexplained upload stopped … — cleared" → `app_unexplained_upload_cleared`; ONE |
| 8 | the system settings page (`GET /settings`) | „Feltöltési sebesség: legalább 40 Mbit/s (az éjszakai távoli mentésből mérve)"; qBittorrent's page carried no limit line after step 6 (the household's) — the box-owned branch is pinned by `TestUpwatch_QBLimitLineOnQBittorrentsPageOnly`, not captured live |
**Found live:** the very first minute after a start failed to reach the apps by name (the bootstrap joins the controller
to the app network a few seconds after the start); every later minute answered. That first minute only sets baselines —
**NOT-A-FINDING**. The media wiring's generated `docker-compose.override.yml` stays beside the template after a removal
(Jellyfin tonight; Plex's from the morning session) — rewritten before every start, harmless — **NOT-A-FINDING**.
**Teardown, three layers:** machine — the four throwaway apps removed through the product (containers and volumes gone,
verified), my test files and probes deleted, the `alpine:3.20` helper image removed, 9202 back on 0.341.0 with the seeded
record removed, the rc image removed; host — the receiver LXC 9471 destroyed (`--purge`, its disk gone); hub — none (9202
is not on the hub). The night sampler on the three test boxes is reads only.
@@ -0,0 +1,15 @@
gitea.dooplex.hu/admin/felhom-controller:0.342.0-rc.1
felhom-controller gitea.dooplex.hu/admin/felhom-controller:0.342.0-rc.1 Up 6 minutes (healthy)
filebrowser gtstef/filebrowser:1.5.6-stable Up 4 hours (healthy)
immich-machine-learning ghcr.io/immich-app/immich-machine-learning:v3.2.4 Up 4 hours (healthy)
immich-postgres ghcr.io/immich-app/postgres:16-vectorchord0.4.3-pgvectors0.2.0 Up 4 hours (healthy)
immich-redis redis:7-alpine Up 4 hours (healthy)
immich-server ghcr.io/immich-app/immich-server:v3.2.4 Up 4 hours (healthy)
jellyfin jellyfin/jellyfin:10.11.11 Up About an hour (healthy)
paperless-postgres postgres:18-alpine Up 4 hours (healthy)
paperless-redis redis:7-alpine Up 4 hours (healthy)
paperless-webserver ghcr.io/paperless-ngx/paperless-ngx:2.20.15 Up 4 hours (healthy)
plex plexinc/pms-docker:1.43.5.11029-6bf8af3f0 Up About an hour (healthy)
qbittorrent qbittorrentofficial/qbittorrent-nox:5.2.4-1 Up About an hour (healthy)
traefik traefik:v3.7.13 Up 4 hours
transmission lscr.io/linuxserver/transmission:version-4.1.3-r0 Up About an hour (healthy)
@@ -0,0 +1,10 @@
VMID Status Lock Name
9201 running demo-hp
9202 running demo-hp-scratch
9401 stopped upgrade-harness
9471 running cc-uw-recv
description: CC throwaway 2026-10-23 night%3A upload-watch spike receiver/leecher. Remove after the session.%0A
hostname: cc-uw-recv
net0: name=eth0,bridge=vmbr0,hwaddr=BC:24:11:04:68:80,ip=dhcp,type=veth
rootfs: nvme-scratch:9471/vm-9471-disk-0.raw,size=8G
tags: cc;scratch;uw-spike
@@ -0,0 +1,9 @@
2026/10/23 19:32:41 upwatch_wiring.go:97: [INFO] [upwatch] upload and CPU watch started (line at least 40 Mbit/s, qBittorrent share 50 %)
2026/10/23 19:32:41 watch.go:237: [DEBUG] [upwatch] plex: the app did not answer (resolving the plex container: lookup plex on 192.168.0.250:53: no such host) — treated as no number this minute
2026/10/23 19:32:42 watch.go:237: [DEBUG] [upwatch] transmission: the app did not answer (Post "http://transmission:9091/transmission/rpc": dial tcp: lookup transmission on 192.168.0.250:53: no such host) — treated as no number this minute
2026/10/23 19:32:42 notifier.go:1463: [WARN] notifier disabled (no hub configured): DROPPED event app_definition_refused (severity warning) — further app_definition_refused events are logged at DEBUG only
2026/10/23 19:32:42 watch.go:237: [DEBUG] [upwatch] qbittorrent: the app did not answer (Post "http://qbittorrent:8080/api/v2/auth/login": dial tcp: lookup qbittorrent on 192.168.0.250:53: no such host) — treated as no number this minute
2026/10/23 19:47:42 service.go:108: [INFO] [upwatch] qBittorrent upload limit set to 2499584 B/s (50 % of the measured line, 40.0 Mbit/s)
2026/10/23 20:04:42 watch.go:303: [INFO] [upwatch] qbittorrent sent 20.8 Mbit/s for 15 min — explained by the app (qbittorrent: 20.0 Mbit/s, 0 viewer(s)); normal use
2026/10/23 20:07:42 watch.go:343: [WARN] [upwatch] plex used 399% CPU (of one core; 7 cores) for 30 min with no work that explains it (plex transcodes) — operator alarm
2026/10/23 20:07:42 notifier.go:1463: [WARN] notifier disabled (no hub configured): DROPPED event app_unexplained_cpu (severity warning) — further app_unexplained_cpu events are logged at DEBUG only
@@ -0,0 +1,16 @@
2026/10/23 19:32:41 upwatch_wiring.go:97: [INFO] [upwatch] upload and CPU watch started (line at least 40 Mbit/s, qBittorrent share 50 %)
2026/10/23 19:32:41 watch.go:237: [DEBUG] [upwatch] plex: the app did not answer (resolving the plex container: lookup plex on 192.168.0.250:53: no such host) — treated as no number this minute
2026/10/23 19:32:42 watch.go:237: [DEBUG] [upwatch] transmission: the app did not answer (Post "http://transmission:9091/transmission/rpc": dial tcp: lookup transmission on 192.168.0.250:53: no such host) — treated as no number this minute
2026/10/23 19:32:42 notifier.go:1463: [WARN] notifier disabled (no hub configured): DROPPED event app_definition_refused (severity warning) — further app_definition_refused events are logged at DEBUG only
2026/10/23 19:32:42 watch.go:237: [DEBUG] [upwatch] qbittorrent: the app did not answer (Post "http://qbittorrent:8080/api/v2/auth/login": dial tcp: lookup qbittorrent on 192.168.0.250:53: no such host) — treated as no number this minute
2026/10/23 19:47:42 service.go:108: [INFO] [upwatch] qBittorrent upload limit set to 2499584 B/s (50 % of the measured line, 40.0 Mbit/s)
2026/10/23 20:04:42 watch.go:303: [INFO] [upwatch] qbittorrent sent 20.8 Mbit/s for 15 min — explained by the app (qbittorrent: 20.0 Mbit/s, 0 viewer(s)); normal use
2026/10/23 20:07:42 watch.go:343: [WARN] [upwatch] plex used 399% CPU (of one core; 7 cores) for 30 min with no work that explains it (plex transcodes) — operator alarm
2026/10/23 20:07:42 notifier.go:1463: [WARN] notifier disabled (no hub configured): DROPPED event app_unexplained_cpu (severity warning) — further app_unexplained_cpu events are logged at DEBUG only
2026/10/23 20:19:42 watch.go:307: [WARN] [upwatch] qbittorrent sent 65.0 Mbit/s for 15 min — NOT explained by the app (qbittorrent: 20.0 Mbit/s, 0 viewer(s)) — operator alarm
2026/10/23 20:19:42 notifier.go:1463: [WARN] notifier disabled (no hub configured): DROPPED event app_unexplained_upload (severity warning) — further app_unexplained_upload events are logged at DEBUG only
2026/10/23 20:25:41 watch.go:378: [INFO] [upwatch] plex: the unexplained CPU stopped (15 min below the trigger or explained) — cleared
2026/10/23 20:25:41 notifier.go:1463: [WARN] notifier disabled (no hub configured): DROPPED event app_unexplained_cpu_cleared (severity info) — further app_unexplained_cpu_cleared events are logged at DEBUG only
2026/10/23 20:32:42 service.go:111: [INFO] [upwatch] qBittorrent's upload limit is the household's — the box leaves it alone from now on
2026/10/23 20:41:41 watch.go:370: [INFO] [upwatch] qbittorrent: the unexplained upload stopped (15 min below the trigger or explained) — cleared
2026/10/23 20:41:41 notifier.go:1463: [WARN] notifier disabled (no hub configured): DROPPED event app_unexplained_upload_cleared (severity info) — further app_unexplained_upload_cleared events are logged at DEBUG only
@@ -0,0 +1,2 @@
/settings 56743 data-uplink> <span class="settings-label">Feltöltési sebesség</span> <span class="settings-value">legalább <span class="mono">40</span> Mbit/s (az éjszakai távoli mentésből mérve)</span> </div> | qb line: none
/apps/qbittorrent 49281 no uplink row | qb line: none
@@ -0,0 +1,4 @@
version v5.2.4 webapi 2.15.1
transfer/info {'connection_status': 'connected', 'dht_nodes': 375, 'dl_info_data': 0, 'dl_info_speed': 0, 'dl_rate_limit': 0, 'last_external_address_v4': '37.191.56.193', 'last_external_address_v6': '', 'up_info_data': 5566595787, 'up_info_speed': 0, 'up_rate_limit': 1499136}
prefs {'up_limit': 1499136, 'dl_limit': 0, 'alt_up_limit': 10240, 'alt_dl_limit': 10240, 'scheduler_enabled': False, 'limit_tcp_overhead': False, 'limit_lan_peers': True, 'limit_utp_rate': True, 'max_uploads': 20, 'enable_upload_suggestions': False}
uploadLimit 1499136 speedLimitsMode 0
@@ -0,0 +1,186 @@
=== demo-hp: 2026-09-23 02:00 -> 2026-10-23 18:09 UTC (30.7 d), 998216 rows
container n tx p50 p95 max Mbit/s | cpu p50 p95 max %core | notes
qbittorrent 18 0.019 1.199 4.01 | 0.4 5.4 11.3 |
metube 3 0.146 0.146 0.15 | 0.0 0.1 0.1 |
immich-server 318 0.031 0.133 242.93 | 0.1 5.6 138.1 | resets=7
grimmory-db 102 0.000 0.116 0.35 | 0.0 16.9 102.5 | resets=12
immich-postgres 320 0.000 0.066 2.20 | 0.0 8.7 70.2 | resets=7
grimmory 94 0.001 0.047 0.77 | 1.1 272.0 305.0 | resets=9
immich-redis 320 0.013 0.029 0.18 | 0.6 4.3 5.1 | resets=7
romm 26492 0.019 0.027 0.20 | 0.7 3.2 442.4 | resets=97
docmost 43499 0.013 0.027 0.23 | 0.1 0.8 158.1 | resets=147
rallly 71 0.000 0.017 0.12 | 0.0 8.5 152.1 | resets=10
radarr 16 0.002 0.015 0.03 | 0.2 7.2 11.8 |
romm-redis 26523 0.005 0.013 0.10 | 0.7 4.4 61.5 | resets=101
paperless-webserver 43488 0.005 0.013 0.04 | 0.1 0.3 404.2 | resets=144
nextcloud-db 663 0.001 0.013 1.74 | 0.0 6.1 71.8 | resets=11
docmost-redis 43532 0.005 0.013 0.13 | 0.7 4.4 6.6 | resets=147
cloudflared 43604 0.000 0.013 1.21 | 0.3 0.5 13.8 | resets=6
rallly-postgres 71 0.000 0.007 0.01 | 0.0 5.0 8.8 | resets=7
prowlarr 5 0.002 0.004 0.00 | 0.1 0.2 0.2 |
sonarr 18 0.000 0.004 0.01 | 2.5 8.2 8.8 |
felhom-controller 43608 0.000 0.003 17.79 | 1.0 57.9 251.4 | resets=133
paperless-redis 43521 0.001 0.003 0.02 | 0.6 4.3 6.1 | resets=148
bentopdf 43567 0.000 0.003 0.01 | 0.0 0.0 5.2 | resets=58
homepage 78 0.000 0.002 0.01 | 0.0 4.2 4.5 | resets=1
bookstack-db 43565 0.001 0.001 0.01 | 0.0 6.1 102.8 | resets=147
romm-db 26526 0.000 0.001 0.19 | 0.0 6.0 105.3 | resets=89
plex 11974 0.001 0.001 1.10 | 0.3 0.6 124.6 | resets=46
nextcloud 662 0.000 0.001 0.80 | 0.0 5.7 150.0 | resets=11
immich-machine-learning 320 0.000 0.001 0.39 | 0.2 32.0 548.0 | resets=7
docmost-postgres 43533 0.000 0.001 0.02 | 0.0 4.7 29.6 | resets=147
bookstack 43546 0.000 0.001 0.01 | 0.0 0.0 63.0 | resets=148
adventurelog-postgres 43567 0.000 0.001 1.35 | 0.0 4.7 37.9 | resets=138
adventurelog 43549 0.000 0.001 2.16 | 0.0 0.7 204.3 | resets=146
ghost 20 0.000 0.001 0.00 | 0.0 6.8 132.9 | resets=2
glance 20 0.000 0.001 0.00 | 0.0 0.0 0.0 | resets=2
privatebin 43518 0.000 0.001 0.00 | 0.1 0.1 8.1 | resets=140
paperless-postgres 43520 0.000 0.001 0.05 | 0.0 4.7 19.1 | resets=148
kimai 30136 0.000 0.000 0.00 | 0.0 0.0 107.2 | resets=102
home-assistant 14403 0.000 0.000 1.00 | 0.0 0.5 106.9 | resets=62
kimai-db 30150 0.000 0.000 0.05 | 0.0 5.9 100.8 | resets=96
adventurelog-frontend 43559 0.000 0.000 0.21 | 0.0 3.8 22.8 | resets=126
vaultwarden 329 0.000 0.000 0.00 | 0.0 0.1 4.0 | resets=7
calibre-web 43547 0.000 0.000 0.01 | 0.0 0.3 127.1 | resets=145
opengist 43530 0.000 0.000 0.01 | 0.0 0.0 9.8 | resets=140
jellyfin 297 0.000 0.000 5.87 | 0.0 4.4 160.5 | resets=7
vikunja 8 0.000 0.000 0.00 | 0.0 0.0 0.0 | resets=2
a1-echo 113 0.000 0.000 0.00 | 0.0 0.0 0.0 |
upbeat_perlman 1 0.000 0.000 0.00 | 31.2 31.2 31.2 |
traefik 43608 0.000 0.000 1.21 | 0.1 3.5 92.1 | resets=11
practical_johnson 1 0.000 0.000 0.00 | 9.9 9.9 9.9 |
peaceful_ptolemy 1 0.000 0.000 0.00 | 14.1 14.1 14.1 |
nextcloud-redis 663 0.000 0.000 0.03 | 0.6 4.1 7.9 | resets=5
friendly_wilbur 1 0.000 0.000 0.00 | 59.0 59.0 59.0 |
filebrowser 43607 0.000 0.000 0.74 | 0.0 0.0 35.1 | resets=17
felhom-samba 10 0.000 0.000 0.00 | 0.0 13.5 17.6 | tx counter always 0 (host network?)
determined_satoshi 1 0.000 0.000 0.00 | 17.4 17.4 17.4 |
busiest UTC hours by bytes sent: 03h 14%, 02h 7%, 13h 5%, 00h 4%
=== demo-felhom: 2026-09-23 02:00 -> 2026-10-23 18:08 UTC (30.7 d), 268120 rows
container n tx p50 p95 max Mbit/s | cpu p50 p95 max %core | notes
immich-server 32 0.667 5.953 12.90 | 0.6 120.1 130.8 |
jellyfin 16 0.000 0.854 2.85 | 0.0 72.7 290.7 |
immich-postgres 32 0.000 0.766 2.24 | 0.3 8.5 197.6 |
romm 16 0.020 0.339 1.07 | 0.5 25.5 100.5 |
dawarich 20 0.000 0.313 3.01 | 0.1 5.3 104.4 |
immich-machine-learning 32 0.003 0.243 0.42 | 0.2 294.7 295.7 |
immich-redis 32 0.017 0.144 0.16 | 0.5 3.9 4.2 |
nextcloud-db 16 0.000 0.137 0.43 | 0.0 4.9 5.8 |
nextcloud 16 0.000 0.099 0.33 | 0.0 21.7 86.7 |
paperless-webserver 21 0.005 0.073 0.08 | 0.0 137.4 139.7 |
paperless-postgres 22 0.000 0.048 0.06 | 0.0 4.6 5.0 |
kimai-db 19 0.000 0.023 0.15 | 0.0 8.4 38.8 |
dawarich-sidekiq 19 0.020 0.023 0.02 | 0.1 0.2 0.2 |
claper 20 0.019 0.020 0.02 | 0.5 0.7 0.9 |
docmost 22 0.020 0.020 0.02 | 0.0 0.2 0.3 |
wanderer 19 0.002 0.015 0.02 | 0.0 0.0 0.0 |
cloudflared 43863 0.000 0.013 1.33 | 0.2 0.3 8.3 | resets=11
adventurelog 22 0.000 0.013 3.24 | 0.0 0.1 65.8 |
grafana 20 0.000 0.012 0.12 | 1.0 1.9 17.3 |
wanderer-db 19 0.007 0.011 0.01 | 0.0 3.7 3.7 |
dawarich-redis 20 0.009 0.011 0.01 | 0.4 3.7 3.8 |
claper-postgres 20 0.011 0.011 0.01 | 0.2 0.5 4.4 |
outline 19 0.008 0.008 0.01 | 0.0 7.4 7.7 |
nextcloud-redis 16 0.000 0.008 0.02 | 0.4 0.7 1.4 |
romm-redis 16 0.006 0.007 0.01 | 0.5 3.7 3.8 |
docmost-redis 23 0.005 0.005 0.07 | 0.4 0.7 3.9 |
dawarich-db 20 0.001 0.005 0.03 | 0.0 0.1 0.1 |
bookstack-db 20 0.001 0.005 0.04 | 0.0 4.7 4.8 |
grocy 19 0.000 0.005 0.01 | 0.0 0.0 0.0 |
bookstack 20 0.000 0.005 0.04 | 0.0 7.9 47.2 |
zipline 20 0.003 0.003 0.00 | 0.0 0.0 0.0 |
paperless-redis 22 0.002 0.003 0.00 | 0.4 0.4 0.4 |
outline-redis 19 0.003 0.003 0.00 | 0.4 0.4 0.5 |
kimai 19 0.000 0.003 0.02 | 0.0 2.4 24.3 |
zipline-postgres 20 0.003 0.003 0.00 | 0.0 0.0 0.0 |
qbittorrent 11759 0.001 0.003 0.01 | 0.1 0.2 97.5 | resets=25
felhom-controller 43863 0.000 0.003 1.73 | 0.1 15.5 122.0 | resets=92
bentopdf 18 0.000 0.002 0.00 | 0.0 0.0 0.0 |
emby 19 0.001 0.002 0.01 | 0.0 0.1 0.1 |
homepage 20 0.000 0.002 0.00 | 0.0 0.0 0.0 |
sonarr 11756 0.000 0.001 0.01 | 0.1 0.3 74.7 | resets=25
grimmory-db 24 0.000 0.001 0.35 | 0.0 5.0 100.2 |
grimmory 23 0.001 0.001 0.00 | 5.7 25.3 35.0 |
lubelogger 19 0.000 0.001 0.00 | 0.0 0.2 0.6 |
radarr 11756 0.000 0.001 0.17 | 0.0 0.6 79.9 | resets=25
glance 19 0.000 0.001 0.00 | 0.0 0.0 0.0 |
metube 20 0.000 0.001 0.00 | 0.0 1.3 26.1 |
actualbudget 18 0.000 0.001 0.00 | 0.0 0.0 0.0 |
privatebin 19 0.000 0.001 0.00 | 0.0 0.0 0.0 |
plex 18 0.000 0.001 0.00 | 0.7 0.8 0.8 |
papra 20 0.000 0.001 0.00 | 0.0 6.8 7.5 |
home-assistant 16 0.000 0.001 0.00 | 0.0 19.8 79.0 |
wanderer-search 19 0.000 0.001 0.00 | 0.1 0.1 0.1 |
karakeep 19 0.001 0.001 0.00 | 1.8 2.0 2.0 |
romm-db 16 0.001 0.001 0.00 | 0.0 4.6 4.7 |
radicale 19 0.000 0.001 0.00 | 0.0 0.0 0.0 |
gramps-web 20 0.000 0.001 0.00 | 0.0 0.0 0.0 |
tandoor 19 0.000 0.001 0.00 | 0.1 4.7 4.8 |
karakeep-chrome 19 0.001 0.001 0.00 | 0.0 0.0 0.0 |
outline-postgres 19 0.000 0.001 0.00 | 0.0 0.4 0.7 |
seerr 18 0.000 0.001 0.00 | 0.0 0.0 0.0 |
n8n 22 0.000 0.000 0.00 | 0.8 1.0 110.6 |
termix 20 0.000 0.000 0.00 | 0.0 0.4 2.3 |
tandoor-postgres 19 0.000 0.000 0.00 | 0.4 1.5 4.1 |
audiobookshelf 19 0.000 0.000 0.00 | 0.0 0.0 0.1 |
adventurelog-postgres 22 0.000 0.000 0.02 | 0.0 3.8 33.6 |
ghost 21 0.000 0.000 0.00 | 0.0 0.0 0.0 |
transmission 19 0.000 0.000 0.00 | 0.1 0.1 0.1 |
komga 19 0.000 0.000 0.00 | 0.3 6.8 10.6 |
calcom 18 0.000 0.000 0.00 | 0.0 3.4 22.3 |
vaultwarden 20 0.000 0.000 0.00 | 0.0 0.0 0.0 |
sparkyfitness 19 0.000 0.000 0.00 | 0.0 0.0 0.0 |
homebox 19 0.000 0.000 0.00 | 0.1 0.2 0.2 |
docmost-postgres 23 0.000 0.000 0.01 | 0.0 3.8 73.9 |
vikunja 19 0.000 0.000 0.00 | 0.0 0.0 0.0 |
adventurelog-frontend 22 0.000 0.000 0.00 | 0.0 0.0 0.0 |
rallly 20 0.000 0.000 0.00 | 0.0 5.6 110.3 |
calibre-web 17 0.000 0.000 0.00 | 0.0 21.3 106.4 |
wishlist 20 0.000 0.000 0.00 | 0.0 6.3 125.1 |
prowlarr 11738 0.000 0.000 0.00 | 0.0 0.1 77.0 | resets=26
opengist 43862 0.000 0.000 0.01 | 0.0 0.0 6.0 | resets=107
onlyoffice 22 0.000 0.000 0.00 | 0.0 130.5 147.5 |
sabnzbd 19 0.000 0.000 0.00 | 0.0 0.0 0.0 |
gitea 19 0.000 0.000 0.00 | 0.0 0.4 4.0 |
navidrome 19 0.000 0.000 0.00 | 0.1 0.1 0.1 |
code-server 20 0.000 0.000 0.00 | 0.0 0.0 0.0 |
uptime-kuma 19 0.000 0.000 0.00 | 0.7 0.7 0.7 |
nzbget 19 0.000 0.000 0.00 | 0.0 0.0 0.0 |
gokapi 19 0.000 0.000 0.00 | 0.0 0.0 0.0 |
recipe-importer 20 0.000 0.000 0.00 | 0.0 0.0 0.0 |
crafty-controller 19 0.000 0.000 0.00 | 0.1 8.3 8.5 |
mealie 20 0.000 0.000 0.00 | 0.1 0.1 0.1 |
rallly-postgres 20 0.000 0.000 0.00 | 0.0 3.7 3.8 |
traefik 43863 0.000 0.000 0.96 | 0.0 3.6 17.9 | resets=13
sparkyfitness-server 19 0.000 0.000 0.00 | 0.1 0.1 0.1 |
sparkyfitness-db 19 0.000 0.000 0.00 | 0.0 3.8 3.8 |
karakeep-meilisearch 19 0.000 0.000 0.00 | 0.1 0.1 0.1 |
filebrowser 43863 0.000 0.000 0.74 | 0.0 0.0 15.7 | resets=16
calcom-postgres 18 0.000 0.000 0.00 | 0.0 3.9 4.0 |
busiest UTC hours by bytes sent: 16h 16%, 05h 12%, 09h 6%, 02h 5%
=== tester-1: 2026-10-04 19:41 -> 2026-10-23 18:08 UTC (18.9 d), 294433 rows
container n tx p50 p95 max Mbit/s | cpu p50 p95 max %core | notes
qbittorrent 3857 0.007 0.133 42.40 | 0.1 2.6 92.3 | resets=20
transmission 3857 0.001 0.013 57.43 | 0.1 1.6 82.5 | resets=19
paperless-webserver 26710 0.005 0.013 0.09 | 0.1 0.7 508.1 | resets=63
cloudflared 26751 0.000 0.013 1.63 | 0.4 1.2 29.4 | resets=6
prowlarr 3725 0.000 0.012 0.26 | 0.1 0.3 101.8 | resets=8
sonarr 3855 0.001 0.004 1.21 | 0.1 4.5 131.6 | resets=20
radarr 3855 0.001 0.003 1.52 | 0.1 4.3 103.3 | resets=19
paperless-redis 26740 0.001 0.003 0.01 | 0.7 4.2 27.5 | resets=68
felhom-controller 26751 0.000 0.003 37.47 | 0.5 46.4 422.6 | resets=62
plex 3739 0.001 0.002 1.07 | 0.3 4.3 198.4 | resets=17
bookstack-db 26729 0.001 0.001 0.03 | 0.0 5.7 130.6 | resets=66
plex-k6 514 0.001 0.001 0.01 | 0.4 5.4 7.2 |
bookstack 26722 0.000 0.001 0.04 | 0.0 0.1 72.5 | resets=65
privatebin 26744 0.000 0.001 0.00 | 0.0 0.1 14.7 | resets=64
paperless-postgres 26740 0.000 0.001 0.02 | 0.0 4.4 65.8 | resets=68
traefik 26751 0.000 0.000 1.56 | 0.0 3.4 100.6 | resets=3
jellyfin 3648 0.000 0.000 2.83 | 0.0 0.2 181.5 | resets=19
xfp-echo 1 0.000 0.000 0.00 | 0.0 0.0 0.0 |
vaultwarden 1 0.000 0.000 0.00 | 0.0 0.0 0.0 |
filebrowser 26743 0.000 0.000 0.01 | 0.0 0.0 80.1 | resets=22
busiest UTC hours by bytes sent: 07h 13%, 18h 11%, 02h 9%, 17h 9%
@@ -0,0 +1,22 @@
== demo-hp
container cpu>=80% cpu>=150% (at) tx>=1Mbit tx>=5Mbit (at) [longest run, minutes]
kimai 13 0 (-) 0 0 (-)
paperless-webserver 6 1 (09-23 04:56) 0 0 (-)
immich-machine-learning 4 4 (10-14 00:54) 0 0 (-)
romm 3 2 (10-23 15:36) 0 0 (-)
adventurelog 2 1 (09-30 11:29) 3 0 (-)
adventurelog-postgres 0 0 (-) 3 0 (-)
felhom-controller 3 1 (09-23 11:37) 2 2 (09-28 13:44)
immich-server 2 0 (-) 3 2 (10-14 00:53)
== demo-felhom
container cpu>=80% cpu>=150% (at) tx>=1Mbit tx>=5Mbit (at) [longest run, minutes]
immich-server 2 0 (-) 8 1 (10-13 05:32)
immich-machine-learning 7 7 (10-13 16:39) 0 0 (-)
paperless-webserver 6 0 (-) 0 0 (-)
onlyoffice 4 0 (-) 0 0 (-)
== tester-1
container cpu>=80% cpu>=150% (at) tx>=1Mbit tx>=5Mbit (at) [longest run, minutes]
plex 10 5 (10-14 17:20) 1 0 (-)
qbittorrent 2 0 (-) 9 3 (10-14 18:08)
sonarr 9 0 (-) 2 0 (-)
transmission 1 0 (-) 6 2 (10-16 07:17)
@@ -0,0 +1,90 @@
== demo-hp: per UTC day — max 1-min, best 5-min mean, minutes above 5 Mbit/s, hour of the peak
2026-09-23 max1= 3.14 best5= 0.91 busy_min= 0 peak_at=02:17Z
2026-09-24 max1= 3.04 best5= 0.73 busy_min= 0 peak_at=02:17Z
2026-09-25 max1= 2.13 best5= 0.67 busy_min= 0 peak_at=02:18Z
2026-09-26 max1= 1.77 best5= 0.63 busy_min= 0 peak_at=02:18Z
2026-09-27 max1= 2.04 best5= 0.75 busy_min= 0 peak_at=02:18Z
2026-09-28 max1= 17.79 best5= 6.89 busy_min= 3 peak_at=13:43Z
2026-09-29 max1= 2.45 best5= 0.65 busy_min= 0 peak_at=02:17Z
2026-09-30 max1= 2.62 best5= 0.76 busy_min= 0 peak_at=02:18Z
2026-10-01 max1= 1.02 best5= 0.54 busy_min= 0 peak_at=02:18Z
2026-10-02 max1= 2.02 best5= 0.62 busy_min= 0 peak_at=02:18Z
2026-10-03 max1= 2.01 best5= 0.60 busy_min= 0 peak_at=15:25Z
2026-10-04 max1= 2.08 best5= 0.42 busy_min= 0 peak_at=02:17Z
2026-10-05 max1= 2.36 best5= 0.48 busy_min= 0 peak_at=05:26Z
2026-10-06 max1= 1.58 best5= 0.32 busy_min= 0 peak_at=02:17Z
2026-10-07 max1= 1.05 best5= 0.30 busy_min= 0 peak_at=02:16Z
2026-10-08 max1= 1.43 best5= 0.29 busy_min= 0 peak_at=02:17Z
2026-10-09 max1= 1.47 best5= 0.29 busy_min= 0 peak_at=02:17Z
2026-10-10 max1= 0.90 best5= 0.27 busy_min= 0 peak_at=02:16Z
2026-10-11 max1= 1.34 best5= 0.30 busy_min= 0 peak_at=02:16Z
2026-10-12 max1= 4.96 best5= 0.99 busy_min= 0 peak_at=02:17Z
2026-10-13 max1= 1.31 best5= 0.28 busy_min= 0 peak_at=02:16Z
2026-10-14 max1= 6.31 best5= 1.27 busy_min= 1 peak_at=02:18Z
2026-10-15 max1= 2.25 best5= 0.45 busy_min= 0 peak_at=02:17Z
2026-10-16 max1= 2.78 best5= 0.66 busy_min= 0 peak_at=20:55Z
2026-10-17 max1= 2.26 best5= 0.45 busy_min= 0 peak_at=02:17Z
2026-10-18 max1= 2.08 best5= 0.47 busy_min= 0 peak_at=02:18Z
2026-10-19 max1= 16.95 best5= 5.08 busy_min= 2 peak_at=02:18Z
2026-10-20 max1= 1.20 best5= 0.48 busy_min= 0 peak_at=02:17Z
2026-10-21 max1= 2.27 best5= 0.46 busy_min= 0 peak_at=02:18Z
2026-10-22 max1= 2.13 best5= 0.52 busy_min= 0 peak_at=02:18Z
2026-10-23 max1= 1.37 best5= 0.48 busy_min= 0 peak_at=02:18Z
nights with a push (best5>2): 2; best5 min/median/max = 5.1/6.9/6.9 Mbit/s
== demo-felhom: per UTC day — max 1-min, best 5-min mean, minutes above 5 Mbit/s, hour of the peak
2026-09-23 max1= 0.05 best5= 0.01 busy_min= 0 peak_at=02:15Z
2026-09-24 max1= 0.06 best5= 0.01 busy_min= 0 peak_at=02:15Z
2026-09-25 max1= 0.04 best5= 0.01 busy_min= 0 peak_at=02:16Z
2026-09-26 max1= 0.04 best5= 0.01 busy_min= 0 peak_at=02:16Z
2026-09-27 max1= 0.01 best5= 0.00 busy_min= 0 peak_at=00:19Z
2026-09-28 max1= 0.03 best5= 0.01 busy_min= 0 peak_at=02:16Z
2026-09-29 max1= 0.03 best5= 0.01 busy_min= 0 peak_at=02:15Z
2026-09-30 max1= 0.04 best5= 0.01 busy_min= 0 peak_at=02:16Z
2026-10-01 max1= 0.07 best5= 0.01 busy_min= 0 peak_at=19:54Z
2026-10-02 max1= 0.04 best5= 0.01 busy_min= 0 peak_at=02:16Z
2026-10-03 max1= 0.05 best5= 0.01 busy_min= 0 peak_at=02:16Z
2026-10-04 max1= 0.02 best5= 0.00 busy_min= 0 peak_at=06:58Z
2026-10-05 max1= 0.05 best5= 0.01 busy_min= 0 peak_at=05:21Z
2026-10-06 max1= 0.01 best5= 0.00 busy_min= 0 peak_at=17:34Z
2026-10-07 max1= 0.01 best5= 0.00 busy_min= 0 peak_at=02:15Z
2026-10-08 max1= 0.09 best5= 0.02 busy_min= 0 peak_at=13:04Z
2026-10-09 max1= 0.10 best5= 0.02 busy_min= 0 peak_at=05:34Z
2026-10-10 max1= 0.01 best5= 0.00 busy_min= 0 peak_at=02:15Z
2026-10-11 max1= 0.04 best5= 0.01 busy_min= 0 peak_at=10:46Z
2026-10-12 max1= 0.08 best5= 0.02 busy_min= 0 peak_at=06:18Z
2026-10-13 max1= 0.05 best5= 0.01 busy_min= 0 peak_at=13:54Z
2026-10-14 max1= 0.07 best5= 0.02 busy_min= 0 peak_at=07:59Z
2026-10-15 max1= 0.14 best5= 0.03 busy_min= 0 peak_at=14:25Z
2026-10-16 max1= 0.84 best5= 0.17 busy_min= 0 peak_at=02:15Z
2026-10-17 max1= 0.49 best5= 0.10 busy_min= 0 peak_at=02:15Z
2026-10-18 max1= 0.33 best5= 0.07 busy_min= 0 peak_at=02:16Z
2026-10-19 max1= 1.73 best5= 0.35 busy_min= 0 peak_at=02:16Z
2026-10-20 max1= 0.23 best5= 0.07 busy_min= 0 peak_at=02:16Z
2026-10-21 max1= 0.36 best5= 0.07 busy_min= 0 peak_at=02:16Z
2026-10-22 max1= 0.52 best5= 0.11 busy_min= 0 peak_at=02:15Z
2026-10-23 max1= 0.48 best5= 0.10 busy_min= 0 peak_at=02:15Z
== tester-1: per UTC day — max 1-min, best 5-min mean, minutes above 5 Mbit/s, hour of the peak
2026-10-04 max1= 0.17 best5= 0.14 busy_min= 0 peak_at=19:55Z
2026-10-05 max1= 1.44 best5= 0.29 busy_min= 0 peak_at=03:10Z
2026-10-06 max1= 0.64 best5= 0.13 busy_min= 0 peak_at=02:16Z
2026-10-07 max1= 0.64 best5= 0.13 busy_min= 0 peak_at=02:15Z
2026-10-08 max1= 0.42 best5= 0.08 busy_min= 0 peak_at=02:16Z
2026-10-09 max1= 0.48 best5= 0.10 busy_min= 0 peak_at=02:16Z
2026-10-10 max1= 0.84 best5= 0.17 busy_min= 0 peak_at=02:16Z
2026-10-11 max1= 0.46 best5= 0.09 busy_min= 0 peak_at=02:15Z
2026-10-12 max1= 1.71 best5= 0.34 busy_min= 0 peak_at=02:16Z
2026-10-13 max1= 0.99 best5= 0.20 busy_min= 0 peak_at=02:15Z
2026-10-14 max1= 0.45 best5= 0.09 busy_min= 0 peak_at=02:16Z
2026-10-15 max1= 37.47 best5= 7.58 busy_min= 1 peak_at=02:17Z
2026-10-16 max1= 3.85 best5= 0.77 busy_min= 0 peak_at=02:17Z
2026-10-17 max1= 5.11 best5= 1.21 busy_min= 1 peak_at=02:16Z
2026-10-18 max1= 0.50 best5= 0.10 busy_min= 0 peak_at=02:16Z
2026-10-19 max1= 5.14 best5= 1.03 busy_min= 1 peak_at=02:16Z
2026-10-20 max1= 0.52 best5= 0.10 busy_min= 0 peak_at=02:16Z
2026-10-21 max1= 0.61 best5= 0.12 busy_min= 0 peak_at=02:16Z
2026-10-22 max1= 0.53 best5= 0.11 busy_min= 0 peak_at=02:16Z
2026-10-23 max1= 0.80 best5= 0.18 busy_min= 0 peak_at=02:16Z
nights with a push (best5>2): 1; best5 min/median/max = 7.6/7.6/7.6 Mbit/s
@@ -0,0 +1,6 @@
login 204 cookie
{"t": 0.2, "qb_up_speed": 0, "qb_up_data": 197886667, "qb_tor_uploaded": 1660504484, "proc_tx": 65136369198, "engine_tx": 65136367684, "cli": "65.5MB / 65.1GB"}
{"t": 6.5, "qb_up_speed": 0, "qb_up_data": 197886667, "qb_tor_uploaded": 1660504484, "proc_tx": 65152041285, "engine_tx": 65152039771, "cli": "65.9MB / 65.2GB", "rate_qb_data_Mbit": 0.0, "rate_proc_Mbit": 19.9, "rate_engine_Mbit": 19.9}
{"t": 12.7, "qb_up_speed": 0, "qb_up_data": 197886667, "qb_tor_uploaded": 1660504484, "proc_tx": 65167646902, "engine_tx": 65167645388, "cli": "66.2MB / 65.2GB", "rate_qb_data_Mbit": 0.0, "rate_proc_Mbit": 20.14, "rate_engine_Mbit": 20.14}
{"t": 19.0, "qb_up_speed": 0, "qb_up_data": 197886667, "qb_tor_uploaded": 1660504484, "proc_tx": 65183320503, "engine_tx": 65183318989, "cli": "66.6MB / 65.2GB", "rate_qb_data_Mbit": 0.0, "rate_proc_Mbit": 19.9, "rate_engine_Mbit": 19.9}
{"t": 25.2, "qb_up_speed": 0, "qb_up_data": 197886667, "qb_tor_uploaded": 1660504484, "proc_tx": 65198925974, "engine_tx": 65198924460, "cli": "66.9MB / 65.2GB", "rate_qb_data_Mbit": 0.0, "rate_proc_Mbit": 20.14, "rate_engine_Mbit": 20.14}
@@ -0,0 +1,10 @@
LISTEN 0 5 0.0.0.0:5001 0.0.0.0:*
login 204 cookie
{"t": 0.0, "qb_up_speed": 0, "qb_up_data": 0, "qb_tor_uploaded": 1462617817, "proc_tx": 1559315619, "engine_tx": 1558369279, "cli": "2.94MB / 2.85GB"}
{"t": 6.0, "qb_up_speed": 0, "qb_up_data": 0, "qb_tor_uploaded": 1462617817, "proc_tx": 9161893432, "engine_tx": 9161333668, "cli": "9.34MB / 10.5GB", "rate_qb_data_Mbit": 0.0, "rate_proc_Mbit": 10136.77, "rate_engine_Mbit": 10137.29}
{"t": 12.1, "qb_up_speed": 0, "qb_up_data": 0, "qb_tor_uploaded": 1462617817, "proc_tx": 17020963755, "engine_tx": 17019975365, "cli": "16.7MB / 18.7GB", "rate_qb_data_Mbit": 0.0, "rate_proc_Mbit": 10306.98, "rate_engine_Mbit": 10306.42}
{"t": 18.1, "qb_up_speed": 0, "qb_up_data": 0, "qb_tor_uploaded": 1462617817, "proc_tx": 25140960556, "engine_tx": 25139940620, "cli": "23.6MB / 26.5GB", "rate_qb_data_Mbit": 0.0, "rate_proc_Mbit": 10826.66, "rate_engine_Mbit": 10826.62}
{"t": 24.2, "qb_up_speed": 0, "qb_up_data": 0, "qb_tor_uploaded": 1462617817, "proc_tx": 33049634829, "engine_tx": 33048966257, "cli": "30.6MB / 34.4GB", "rate_qb_data_Mbit": 0.0, "rate_proc_Mbit": 10372.03, "rate_engine_Mbit": 10372.49}
{"t": 30.2, "qb_up_speed": 0, "qb_up_data": 0, "qb_tor_uploaded": 1462617817, "proc_tx": 41055773948, "engine_tx": 41055105508, "cli": "37.6MB / 42.3GB", "rate_qb_data_Mbit": 0.0, "rate_proc_Mbit": 10674.85, "rate_engine_Mbit": 10674.85}
{"t": 36.3, "qb_up_speed": 0, "qb_up_data": 0, "qb_tor_uploaded": 1462617817, "proc_tx": 48735514801, "engine_tx": 48734576785, "cli": "44.3MB / 50GB", "rate_qb_data_Mbit": 0.0, "rate_proc_Mbit": 10071.79, "rate_engine_Mbit": 10071.44}
{"t": 42.3, "qb_up_speed": 0, "qb_up_data": 0, "qb_tor_uploaded": 1462617817, "proc_tx": 56370706217, "engine_tx": 56370119481, "cli": "52.4MB / 58.8GB", "rate_qb_data_Mbit": 0.0, "rate_proc_Mbit": 10180.26, "rate_engine_Mbit": 10180.72}
@@ -0,0 +1,9 @@
login 204 cookie
setUploadLimit (200, '')
uploadLimit now 2499584 prefs.up_limit 2499584
login 204 cookie
{"t": 0.0, "qb_up_speed": 16386315, "qb_up_data": 1346633728, "qb_tor_uploaded": 1346633728, "proc_tx": 1422747831, "engine_tx": 1422747831, "cli": "27.2MB / 1.42GB"}
{"t": 6.0, "qb_up_speed": 0, "qb_up_data": 1374387364, "qb_tor_uploaded": 1374387364, "proc_tx": 1434635707, "engine_tx": 1434635707, "cli": "27.6MB / 1.44GB", "rate_qb_data_Mbit": 37.0, "rate_proc_Mbit": 15.85, "rate_engine_Mbit": 15.85}
{"t": 12.1, "qb_up_speed": 2872275, "qb_up_data": 1392093322, "qb_tor_uploaded": 1391692420, "proc_tx": 1457229455, "engine_tx": 1457229455, "cli": "27.9MB / 1.46GB", "rate_qb_data_Mbit": 23.22, "rate_proc_Mbit": 29.63, "rate_engine_Mbit": 29.63}
{"t": 18.1, "qb_up_speed": 1975559, "qb_up_data": 1406540742, "qb_tor_uploaded": 1406540742, "proc_tx": 1471460371, "engine_tx": 1471460371, "cli": "28.2MB / 1.47GB", "rate_qb_data_Mbit": 19.26, "rate_proc_Mbit": 18.97, "rate_engine_Mbit": 18.97}
{"t": 24.2, "qb_up_speed": 3254241, "qb_up_data": 1423113257, "qb_tor_uploaded": 1420865709, "proc_tx": 1488294067, "engine_tx": 1488294067, "cli": "28.5MB / 1.49GB", "rate_qb_data_Mbit": 21.73, "rate_proc_Mbit": 22.08, "rate_engine_Mbit": 22.08}
@@ -0,0 +1,11 @@
login 204 cookie
{"t": 0.0, "qb_up_speed": 16266049, "qb_up_data": 117833728, "qb_tor_uploaded": 117701484, "proc_tx": 123161204, "engine_tx": 123161204, "cli": "6.74MB / 140MB"}
{"t": 6.0, "qb_up_speed": 16384087, "qb_up_data": 216137728, "qb_tor_uploaded": 216137728, "proc_tx": 225760308, "engine_tx": 225760308, "cli": "8.38MB / 243MB", "rate_qb_data_Mbit": 131.07, "rate_proc_Mbit": 136.8, "rate_engine_Mbit": 136.8}
{"t": 12.1, "qb_up_speed": 16387266, "qb_up_data": 314441728, "qb_tor_uploaded": 314441728, "proc_tx": 328359626, "engine_tx": 328359626, "cli": "10.1MB / 346MB", "rate_qb_data_Mbit": 128.92, "rate_proc_Mbit": 134.56, "rate_engine_Mbit": 134.56}
{"t": 18.1, "qb_up_speed": 16391332, "qb_up_data": 412745728, "qb_tor_uploaded": 412745728, "proc_tx": 431576783, "engine_tx": 431540471, "cli": "11.8MB / 450MB", "rate_qb_data_Mbit": 131.07, "rate_proc_Mbit": 137.62, "rate_engine_Mbit": 137.57}
{"t": 24.2, "qb_up_speed": 16377743, "qb_up_data": 511049728, "qb_tor_uploaded": 511049728, "proc_tx": 536615588, "engine_tx": 536559607, "cli": "13.4MB / 556MB", "rate_qb_data_Mbit": 128.92, "rate_proc_Mbit": 137.76, "rate_engine_Mbit": 137.73}
{"t": 30.2, "qb_up_speed": 16387474, "qb_up_data": 609353728, "qb_tor_uploaded": 609353728, "proc_tx": 641957804, "engine_tx": 641903336, "cli": "14.9MB / 660MB", "rate_qb_data_Mbit": 131.07, "rate_proc_Mbit": 140.46, "rate_engine_Mbit": 140.46}
{"t": 36.3, "qb_up_speed": 16383934, "qb_up_data": 707657728, "qb_tor_uploaded": 707657728, "proc_tx": 746552576, "engine_tx": 746552576, "cli": "16.8MB / 764MB", "rate_qb_data_Mbit": 128.92, "rate_proc_Mbit": 137.17, "rate_engine_Mbit": 137.24}
{"t": 42.3, "qb_up_speed": 16392852, "qb_up_data": 805961728, "qb_tor_uploaded": 805961728, "proc_tx": 849903723, "engine_tx": 849903723, "cli": "18.3MB / 867MB", "rate_qb_data_Mbit": 131.07, "rate_proc_Mbit": 137.8, "rate_engine_Mbit": 137.8}
{"t": 48.4, "qb_up_speed": 16382132, "qb_up_data": 904265728, "qb_tor_uploaded": 904265728, "proc_tx": 952502020, "engine_tx": 952502020, "cli": "19.9MB / 970MB", "rate_qb_data_Mbit": 128.92, "rate_proc_Mbit": 134.56, "rate_engine_Mbit": 134.56}
{"t": 54.4, "qb_up_speed": 16376106, "qb_up_data": 1002569728, "qb_tor_uploaded": 1002569728, "proc_tx": 1055099637, "engine_tx": 1055099637, "cli": "21.5MB / 1.07GB", "rate_qb_data_Mbit": 131.07, "rate_proc_Mbit": 136.8, "rate_engine_Mbit": 136.8}
@@ -0,0 +1,8 @@
{'arguments': {}, 'result': 'success'}
{'speed-limit-up': 2500, 'speed-limit-up-enabled': True}
{"t": 0.0, "tr_upspeed": 0, "tr_cur_up": 2149187584, "tr_tor_up": 2149187584, "tx": 2157242728}
{"t": 5.0, "tr_upspeed": 0, "tr_cur_up": 2149187584, "tr_tor_up": 2149187584, "tx": 2157244479, "rate_tr_Mbit": 0.0, "rate_container_Mbit": 0.0}
{"t": 10.0, "tr_upspeed": 0, "tr_cur_up": 2149187584, "tr_tor_up": 2149187584, "tx": 2157246230, "rate_tr_Mbit": 0.0, "rate_container_Mbit": 0.0}
{"t": 15.0, "tr_upspeed": 0, "tr_cur_up": 2149187584, "tr_tor_up": 2149187584, "tx": 2157248133, "rate_tr_Mbit": 0.0, "rate_container_Mbit": 0.0}
{"t": 20.0, "tr_upspeed": 0, "tr_cur_up": 2149187584, "tr_tor_up": 2149187584, "tx": 2157249884, "rate_tr_Mbit": 0.0, "rate_container_Mbit": 0.0}
{"t": 25.0, "tr_upspeed": 0, "tr_cur_up": 2149187584, "tr_tor_up": 2149187584, "tx": 2157251635, "rate_tr_Mbit": 0.0, "rate_container_Mbit": 0.0}
@@ -0,0 +1,10 @@
{"t": 0.0, "tr_upspeed": 0, "tr_cur_up": 2149187584, "tr_tor_up": 2149187584, "tx": 2157256302}
{"t": 10.0, "tr_upspeed": 0, "tr_cur_up": 2149187584, "tr_tor_up": 2149187584, "tx": 2157258205, "rate_tr_Mbit": 0.0, "rate_container_Mbit": 0.0}
{"t": 20.0, "tr_upspeed": 0, "tr_cur_up": 2149187584, "tr_tor_up": 2149187584, "tx": 2157261594, "rate_tr_Mbit": 0.0, "rate_container_Mbit": 0.0}
{"t": 30.0, "tr_upspeed": 0, "tr_cur_up": 2149187584, "tr_tor_up": 2149187584, "tx": 2157263345, "rate_tr_Mbit": 0.0, "rate_container_Mbit": 0.0}
{"t": 40.0, "tr_upspeed": 0, "tr_cur_up": 2149187584, "tr_tor_up": 2149187584, "tx": 2157265096, "rate_tr_Mbit": 0.0, "rate_container_Mbit": 0.0}
{"t": 50.0, "tr_upspeed": 0, "tr_cur_up": 2149187584, "tr_tor_up": 2149187584, "tx": 2157268485, "rate_tr_Mbit": 0.0, "rate_container_Mbit": 0.0}
{"t": 60.0, "tr_upspeed": 0, "tr_cur_up": 2149187584, "tr_tor_up": 2149187584, "tx": 2157271188, "rate_tr_Mbit": 0.0, "rate_container_Mbit": 0.0}
{"t": 70.0, "tr_upspeed": 0, "tr_cur_up": 2149187584, "tr_tor_up": 2149187584, "tx": 2157272939, "rate_tr_Mbit": 0.0, "rate_container_Mbit": 0.0}
{"t": 80.0, "tr_upspeed": 0, "tr_cur_up": 2149187584, "tr_tor_up": 2149187584, "tx": 2157276328, "rate_tr_Mbit": 0.0, "rate_container_Mbit": 0.0}
{"t": 90.0, "tr_upspeed": 0, "tr_cur_up": 2149187584, "tr_tor_up": 2149187584, "tx": 2157278588, "rate_tr_Mbit": 0.0, "rate_container_Mbit": 0.0}
@@ -0,0 +1,15 @@
login 204 cookie
/api/v2/torrents/stop (200, '')
{'arguments': {}, 'result': 'success'}
{"t": 0.0, "tr_upspeed": 40648163, "tr_cur_up": 1528429958, "tr_tor_up": 1528429958, "tx": 1534546958}
{"t": 5.0, "tr_upspeed": 65588000, "tr_cur_up": 1832873057, "tr_tor_up": 1832873057, "tx": 1839315356, "rate_tr_Mbit": 487.11, "rate_container_Mbit": 487.63}
{"t": 10.0, "tr_upspeed": 23587084, "tr_cur_up": 2076811226, "tr_tor_up": 2076811226, "tx": 2083512878, "rate_tr_Mbit": 390.3, "rate_container_Mbit": 390.72}
{"t": 15.0, "tr_upspeed": 0, "tr_cur_up": 2149187584, "tr_tor_up": 2149187584, "tx": 2157213873, "rate_tr_Mbit": 115.8, "rate_container_Mbit": 117.92}
{"t": 20.0, "tr_upspeed": 0, "tr_cur_up": 2149187584, "tr_tor_up": 2149187584, "tx": 2157215624, "rate_tr_Mbit": 0.0, "rate_container_Mbit": 0.0}
{"t": 25.0, "tr_upspeed": 0, "tr_cur_up": 2149187584, "tr_tor_up": 2149187584, "tx": 2157218947, "rate_tr_Mbit": 0.0, "rate_container_Mbit": 0.01}
{"t": 30.0, "tr_upspeed": 0, "tr_cur_up": 2149187584, "tr_tor_up": 2149187584, "tx": 2157220698, "rate_tr_Mbit": 0.0, "rate_container_Mbit": 0.0}
{"t": 35.0, "tr_upspeed": 0, "tr_cur_up": 2149187584, "tr_tor_up": 2149187584, "tx": 2157222449, "rate_tr_Mbit": 0.0, "rate_container_Mbit": 0.0}
{"t": 40.0, "tr_upspeed": 0, "tr_cur_up": 2149187584, "tr_tor_up": 2149187584, "tx": 2157224200, "rate_tr_Mbit": 0.0, "rate_container_Mbit": 0.0}
{"t": 45.0, "tr_upspeed": 0, "tr_cur_up": 2149187584, "tr_tor_up": 2149187584, "tx": 2157225951, "rate_tr_Mbit": 0.0, "rate_container_Mbit": 0.0}
{"t": 50.0, "tr_upspeed": 0, "tr_cur_up": 2149187584, "tr_tor_up": 2149187584, "tx": 2157227702, "rate_tr_Mbit": 0.0, "rate_container_Mbit": 0.0}
{"t": 55.0, "tr_upspeed": 0, "tr_cur_up": 2149187584, "tr_tor_up": 2149187584, "tx": 2157231243, "rate_tr_Mbit": 0.0, "rate_container_Mbit": 0.01}
@@ -0,0 +1,2 @@
# usage: gen.sh <dir> ; writes <dir>/uwtest.bin, 2 GiB, identical on every machine (AES-CTR keystream of a fixed key)
mkdir -p "$1"; openssl enc -aes-128-ctr -nosalt -K 00112233445566778899aabbccddeeff -iv 0 -in /dev/zero 2>/dev/null | head -c 2147483648 > "$1/uwtest.bin"; sha256sum "$1/uwtest.bin" | cut -c1-16
@@ -0,0 +1,30 @@
import sqlite3,sys,collections,datetime,statistics
def pct(a,p):
if not a: return 0
a=sorted(a); k=(len(a)-1)*p/100; f=int(k); c=min(f+1,len(a)-1); return a[f]+(a[c]-a[f])*(k-f)
for box in sys.argv[1:]:
db=sqlite3.connect(f'file:{box}/metrics.db?mode=ro',uri=True)
lo,hi,n=db.execute('select min(ts),max(ts),count(*) from container_metrics').fetchone()
print(f'\n=== {box.rsplit("/",1)[1]}: {datetime.datetime.utcfromtimestamp(lo):%Y-%m-%d %H:%M} -> {datetime.datetime.utcfromtimestamp(hi):%Y-%m-%d %H:%M} UTC ({(hi-lo)/86400:.1f} d), {n} rows')
rows=collections.defaultdict(list)
for ts,name,cpu,tx in db.execute('select ts,container_name,cpu_percent,net_tx_bytes from container_metrics order by ts'):
rows[name].append((ts,cpu,tx))
hour=collections.defaultdict(float)
out=[]
for name,r in rows.items():
rates=[];resets=0;zero=all((x[2] or 0)==0 for x in r)
for (t0,_,a),(t1,_,b) in zip(r,r[1:]):
if a is None or b is None or t1-t0<=0 or t1-t0>180: continue
d=b-a
if d<0: resets+=1; continue
mbps=d*8/(t1-t0)/1e6; rates.append(mbps)
hour[datetime.datetime.utcfromtimestamp(t1).hour]+=d
cpus=[x[1] for x in r]
out.append((pct(rates,95),name,len(r),pct(rates,50),pct(rates,95),max(rates or [0]),pct(cpus,50),pct(cpus,95),max(cpus),zero,resets))
print(f'{"container":32} {"n":>6} {"tx p50":>8} {"p95":>8} {"max":>8} Mbit/s | {"cpu p50":>7} {"p95":>7} {"max":>7} %core | notes')
for o in sorted(out,reverse=True):
_,name,nn,a,b,c,d,e,f,zero,res=o
note=('tx counter always 0 (host network?)' if zero else '')+(f' resets={res}' if res else '')
print(f'{name[:32]:32} {nn:6} {a:8.3f} {b:8.3f} {c:8.2f} | {d:7.1f} {e:7.1f} {f:7.1f} | {note}')
tot=sum(hour.values()) or 1
print('busiest UTC hours by bytes sent:',', '.join(f'{h:02d}h {100*v/tot:.0f}%' for h,v in sorted(hour.items(),key=lambda x:-x[1])[:4]))
@@ -0,0 +1,21 @@
import sqlite3,sys,collections,datetime
for box in sys.argv[1:]:
db=sqlite3.connect(f'file:{box}/metrics.db?mode=ro',uri=True)
r=db.execute("select ts,net_tx_bytes from container_metrics where container_name='felhom-controller' order by ts").fetchall()
per=collections.defaultdict(list)
for (t0,a),(t1,b) in zip(r,r[1:]):
if a is None or b is None or b<a or not 0<t1-t0<=180: continue
d=datetime.datetime.utcfromtimestamp(t1)
per[d.date()].append((t1,(b-a)*8/(t1-t0)/1e6))
print(f'\n== {box.rsplit("/",1)[1]}: per UTC day — max 1-min, best 5-min mean, minutes above 5 Mbit/s, hour of the peak')
peaks=[]
for day in sorted(per):
v=per[day]; rates=[x[1] for x in v]
best5=max((sum(rates[i:i+5])/5 for i in range(max(1,len(rates)-4))),default=0)
m=max(v,key=lambda x:x[1])
busy=sum(1 for x in rates if x>5)
peaks.append(best5)
print(f'{day} max1={m[1]:6.2f} best5={best5:6.2f} busy_min={busy:4d} peak_at={datetime.datetime.utcfromtimestamp(m[0]):%H:%M}Z')
big=[p for p in peaks if p>2]
if big:
big.sort(); print(f'nights with a push (best5>2): {len(big)}; best5 min/median/max = {big[0]:.1f}/{big[len(big)//2]:.1f}/{big[-1]:.1f} Mbit/s')
@@ -0,0 +1,10 @@
#!/bin/bash
# Waits until 02:08Z on 2026-10-24, then reads the controller container's eth0 tx bytes once a second for 22 minutes on
# each of the three test boxes (read only: /proc/<pid>/net/dev inside guest 9201). Output: one file per box.
OUT=$1
target=$(date -u -d '2026-10-24T02:08:00Z' +%s); now=$(date -u +%s); [ $target -gt $now ] && sleep $((target-now))
INNER='P=$(docker inspect -f {{.State.Pid}} felhom-controller); end=$(( $(date +%s) + 1320 )); while [ $(date +%s) -lt $end ]; do echo "$(date +%s.%N | cut -c1-14) $(awk "/eth0:/{print \$10}" /proc/$P/net/dev)"; sleep 1; done'
for pair in "demo-hp:demo-hp" "felhom-pve:demo-felhom" "root@192.168.0.154:tester-1"; do h=${pair%%:*}; n=${pair##*:}
ssh -o BatchMode=yes -o ServerAliveInterval=30 $h "pct exec 9201 -- bash -c '$INNER'" > "$OUT/night-push-1s-$n.txt" 2>&1 &
done
wait; echo "done $(date -u +%FT%TZ)"
@@ -0,0 +1,89 @@
# Runs INSIDE guest 9202. Asks qBittorrent's own Web API and reads the container's exact byte counters.
# The admin password is read from the container env at use (as the controller does) and never printed.
import json, subprocess, sys, time, urllib.request, urllib.parse, http.client, socket, re, uuid
def sh(*a): return subprocess.run(a, capture_output=True, text=True).stdout.strip()
C = sys.argv[1] if len(sys.argv) > 1 else 'qbittorrent'
IP = sh('docker', 'inspect', '-f', '{{range .NetworkSettings.Networks}}{{.IPAddress}} {{end}}', C).split()[0]
PID = sh('docker', 'inspect', '-f', '{{.State.Pid}}', C)
CID = sh('docker', 'inspect', '-f', '{{.Id}}', C)
BASE = f'http://{IP}:8080'
PW = sh('docker', 'exec', C, 'printenv', 'QBT_ADMIN_PASSWORD')
def req(method, path, data=None, hdr=None, raw=False):
h = {'Referer': BASE}
h.update(hdr or {})
if COOKIE: h['Cookie'] = COOKIE
r = urllib.request.Request(BASE + path, data=data, headers=h, method=method)
try:
with urllib.request.urlopen(r, timeout=20) as resp:
b = resp.read(); return resp.status, (b if raw else (json.loads(b) if b and b[:1] in b'[{' else b.decode()))
except urllib.error.HTTPError as e:
return e.code, e.read().decode()[:200]
COOKIE = None
code, _ = None, None
r = urllib.request.Request(BASE + '/api/v2/auth/login', data=urllib.parse.urlencode({'username': 'admin', 'password': PW}).encode(),
headers={'Referer': BASE, 'Content-Type': 'application/x-www-form-urlencoded'}, method='POST')
with urllib.request.urlopen(r, timeout=20) as resp:
m = re.search(r'((?:QBT_)?SID[A-Za-z0-9_]*)=([^;]+)', '; '.join(resp.headers.get_all('Set-Cookie') or []))
print('login', resp.status, 'cookie' if m else 'NO COOKIE')
COOKIE = f'{m.group(1)}={m.group(2)}'
def netdev():
for line in open(f'/proc/{PID}/net/dev'):
if line.strip().startswith('eth0:'):
f = line.split(':', 1)[1].split(); return int(f[8])
def engine_stats():
s = socket.socket(socket.AF_UNIX); s.connect('/var/run/docker.sock')
s.sendall(f'GET /containers/{CID}/stats?stream=false&one-shot=true HTTP/1.0\r\n\r\n'.encode())
b = b''
while True:
x = s.recv(65536)
if not x: break
b += x
j = json.loads(b.split(b'\r\n\r\n', 1)[1])
return sum(n['tx_bytes'] for n in j.get('networks', {}).values()), j['cpu_stats']['cpu_usage']['total_usage']
def cli_stats():
return sh('docker', 'stats', '--no-stream', '--format', '{{.NetIO}}', C)
mode = sys.argv[2] if len(sys.argv) > 2 else 'info'
if mode == 'info':
print('version', req('GET', '/api/v2/app/version')[1], 'webapi', req('GET', '/api/v2/app/webapiVersion')[1])
print('transfer/info', req('GET', '/api/v2/transfer/info')[1])
p = req('GET', '/api/v2/app/preferences')[1]
print('prefs', {k: p.get(k) for k in ('up_limit', 'dl_limit', 'alt_up_limit', 'alt_dl_limit', 'scheduler_enabled', 'limit_tcp_overhead', 'limit_lan_peers', 'limit_utp_rate', 'max_uploads', 'enable_upload_suggestions')})
print('uploadLimit', req('GET', '/api/v2/transfer/uploadLimit')[1], 'speedLimitsMode', req('GET', '/api/v2/transfer/speedLimitsMode')[1])
elif mode == 'add':
bnd = uuid.uuid4().hex
tor = open('/root/uwtest.torrent', 'rb').read()
parts = []
for k, v in (('savepath', '/mnt/felhom-drives/scratch_hdd/userdata/media/torrents'), ('skip_checking', 'true'), ('category', '')):
parts.append(f'--{bnd}\r\nContent-Disposition: form-data; name="{k}"\r\n\r\n{v}\r\n'.encode())
parts.append(f'--{bnd}\r\nContent-Disposition: form-data; name="torrents"; filename="uwtest.torrent"\r\nContent-Type: application/x-bittorrent\r\n\r\n'.encode() + tor + b'\r\n')
parts.append(f'--{bnd}--\r\n'.encode())
print('add', req('POST', '/api/v2/torrents/add', b''.join(parts), {'Content-Type': f'multipart/form-data; boundary={bnd}'}))
time.sleep(3)
print('torrents', [(t['name'], t['state'], t['progress']) for t in req('GET', '/api/v2/torrents/info')[1]])
elif mode == 'setlimit':
print('setUploadLimit', req('POST', '/api/v2/transfer/setUploadLimit', urllib.parse.urlencode({'limit': sys.argv[3]}).encode(), {'Content-Type': 'application/x-www-form-urlencoded'}))
print('uploadLimit now', req('GET', '/api/v2/transfer/uploadLimit')[1], 'prefs.up_limit', req('GET', '/api/v2/app/preferences')[1].get('up_limit'))
elif mode == 'setpref':
print('setPreferences', req('POST', '/api/v2/app/setPreferences', urllib.parse.urlencode({'json': json.dumps({'up_limit': int(sys.argv[3])})}).encode(), {'Content-Type': 'application/x-www-form-urlencoded'}))
print('uploadLimit now', req('GET', '/api/v2/transfer/uploadLimit')[1], 'prefs.up_limit', req('GET', '/api/v2/app/preferences')[1].get('up_limit'))
elif mode == 'peer':
print('addPeers', req('POST', '/api/v2/torrents/addPeers', urllib.parse.urlencode({'hashes': 'all', 'peers': sys.argv[3]}).encode(), {'Content-Type': 'application/x-www-form-urlencoded'}))
print('reannounce', req('POST', '/api/v2/torrents/reannounce', urllib.parse.urlencode({'hashes': 'all'}).encode(), {'Content-Type': 'application/x-www-form-urlencoded'}))
elif mode == 'post':
print(sys.argv[3], req('POST', sys.argv[3], urllib.parse.urlencode(json.loads(sys.argv[4])).encode(), {'Content-Type': 'application/x-www-form-urlencoded'}))
elif mode == 'sample':
dur, step = int(sys.argv[3]), int(sys.argv[4])
t0 = time.time(); prev = None
while time.time() - t0 <= dur:
ti = req('GET', '/api/v2/transfer/info')[1]
tor = req('GET', '/api/v2/torrents/info')[1]
etx, ecpu = engine_stats()
row = {'t': round(time.time() - t0, 1), 'qb_up_speed': ti['up_info_speed'], 'qb_up_data': ti['up_info_data'],
'qb_tor_uploaded': sum(x.get('uploaded', 0) for x in tor), 'proc_tx': netdev(), 'engine_tx': etx, 'cli': cli_stats()}
if prev:
dt = row['t'] - prev['t']
row['rate_qb_data_Mbit'] = round((row['qb_up_data'] - prev['qb_up_data']) * 8 / dt / 1e6, 2)
row['rate_proc_Mbit'] = round((row['proc_tx'] - prev['proc_tx']) * 8 / dt / 1e6, 2)
row['rate_engine_Mbit'] = round((row['engine_tx'] - prev['engine_tx']) * 8 / dt / 1e6, 2)
print(json.dumps(row), flush=True); prev = row
time.sleep(step)
@@ -0,0 +1,32 @@
import sqlite3,sys,collections
def runs(r, pred):
best=cur=0; bt=None; prev=None
for t,v in r:
if pred(v) and prev is not None and t-prev<=180: cur+=1
elif pred(v): cur=1
else: cur=0
if cur>best: best=cur; bt=t
prev=t
return best,bt
import datetime
for box in sys.argv[1:]:
db=sqlite3.connect(f'file:{box}/metrics.db?mode=ro',uri=True)
nc=None
rows=collections.defaultdict(list)
for ts,name,cpu,tx in db.execute('select ts,container_name,cpu_percent,net_tx_bytes from container_metrics order by ts'):
rows[name].append((ts,cpu,tx))
print('==',box.rsplit('/',1)[1])
out=[]
for name,r in rows.items():
cpu=[(t,c) for t,c,_ in r]
tx=[]
for (t0,_,a),(t1,_,b) in zip(r,r[1:]):
if a is None or b is None or b<a or not 0<t1-t0<=180: continue
tx.append((t1,(b-a)*8/(t1-t0)/1e6))
c150,ct=runs(cpu,lambda v:v>=150); c80,_=runs(cpu,lambda v:v>=80)
u5,ut=runs(tx,lambda v:v>=5); u1,_=runs(tx,lambda v:v>=1)
if max(c80,u1)>=3: out.append((name,c80,c150,ct,u1,u5,ut))
print(f'{"container":28} cpu>=80% cpu>=150% (at) tx>=1Mbit tx>=5Mbit (at) [longest run, minutes]')
for name,c80,c150,ct,u1,u5,ut in sorted(out,key=lambda x:-max(x[1],x[4])):
f=lambda t: datetime.datetime.utcfromtimestamp(t).strftime('%m-%d %H:%M') if t else '-'
print(f'{name[:28]:28} {c80:8} {c150:9} ({f(ct)}) {u1:9} {u5:9} ({f(ut)})')
@@ -0,0 +1,21 @@
# Minimal BitTorrent HTTP tracker for a closed scratch test (no internet). Compact peer lists.
import http.server, urllib.parse, socket, struct, time
peers = {} # info_hash -> {(ip,port): last_seen}
def benc(o):
if isinstance(o, int): return b"i%de" % o
if isinstance(o, bytes): return b"%d:%s" % (len(o), o)
if isinstance(o, str): return benc(o.encode())
if isinstance(o, dict): return b"d" + b"".join(benc(k) + benc(v) for k, v in sorted(o.items())) + b"e"
class H(http.server.BaseHTTPRequestHandler):
def do_GET(self):
q = urllib.parse.parse_qs(urllib.parse.urlsplit(self.path).query.encode('latin-1').decode('latin-1'), encoding='latin-1')
ih = q.get('info_hash', [''])[0]; port = int(q.get('port', ['0'])[0]); ip = self.client_address[0]
d = peers.setdefault(ih, {}); now = time.time()
if q.get('event', [''])[0] == 'stopped': d.pop((ip, port), None)
else: d[(ip, port)] = now
lst = b"".join(socket.inet_aton(i) + struct.pack(">H", p) for (i, p), t in d.items() if now - t < 600 and (i, p) != (ip, port))
body = benc({"interval": 30, "peers": lst})
print(time.strftime('%H:%M:%S'), 'announce', ip, port, q.get('event', [''])[0], 'peers', len(lst) // 6, flush=True)
self.send_response(200); self.send_header('Content-Length', str(len(body))); self.end_headers(); self.wfile.write(body)
def log_message(self, *a): pass
http.server.ThreadingHTTPServer(('0.0.0.0', 6969), H).serve_forever()
@@ -0,0 +1,47 @@
# Runs INSIDE guest 9202. Transmission's own RPC numbers vs the container's exact tx bytes. Password read at use, never printed.
import json, subprocess, sys, time, urllib.request, base64
def sh(*a): return subprocess.run(a, capture_output=True, text=True).stdout.strip()
C = 'transmission'
IP = sh('docker', 'inspect', '-f', '{{range .NetworkSettings.Networks}}{{.IPAddress}} {{end}}', C).split()[0]
PID = sh('docker', 'inspect', '-f', '{{.State.Pid}}', C)
PW = sh('docker', 'exec', C, 'printenv', 'PASS')
AUTH = 'Basic ' + base64.b64encode(('admin:' + PW).encode()).decode()
SID = ''
def rpc(method, args=None):
global SID
for _ in range(2):
r = urllib.request.Request(f'http://{IP}:9091/transmission/rpc', data=json.dumps({'method': method, 'arguments': args or {}}).encode(),
headers={'Authorization': AUTH, 'Host': 'transmission:9091', 'X-Transmission-Session-Id': SID, 'Content-Type': 'application/json'}, method='POST')
try:
with urllib.request.urlopen(r, timeout=20) as resp: return json.loads(resp.read())
except urllib.error.HTTPError as e:
if e.code == 409: SID = e.headers.get('X-Transmission-Session-Id'); continue
return {'http': e.code}
def tx():
for line in open(f'/proc/{PID}/net/dev'):
if line.strip().startswith('eth0:'): return int(line.split(':', 1)[1].split()[8])
mode = sys.argv[1]
if mode == 'info':
g = rpc('session-get')['arguments']
print('version', g.get('version'), {k: g.get(k) for k in ('speed-limit-up', 'speed-limit-up-enabled', 'alt-speed-up', 'alt-speed-enabled', 'alt-speed-time-enabled', 'units')})
print('session-stats', rpc('session-stats')['arguments'])
elif mode == 'add':
meta = base64.b64encode(open('/root/uwtest.torrent', 'rb').read()).decode()
print(rpc('torrent-add', {'metainfo': meta, 'download-dir': '/mnt/felhom-drives/scratch_hdd/userdata/media/transmission', 'paused': False}))
time.sleep(5); rpc('torrent-verify', {}); time.sleep(20)
print(rpc('torrent-get', {'fields': ['name', 'status', 'percentDone', 'error', 'errorString']}))
elif mode == 'limit':
print(rpc('session-set', {'speed-limit-up': int(sys.argv[2]), 'speed-limit-up-enabled': True}))
g = rpc('session-get')['arguments']; print({k: g.get(k) for k in ('speed-limit-up', 'speed-limit-up-enabled')})
elif mode == 'reannounce':
print(rpc('torrent-reannounce', {}))
elif mode == 'sample':
dur, step = int(sys.argv[2]), int(sys.argv[3]); t0 = time.time(); prev = None
while time.time() - t0 <= dur:
st = rpc('session-stats')['arguments']; tg = rpc('torrent-get', {'fields': ['uploadedEver', 'rateUpload']})['arguments']['torrents']
row = {'t': round(time.time() - t0, 1), 'tr_upspeed': st['uploadSpeed'], 'tr_cur_up': st['current-stats']['uploadedBytes'], 'tr_tor_up': sum(x['uploadedEver'] for x in tg), 'tx': tx()}
if prev:
dt = row['t'] - prev['t']
row['rate_tr_Mbit'] = round((row['tr_cur_up'] - prev['tr_cur_up']) * 8 / dt / 1e6, 2)
row['rate_container_Mbit'] = round((row['tx'] - prev['tx']) * 8 / dt / 1e6, 2)
print(json.dumps(row), flush=True); prev = row; time.sleep(step)
@@ -0,0 +1,6 @@
== 9202 smoke 06:37:25
switched to gitea.dooplex.hu/admin/felhom-controller:0.340.0 at 06:37:28
healthy after ~10s: Up 7 seconds (healthy)
2026/10/23 06:37:28 [INFO] [tier2] start-up: no leftover second-drive copy container
errors, unhealthy+restarting: 0 0
login page: 200
@@ -0,0 +1,3 @@
tester-1: HTTP/1.1 303 See Other Location: /customers/tester-1?flash=floor_set
demo-hp: HTTP/1.1 303 See Other Location: /customers/demo-hp?flash=floor_set
demo-felhom: HTTP/1.1 303 See Other Location: /customers/demo-felhom?flash=floor_set
@@ -0,0 +1,15 @@
### root@192.168.0.154
containers=10 unhealthy=0 restarting=0 gitea.dooplex.hu/admin/felhom-controller:0.340.0 Up 53 seconds (healthy)
errors=0
copy-containers=0
2026/10/23 06:38:21 [INFO] [tier2] start-up: no leftover second-drive copy container
### hp
containers=24 unhealthy=0 restarting=0 gitea.dooplex.hu/admin/felhom-controller:0.340.0 Up 54 seconds (healthy)
errors=0
copy-containers=0
2026/10/23 06:38:22 [INFO] [tier2] start-up: no leftover second-drive copy container
### felhom-pve
containers=9 unhealthy=0 restarting=0 gitea.dooplex.hu/admin/felhom-controller:0.340.0 Up 58 seconds (healthy)
errors=0
copy-containers=0
2026/10/23 06:38:05 [INFO] [tier2] start-up: no leftover second-drive copy container
@@ -0,0 +1,33 @@
control NEGATIVE (a stub answering 200 over plain http): convicted, as it must (200 -)
== tester-1 (enkicsifelhom.hu): 6 public name(s)
OK control POSITIVE http://felhom.enkicsifelhom.hu/r1033-check?q=1 -> 301 https://felhom.enkicsifelhom.hu/r1033-check?q=1
OK http://files.enkicsifelhom.hu/r1033-check?q=1 -> 301 https://files.enkicsifelhom.hu/r1033-check?q=1
OK http://no-such-name-r1033.enkicsifelhom.hu/r1033-check?q=1 -> 301 https://no-such-name-r1033.enkicsifelhom.hu/r1033-check?q=1
OK http://paperless.enkicsifelhom.hu/r1033-check?q=1 -> 301 https://paperless.enkicsifelhom.hu/r1033-check?q=1
OK http://paste.enkicsifelhom.hu/r1033-check?q=1 -> 301 https://paste.enkicsifelhom.hu/r1033-check?q=1
OK http://wiki.enkicsifelhom.hu/r1033-check?q=1 -> 301 https://wiki.enkicsifelhom.hu/r1033-check?q=1
== demo-hp (enkisfelhom.hu): 14 public name(s)
OK http://arcade.enkisfelhom.hu/r1033-check?q=1 -> 301 https://arcade.enkisfelhom.hu/r1033-check?q=1
OK http://books.enkisfelhom.hu/r1033-check?q=1 -> 301 https://books.enkisfelhom.hu/r1033-check?q=1
OK http://docs.enkisfelhom.hu/r1033-check?q=1 -> 301 https://docs.enkisfelhom.hu/r1033-check?q=1
OK http://felhom.enkisfelhom.hu/r1033-check?q=1 -> 301 https://felhom.enkisfelhom.hu/r1033-check?q=1
OK http://files.enkisfelhom.hu/r1033-check?q=1 -> 301 https://files.enkisfelhom.hu/r1033-check?q=1
OK http://gist.enkisfelhom.hu/r1033-check?q=1 -> 301 https://gist.enkisfelhom.hu/r1033-check?q=1
OK http://ha.enkisfelhom.hu/r1033-check?q=1 -> 301 https://ha.enkisfelhom.hu/r1033-check?q=1
OK http://no-such-name-r1033.enkisfelhom.hu/r1033-check?q=1 -> 301 https://no-such-name-r1033.enkisfelhom.hu/r1033-check?q=1
OK http://papir.enkisfelhom.hu/r1033-check?q=1 -> 301 https://papir.enkisfelhom.hu/r1033-check?q=1
OK http://paste.enkisfelhom.hu/r1033-check?q=1 -> 301 https://paste.enkisfelhom.hu/r1033-check?q=1
OK http://pdf.enkisfelhom.hu/r1033-check?q=1 -> 301 https://pdf.enkisfelhom.hu/r1033-check?q=1
OK http://plex.enkisfelhom.hu/r1033-check?q=1 -> 301 https://plex.enkisfelhom.hu/r1033-check?q=1
OK http://travel.enkisfelhom.hu/r1033-check?q=1 -> 301 https://travel.enkisfelhom.hu/r1033-check?q=1
OK http://wiki.enkisfelhom.hu/r1033-check?q=1 -> 301 https://wiki.enkisfelhom.hu/r1033-check?q=1
== demo-felhom (demo-felhom.eu): 8 public name(s)
OK http://felhom.demo-felhom.eu/r1033-check?q=1 -> 301 https://felhom.demo-felhom.eu/r1033-check?q=1
OK http://files.demo-felhom.eu/r1033-check?q=1 -> 301 https://files.demo-felhom.eu/r1033-check?q=1
OK http://gist.demo-felhom.eu/r1033-check?q=1 -> 301 https://gist.demo-felhom.eu/r1033-check?q=1
OK http://no-such-name-r1033.demo-felhom.eu/r1033-check?q=1 -> 301 https://no-such-name-r1033.demo-felhom.eu/r1033-check?q=1
OK http://prowlarr.demo-felhom.eu/r1033-check?q=1 -> 301 https://prowlarr.demo-felhom.eu/r1033-check?q=1
OK http://radarr.demo-felhom.eu/r1033-check?q=1 -> 301 https://radarr.demo-felhom.eu/r1033-check?q=1
OK http://sonarr.demo-felhom.eu/r1033-check?q=1 -> 301 https://sonarr.demo-felhom.eu/r1033-check?q=1
OK http://torrent.demo-felhom.eu/r1033-check?q=1 -> 301 https://torrent.demo-felhom.eu/r1033-check?q=1
== every public name redirects http -> https
@@ -0,0 +1,13 @@
== tester-1 (dashboard login with the household password, the press a browser makes)
python3: can't open file '/tmp/claude-1000/-mnt-5-hdd-felhom-eu-git/38fde0c6-e964-4ec1-b0c7-56e62d675225/scratchpad/n23/fileswalk.py': [Errno 2] No such file or directory
== demo-hp (no session): GET /__files/open -> HTTP/2 302 location: /login
== demo-felhom (no session): GET /__files/open -> HTTP/2 302 location: /login
== tester-1 06:40:35
Fájlok press: GET /__files/open -> ['HTTP/2 302'] https://files.enkicsifelhom.hu/_felhom/sso
manual second-drive copy: 200 2. mentés elindítva
2026/10/23 06:40:43 [INFO] [backup] Tier 2 copied bookstack → /mnt/felhom-drives/adatlemez/backups/secondary/bookstack (157.0 MB, 0 leg(s), 1s)
2026/10/23 06:40:46 [INFO] [backup] Tier 2 copied paperless-ngx → /mnt/sys_drive/felhom-data/backups/secondary/paperless-ngx (85.9 MB, 1 leg(s), 2s) [SSD: state-only]
2026/10/23 06:40:48 [INFO] [backup] Tier 2 copied privatebin → /mnt/felhom-drives/adatlemez/backups/secondary/privatebin (16.4 KB, 0 leg(s), 0s)
2026/10/23 06:40:48 [INFO] [backup] Tier 2 run complete: 3 app(s) processed (incl. volume-only — F6)
copy-containers-left=0
[exited with code 0]
@@ -0,0 +1,5 @@
== global floor 06:41:04: HTTP/1.1 303 See Other Location: /configuration?flash=floor_set
clear tester-1: HTTP/1.1 303 See Other Location: /customers/tester-1?flash=floor_set
clear demo-hp: HTTP/1.1 303 See Other Location: /customers/demo-hp?flash=floor_set
clear demo-felhom: HTTP/1.1 303 See Other Location: /customers/demo-felhom?flash=floor_set
read back (with WAL): [('min_controller_version', '0.340.0', '2026-10-23 06:41:04'), ('min_controller_version_declared_min_agent', '0.340.0=0.158.1', '2026-10-23 06:41:04')]
@@ -0,0 +1,78 @@
# Part 2 — agent 0.163.0 (operator go 2026-10-23), read 2026-10-23T07:28:53Z
## release (scripts/release-agent.sh at felhom-agent 1109092, CI 2246 green; CHANGELOG b4721ee CI 2249 green)
[release-agent] built ok: sha256 561b5316cd511de9fa9d8b8be4553da7add684f715d3bea533ca330ff7f3763c
[release-agent] config bundle built: sha256 3afb88d9fbbc4adc16083fa52a98cd4974583c6378a77a1a6e0ed8ae6d1b80c8
[publish-agent] upload OK (HTTP 201)
[publish-agent] round-trip GET verified (sha256 matches)
[release-agent] config bundle published (HTTP 201)
sha256 : 561b5316cd511de9fa9d8b8be4553da7add684f715d3bea533ca330ff7f3763c
bundle : 3afb88d9fbbc4adc16083fa52a98cd4974583c6378a77a1a6e0ed8ae6d1b80c8 (felhom-config-bundle.json — vouch it with the agent)
* [new tag] v0.163.0 -> v0.163.0
## step bundle (R-880: the D4 drop-in is a NEW path; the boxes ran bundle 0.160.0 = 6b06090190ff609af1fe9842447ebf385fd52da4be382bc7ca708b558c8e202f)
0.163.0-step1 = base 0.160.0 with only /usr/local/sbin/felhom-os-apply replaced; sha256 6cbc066902d5f3294765d5c7dc7113166c1dca25e994dbc36bfc5f139bb61fcf; PUT 201; read back by download: same sha
## delivery: three signed jobs per box (felhom-opsign, key felhom-op-1): agent_update 06:48Z, agent_config_update 0.163.0-step1 06:59Z, agent_config_update 0.163.0 07:19Z
## hp (192.168.0.104) 2026-10-23T07:26:29Z
agent: felhom-agent 0.163.0
bundle: 0.163.0 3afb88d9fbbc4adc16083fa52a98cd4974583c6378a77a1a6e0ed8ae6d1b80c8 2026-10-23T07:19:44Z
1 BUNDLE DONE agent=0.163.0 written=1 same=30 self-check=ok
2 BUNDLE DONE agent=0.163.0-step1 written=1 same=29 self-check=ok
guest 9201: memory: 25898 swap: 25898
guest 9202: memory: 25898 swap: 512
guest 9401: memory: 10240 swap: 0
drop-in: -rw-r--r-- 1 root root 690 Oct 23 09:19 /etc/ssh/sshd_config.d/10-felhom-root-key-only.conf
drop-in content: PermitRootLogin prohibit-password
sshd -T: permitrootlogin without-password
root password set (passwd -S): P
felhom-sshd: active; its root policy: permitrootlogin without-password
felhom-sshd listens: 0.0.0.0:8822 [::]:8822 config test: ok; firewall admits only: elements = { 10.77.0.250 }
main sshd reloaded after the drop-in: Oct 23 09:19:44 demo-hp sshd[1010]: Received SIGHUP; restarting. Oct 23 09:19:44 demo-hp systemd[1]: Reloaded ssh.service - OpenBSD Secure Shell server.
pveproxy: active
main sshd banner from DooPlex (:22): SSH-2.0-OpenSSH_10.0p2 Debian-7+deb13u4
key login: ok
root password attempt rc=255 (non-zero = refused)
Oct 23 09:26:37 demo-hp sshd-session[3026730]: Failed password for root from 192.168.0.180 port 34150 ssh2
## root@192.168.0.154 (192.168.0.154) 2026-10-23T07:28:00Z
agent: felhom-agent 0.163.0
bundle: 0.163.0 3afb88d9fbbc4adc16083fa52a98cd4974583c6378a77a1a6e0ed8ae6d1b80c8 2026-10-23T07:27:38Z
2 BUNDLE DONE agent=0.163.0 written=1 same=30 self-check=ok
2 BUNDLE DONE agent=0.163.0-step1 written=1 same=29 self-check=ok
guest 9201: memory: 4096 swap: 4096
guest 990000: memory: 4096 swap: 512
drop-in: -rw-r--r-- 1 root root 690 Oct 23 09:27 /etc/ssh/sshd_config.d/10-felhom-root-key-only.conf
drop-in content: PermitRootLogin prohibit-password
sshd -T: permitrootlogin without-password
root password set (passwd -S): P
felhom-sshd: active; its root policy: permitrootlogin without-password
felhom-sshd listens: 0.0.0.0:8822 [::]:8822 config test: ok; firewall admits only: elements = { 10.77.0.250 }
main sshd reloaded after the drop-in: Oct 23 09:27:38 felhom sshd[890]: Received SIGHUP; restarting. Oct 23 09:27:38 felhom systemd[1]: Reloaded ssh.service - OpenBSD Secure Shell server.
pveproxy: active
main sshd banner from DooPlex (:22): SSH-2.0-OpenSSH_10.0p2 Debian-7+deb13u4
key login: ok
root password attempt rc=255 (non-zero = refused)
Oct 23 09:28:08 felhom sshd-session[4184378]: Failed password for root from 192.168.0.180 port 33442 ssh2
## felhom-pve (192.168.0.162) 2026-10-23T07:28:11Z
agent: felhom-agent 0.163.0
bundle: 0.163.0 3afb88d9fbbc4adc16083fa52a98cd4974583c6378a77a1a6e0ed8ae6d1b80c8 2026-10-23T07:24:43Z
2 BUNDLE DONE agent=0.163.0 written=1 same=30 self-check=ok
2 BUNDLE DONE agent=0.163.0-step1 written=1 same=29 self-check=ok
guest 9201: memory: 12288 swap: 12288
drop-in: -rw-r--r-- 1 root root 690 Oct 23 09:24 /etc/ssh/sshd_config.d/10-felhom-root-key-only.conf
drop-in content: PermitRootLogin prohibit-password
sshd -T: permitrootlogin without-password
root password set (passwd -S): P
felhom-sshd: active; its root policy: permitrootlogin without-password
felhom-sshd listens: 0.0.0.0:8822 [::]:8822 config test: ok; firewall admits only: elements = { 10.77.0.250 }
main sshd reloaded after the drop-in: Oct 23 09:24:42 demo-felhom sshd[1011]: Received SIGHUP; restarting. Oct 23 09:24:42 demo-felhom systemd[1]: Reloaded ssh.service - OpenBSD Secure Shell server
pveproxy: active
main sshd banner from DooPlex (:22): SSH-2.0-OpenSSH_10.0p2 Debian-7+deb13u4
key login: ok
root password attempt rc=255 (non-zero = refused)
## notes
- felhom-sshd :8822 admits only the operator peer 10.77.0.250 over wg-felhom (H1); a connection test from DooPlex times out BY DESIGN — proven: active, listening, sshd -t ok, firewall set.
- a dummy root password is logged as 'Failed password' (OpenSSH refuses a root password silently under prohibit-password); the policy proof is sshd -T + the SIGHUP reload after the drop-in. The real root password was not tried (CC does not hold it).
- guests 9202, 9401 (demo-hp) and the transient 990000 (Tester 1, gone a minute later) are outside the felhom pool; swap = RAM applies to pool guests (9201 on all three: swap = memory).
@@ -0,0 +1,53 @@
# Part 6 — D33: the released images and agent packages to ep0 nightly (operator yes 2026-10-23), 2026-10-23T07:51:56Z
## ep0 — free space first, then ONE user and ONE directory (nothing else on ep0 changed)
before: /dev/sda1 38G 23G used 14G free 63% (/mnt/pbs-datastore is the PBS datastore root — not used)
created: user felhom-relcopy (system, uid 999, password locked 'L', shell /bin/sh for the forced command), /srv/felhom-release-copy (0750) with data/ and .ssh/authorized_keys:
command="/usr/bin/rrsync /srv/felhom-release-copy/data",restrict ssh-ed25519 <the job key, felhom-release-copy@dooplex>
fence test: rsync --list-only OK; a shell command → 'rrsync error: SSH_ORIGINAL_COMMAND does not run rsync'; '..' → 'do not use .. in arg'
after the first copy: /dev/sda1 38G 24G used 13G free 65%; /srv/felhom-release-copy/data 677M
cap: CAP_MB=3072, enforced by the sender (ep0's root fs has no quota; a quota would change more than one directory)
## DooPlex — the job (felhom.eu d306b8c2): /usr/local/sbin/felhom-release-copy + .service + .timer (01:40), /etc/felhom-release-copy/{env,id_ed25519,known_hosts,registry-token}
registry token: a NEW Gitea access token for user admin, name felhom-release-copy-d33, scope read:package ONLY — minted inside the gitea pod straight into /etc/felhom-release-copy/registry-token (0600 root); never printed
known_hosts: ep0's ed25519 host key, SHA256:NGtcS5v3K+9UjMTM6X5Ib0CoChdhqj9bezLz1hOUqgY — equal to the key already pinned for root@ep0
skopeo, not docker save: skopeo dir: keeps the registry's manifest bytes and compressed blobs, so a push back gives the SAME digest (docker save re-compresses → a new digest); no Docker daemon needed
## the first run (systemctl start, under the unit's sandbox)
2026-10-23T09:48:33+02:00 dooplex felhom-release-copy[1567269]: felhom-release-copy: felhom-controller: keeping 0.338.0, 0.339.0, 0.340.0
2026-10-23T09:48:37+02:00 dooplex felhom-release-copy[1567269]: felhom-release-copy: felhom-hub: keeping 0.164.0, 0.165.0, 0.166.0
2026-10-23T09:48:43+02:00 dooplex felhom-release-copy[1567269]: felhom-release-copy: felhom-samba: keeping 1.0.0, 1.1.0, 1.2.0
2026-10-23T09:48:47+02:00 dooplex felhom-release-copy[1567269]: felhom-release-copy: felhom-agent: keeping 0.159.2, 0.160.0, 0.161.0, 0.162.0, 0.163.0
2026-10-23T09:48:51+02:00 dooplex felhom-release-copy[1567269]: felhom-release-copy: staged and verified: 676 MB, new this run: felhom-controller:0.338.0, felhom-controller:0.339.0, felhom-controller:0.340.0, felhom-hub:0.164.0, felhom-hub:0.165.0, felhom-hub:0.166.0, felhom-samba:1.0.0, felhom-samba:1.1.0, felhom-samba:1.2.0
2026-10-23T09:49:51+02:00 dooplex felhom-release-copy[1567269]: felhom-release-copy: pushed to ep0 and compared by checksum: no difference (91 s)
2026-10-23T09:49:51+02:00 dooplex felhom-release-copy[1567269]: felhom-release-copy: success signal written
2026-10-23T09:49:51+02:00 dooplex systemd[1]: felhom-release-copy.service: Consumed 30.416s CPU time, 743.1M memory peak.
## read back from ep0 (rsync pull with the job key → /var/lib/felhom-release-copy/readback)
sha256sum -c SHA256SUMS: every file OK (141 files), 677 MB
every image re-verified (top manifest = its digest, every blob = its name):
felhom-controller 0.338.0 sha256:e8a529f395bfe8c0e7b87d5d98929a6f8e9834aa13c0ab77bd214ee9e7e53433
felhom-controller 0.339.0 sha256:fee71aafceb4a7d5f24ae4a6a273a8d51eb26e0550fe9d12d4d86955f6a343a8
felhom-controller 0.340.0 sha256:a8d1c6458da4ea9d667f928498656a291771e0b3756b20f2fcc8c1cf9d516621
felhom-hub 0.164.0 sha256:931594e333a4e8a9784eff2fb144d022ab46f89dd6a865a93e6100dc28dbd9dc
felhom-hub 0.165.0 sha256:c6180fb79a2ff7d5546a704c68b634b9207afb0a0ecd524c74b0310434532537
felhom-hub 0.166.0 sha256:829667bb289c790bc99719e88dad8f7d08faaa9f662df1e9a06b1774915a1af6
felhom-samba 1.0.0 sha256:0fa9fae3eaa9d48836c855a4884f0751a90ff050dc9e7d17e41d93bb434499c0
felhom-samba 1.1.0 sha256:1c17c09422bec0366d7cf0e0fcfc1486ba6c90334a0a5d5c851073a9342f8f10
felhom-samba 1.2.0 sha256:da96f25033827fbb77d0ee398e86fe5b744e2f29be9de898994533340c97acf9
agent 0.159.2 binary 4d98868e922d6c10665a6c0da9323e8627ea9c589094e81d27d741e625d9d8f9 bundle 477704ea2980948433ffc34bb59f008cc11410fd9683d386bfd3e2f085d55bc9
agent 0.160.0 binary 7ebb547f2b1ab93544ba828d3040351b60c4126327a5b85bbcb33f8f2b3dfca1 bundle 6b06090190ff609af1fe9842447ebf385fd52da4be382bc7ca708b558c8e202f
agent 0.161.0 binary ff4e6dc52dd70234913445ecdeb88d31dea8e394d77c48704d26ff19b999d3b5 bundle 485f36c957d83f772aa22cac24e5e73f44da5cf8b957b1fd513bec2bc1d12c47
agent 0.162.0 binary 5fd7a23bfe319cb521c4bc399612d5fb3413f1e695f79bc663c386f69c757928 bundle ac772967fd4669045e837a70bf5acca239c58d55f7f00212e472a8facd60b5a5
agent 0.163.0 binary 561b5316cd511de9fa9d8b8be4553da7add684f715d3bea533ca330ff7f3763c bundle 3afb88d9fbbc4adc16083fa52a98cd4974583c6378a77a1a6e0ed8ae6d1b80c8
independent controls (other channels): controller 0.340.0 = the release digest from build.sh (03-release-0340-boxes.txt); hub 0.165.0 = the running hub pod's imageID; hub 0.164.0 = hub/CHANGELOG; agent 0.163.0 = release-agent.sh today; agent 0.161.0 = night2-2026-10-20/P1/1b; bundle 0.160.0 = the three boxes' installed bundle_sha256
## load on a scratch machine (9202 on demo-hp, Tier 0)
the ep0 copy of felhom-controller 0.340.0 → skopeo docker-archive (amd64) → pct push 9202 → docker load:
Loaded image: felhom-restorecopy-test:0.340.0; ID=sha256:3f34d74519463c338422594b70c31d9c5beabed48847134c6d26b5a95ebbae2b = the copy's amd64 config digest; a container ran (ls /)
teardown: image untagged (0 left), the tar removed on 9202, on demo-hp /tmp and on DooPlex
timer: Sat 2026-10-24 01:42:16 CEST 15h - - felhom-release-copy.timer felhom-release-copy.service
## alarm (homelab-manifests 1bbef892): FelhomReleaseCopyStale (> 26 h or absent, warning) — promtool check: 7 rules OK; promtool test: quiet at 25 h, fires at 27 h
synced ConfigMap mon-system/prometheus-rules only; POST /-/reload 200; /api/v1/rules: FelhomReleaseCopyStale inactive ok; metric age at read ~3235 s
@@ -0,0 +1,10 @@
no guest references the three
BEFORE: /dev/mapper/pve-root 39G 29G 8.5G 77% /
Removed volume 'local:iso/felhom-installer-1.27.1-pve9.2-1.iso'
removed local:iso/felhom-installer-1.27.1-pve9.2-1.iso
Removed volume 'local:iso/felhom-installer-1.28.0-pve9.2-1.iso'
removed local:iso/felhom-installer-1.28.0-pve9.2-1.iso
Removed volume 'local:iso/felhom-installer-1.29.0-pve9.2-1.iso'
removed local:iso/felhom-installer-1.29.0-pve9.2-1.iso
AFTER: /dev/mapper/pve-root 39G 24G 14G 64% /
local:iso/felhom-installer-1.30.0-pve9.2-1.iso iso iso 1705324544
@@ -0,0 +1,16 @@
# The vouch read-back — agent 0.163.0 (the operator vouched on the hub, answered 'Vouched now'), read 2026-10-23T08:00:42Z
## channel 1: hub DB (hub.db + -wal + -shm in ONE tar from the pod), hub_settings
artifact_agent_sha256|561b5316cd511de9fa9d8b8be4553da7add684f715d3bea533ca330ff7f3763c|2026-10-23 07:58:46
artifact_agent_version|0.163.0|2026-10-23 07:58:46
artifact_bundle_sha256|3afb88d9fbbc4adc16083fa52a98cd4974583c6378a77a1a6e0ed8ae6d1b80c8|2026-10-23 07:58:46
artifact_golden_sha256|3881de62b0986ccbe5e55580e3f1bb9765d65b8d898f67c6339bac105244f84f|2026-10-23 07:58:46
artifact_golden_version|0.331.0|2026-10-23 07:58:46
artifact_min_agent|0.158.1|2026-10-23 07:58:46
artifact_wrapper_sha256||2026-10-23 07:58:46
## channel 2: the running hub's operator page GET /configuration (CC's token), the selected options
value="0.163.0" data-sha="561b5316cd511de9fa9d8b8be4553da7add684f715d3bea533ca330ff7f3763c" selected>0.163.0
value="0.331.0" data-sha="3881de62b0986ccbe5e55580e3f1bb9765d65b8d898f67c6339bac105244f84f" selected>0.331.0
agent 0.163.0 sha256 = the release (561b5316…); bundle sha256 = the release (3afb88d9…). Golden 0.331.0 unchanged. The floor's MinAgent stays 0.158.1 (artifact_min_agent 0.158.1; controller 0.340.0 declares 0.158.1).
@@ -0,0 +1,13 @@
# Installer 1.36.0 published (operator yes 2026-10-23), read 2026-10-23T08:16:46Z
1. bump: felhom.eu 83388c08 (SCRIPT_VERSION 1.36.0; scripts/test_hostinstall.py 40 passed; CI 2247 success)
2. tag: installer-v1.36.0 (annotated d00f868c) -> 83388c08, pushed
3. pins: manifests/webpage.yaml both --ref=installer-v1.36.0 (sidecar git-sync-scripts + init git-sync-scripts-init), commit 2aebf1bd;
ArgoCD: only Deployment felhom-system/felhom-webpage was OutOfSync; synced that ONE resource at revision 2aebf1bd; rollout ok;
live args: git-sync-scripts-init ['--ref=installer-v1.36.0'], git-sync-scripts ['--ref=installer-v1.36.0'], website git-sync ['--ref=main'] (unchanged)
4. read back: curl https://felhom.eu/scripts/felhom-host-install.sh
SCRIPT_VERSION="1.36.0" # the SINGLE version source (F-1): -h and the run banners follow it.
sha256 served = de8bf5f32cbcda44c9976ba829f04ea151e3b30634b54d5fdd9eb6c4a0351cec
sha256 tag file = de8bf5f32cbcda44c9976ba829f04ea151e3b30634b54d5fdd9eb6c4a0351cec
the drop-in name 10-felhom-root-key-only appears 2 times (the uninstall's removal)
Rollback: move the tag back to installer-v1.35.0's commit and wait ~30 s (no sync).
@@ -0,0 +1,4 @@
# Website publish read-back (felhom.eu 0bb57a4f, operator yes 2026-10-23)
Method: headless Chromium (playwright 1.61.1 image) on the LIVE site; the FAQ answer opened by a click; 390x844 (phone) and 1366x900 (computer).
No page scrolls sideways at either size (scrollWidth == viewport on all 10 shots).
Text: see text-check.txt (new sentences present; the old 'only encrypted (the remote backup)' gone; control: HEAD~1 had it twice).
Binary file not shown.

After

Width:  |  Height:  |  Size: 144 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 122 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 113 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 122 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 124 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 70 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 55 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 55 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 54 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 59 KiB

@@ -0,0 +1,7 @@
waited ~0 s
NEW letoltes 'az alapokat futtatja' count 1 (want 2 on the FAQ: visible + JSON-LD; 1 on download)
NEW en/download 'runs the basics; the photo app needs 16 GB' count 1 (want 2 on the FAQ: visible + JSON-LD; 1 on download)
NEW gyik 'a Cloudflare h' count 4 (want 2 on the FAQ: visible + JSON-LD; 1 on download)
NEW en/faq "passes through Cloudflare's network and is readable there" count 2 (want 2 on the FAQ: visible + JSON-LD; 1 on download)
OLD gyik 'otthonodat (a t' live 0 (want 0); control HEAD~1 2 (want 2)
OLD en/faq 'leaves your home only encrypted (the remote backup)' live 0 (want 0); control HEAD~1 2 (want 2)
@@ -0,0 +1,43 @@
# Part 5 — D34: the hub DB off-site every 6 hours (operator yes 2026-10-23), 2026-10-23T08:41:15Z
## what changed
- hub 0.167.0 (deployed 08:27Z, image sha256:177860a9…): snapshots at 02:00 08:00 14:00 20:00 Budapest; start-up catch-up when the newest > 6 h. Hub log at start:
2026/10/23 10:28:12 [INFO] db-snapshot 08:00: next run at 2026-10-24 08:00 CEST (in 21h31m48s)
2026/10/23 10:28:12 [INFO] db-snapshot 14:00: next run at 2026-10-23 14:00 CEST (in 3h31m48s)
2026/10/23 10:28:12 [INFO] db-snapshot 20:00: next run at 2026-10-23 20:00 CEST (in 9h31m48s)
2026/10/23 10:28:12 [INFO] db-snapshot 02:00: next run at 2026-10-24 02:00 CEST (in 15h31m48s)
2026/10/23 10:30:06 [INFO] db snapshot written: hub-20261023T082812Z.db (525996032 bytes, 1m54.537s); pruned 1, keeping 2
- DooPlex felhom-hub-db-backup (felhom.eu 52af38df): timer 02:30 08:30 14:30 20:30; waits ≤ 20 min for a snapshot being written; refuses a newest snapshot older than 7 h
- R-1234 (closed): the first version (2 h, no wait, be7e97dc) refused the timer's own catch-up at 10:28 CEST and mailed admin@ once — fixed in 52af38df
## retention (ep0, server-side, unchanged): prune-job prune-operator-hubdb, ns operator, 03:45, keep-daily 14, keep-weekly 8
=> the current day's copies (up to 4) stay until the next 03:45 prune, then the newest of each day for 14 days and one per week for 8 weeks. Size per copy: 501.6 MiB raw, 24.5 MiB uploaded (compressed, dedup'd chunks).
## run once by hand (systemctl start felhom-hub-db-backup.service, 10:39 CEST)
2026-10-23T10:39:33+02:00 dooplex felhom-hub-db-backup[2374380]: felhom-hub-db-backup: snapshot hub-20261023T082812Z.db, 11 min old
2026-10-23T10:39:45+02:00 dooplex felhom-hub-db-backup[2374380]: felhom-hub-db-backup: checked: 525996032 bytes, integrity ok, 4 host(s)
2026-10-23T10:39:48+02:00 dooplex felhom-hub-db-backup[2377041]: hubdb.pxar: had to backup 501.629 MiB of 501.629 MiB (compressed 24.471 MiB) in 2.47 s (average 203.437 MiB/s)
2026-10-23T10:39:49+02:00 dooplex felhom-hub-db-backup[2377041]: Duration: 3.21s
2026-10-23T10:39:49+02:00 dooplex felhom-hub-db-backup[2374380]: felhom-hub-db-backup: pushed hub-20261023T082812Z.db to ep0 (ns operator) in 4 s
2026-10-23T10:39:49+02:00 dooplex felhom-hub-db-backup[2374380]: felhom-hub-db-backup: success signal written
## read back: restore the NEWEST copy from ep0 with the READ-ONLY token into a scratch dir (shredded after)
15 copies on ep0, oldest 2026-10-10T00:30:56Z
newest copy on ep0: host/dooplex-hub/2026-10-23T08:39:45Z
Using encryption key from '/etc/felhom-hub-backup/enc.key'..
Fingerprint: b2:19:bf:36:3b:97:3d:6c
restore complete (501.629 MiB processed in 5.4s, average 92.519 MiB/s)
restored size: 525996032 bytes
restored sha256: a9ff4c8a0d0fe34da72411d9c165e573069f5601492d1e625578464f56adbde7
integrity_check: ok
SELECT COUNT(*) FROM hosts: 4
SELECT value FROM hub_settings WHERE key='artifact_agent_version': 0.163.0
pod snapshot hub-20261023T082812Z.db: 525996032 bytes, sha256 a9ff4c8a0d0fe34da72411d9c165e573069f5601492d1e625578464f56adbde7 (kubectl exec sha256sum — a different channel from the restore)
=> byte-identical; it holds today's vouch (artifact_agent_version 0.163.0, set 07:58Z) — a nightly copy could not
## timers
Fri 2026-10-23 14:30:08 CEST 3h 48min Fri 2026-10-23 10:28:30 CEST 12min ago felhom-hub-db-backup.timer felhom-hub-db-backup.service
## alarm (homelab-manifests 1bbef892): HubDBBackupStale 26 h -> 13 h (two missed 6-hourly pushes)
promtool test: quiet at 12 h, fires at 14 h; RED-PROOF: the rule at 26 h fails the 14 h case
in force: /api/v1/rules shows the 13 * 3600 expression, inactive ok; metric age at read ~237 s
@@ -0,0 +1,21 @@
# Part 3 — hub 0.167.0 deploy and the 30-minute watch (operator yes 2026-10-23), read 2026-10-23T08:56:31Z
build: clean clone at d306b8c2 (hub/ unchanged since be7e97dc, CI 2250 success; d306b8c2 CI 2251 success before the deploy); hub tests rc 0 (28 packages)
image: gitea.dooplex.hu/admin/felhom-hub:0.167.0 sha256:177860a996cb285d935777d6ffdf85725f6cf4489885f54fd3bf8135c68041a0
manifest 34979d5d; ArgoCD: only Deployment felhom-system/hub OutOfSync; synced that one resource; rollout ok 08:27:34Z; pod imageID = the digest above; Synced/Healthy
## watch 08:27:34Z → 08:56:31Z — channel 1: the hub DB (with WAL) + log
events since the deploy: 0 (newest event 07:07:10Z Tester4 host_down — the expected dead test box; 161 events since 2026-10-22: the table is live)
host report|demo-felhom-8363b5|2026-10-23 08:54:54|2
host report|demo-hp-bb76ea|2026-10-23 08:49:41|2
host report|tester-1-d70be4|2026-10-23 08:42:35|1
controller report|demo-felhom|2026-10-23 08:53:20|3
controller report|demo-hp|2026-10-23 08:53:24|3
controller report|tester-1|2026-10-23 08:53:23|3
hub log since deploy: 0 [ERROR]; 'osupdates: alarm check done … 0 alarm(s) sent'; 'Host staleness checker initialized: 3 ok, 1 already alarmed (seeded silently, R-1001)' — Tester4 not re-mailed
## channel 2: the operator mailbox (Gmail connector, to:admin@felhom.eu newer_than:1d)
after 08:27Z: ONE mail, 08:28:32Z '[DooPlex backup] FAILED: felhom-hub-db-backup.service' — NOT from the hub: CC's install of the 6-hourly timer (R-1234, closed, fixed 52af38df). No hub mail after the deploy.
before the deploy (control that the channel delivers): 07:07:11Z Tester4 host_down, 07:04:11Z node_down, 06:22Z/06:19Z stale — the hub's mails do arrive
verdict: no new false alarm from the hub in the 30 minutes after the deploy; one CC-caused DooPlex mail, filed and fixed
@@ -0,0 +1,113 @@
# The hub's last plain tokens, sealed (R-975, R-1241's Felhom half) — 2026-10-23 night
Class: implementation (hub 0.168.0, built, **not deployed**) + a design for the backup copies (Part 1.4).
Architecture read: `architecture/05-hub-architecture.md` §16.2–§16.3 (sealing, the snapshot), `13-threat-model.md`
(attacker j, R-1241), `audits/plex2shell-felhom-impact-2026-10-23/README.md`. Names and places only — no value appears
here or in any file of this session. Every count below came from a read-only copy of the hub's own 14:00Z snapshot
(`VACUUM INTO`, so it holds every committed write), copied to a 0700 scratch folder and deleted after.
## 1. Every hub column that holds a secret (measured, 2026-10-23)
| Where | What | Before 0.168.0 | 0.168.0 |
|---|---|---|---|
| `hosts.api_key` | each box's hub key | sealed (R-879, 0.138.0) — 4/4 | same |
| `customer_configs.api_key`, `retrieval_password` | controller key, owner passphrase | sealed (R-879) — 5/5 each | same |
| `host_pbs_secrets.value` | PBS-DR token | sealed (R-879) — 4/4 | same |
| `one_time_secrets.value` | Storage Box sub-account password | sealed (R-821, 0.127.0) — 4/4 | same |
| `host_recovery.secret` | break-glass console password | sealed (R-133, 0.135.0) — 4/4 | same |
| **`customer_configs.config_json` → `infrastructure.cf_tunnel_token`** | Cloudflare tunnel token | **plain — 4 rows** | **sealed** |
| **`customer_configs.config_json` → `infrastructure.cf_api_token`** | Cloudflare API token | **plain — 4 rows** | **sealed** |
| **`customer_configs.config_json` → `git.token`** | git token (the form still accepts one) | none stored today | **sealed** when written |
| `host_escrow.blob`, `identity_blob`; `host_escrow_superseded.*` | escrow | age-wrapped by the household's recovery code — not the hub's to seal | same |
| `api_tokens.token_hash`, `selfbind_tokens.token_hash`, `appliance_registrations.token_hash`, `customer_claims.code_hash`, `hub_settings[operator_password_hash]` | operator tokens, bind tokens, claim codes, operator password | one-way hashes (SHA-256 / bcrypt) | same |
| `hosts.api_key_hash`, `customer_configs.api_key_hash` | lookup twins | unkeyed SHA-256 of a 256-bit random key (R-879) | same |
| `wg_peers.pubkey`, `wg_endpoints.server_pubkey`, `host_escrow.key_fingerprint`, `appliance_registrations.ssh_host_pubkeys`, `hub_settings[oob_operator_ssh_pubkey]` | public keys, fingerprints | not secret | same |
| `guests.api_key` | unused column | empty 7/7 | same |
| `appliance_registrations.pairing_code` | 6-character console code | plain, 31 rows | **NOT-A-FINDING:** it is printed on the box's screen and is only one of two factors; the other (the self-bind token) is stored as a hash. Pending registrations only. |
**Do the token VALUES sit anywhere else?** Each of the 8 distinct Cloudflare values was searched (by value, in memory,
never printed) in every column of every other table: **0 hits**. The key NAME `cf_tunnel_token` appears in one
`reports.report_json` and one `app_telemetry.issues_json` row — names, not values. `events.details_json` carries
`repo_key` (literally the word „changed") and PBS `token_id`s (a name like `user@pbs!name`, not a secret).
## 2. The change (hub 0.168.0)
- **Same mechanism, same key** (`05` §16.2): each token leaf in `config_json` holds `enc:v1:` + AES-256-GCM under
`OFFSITE_SECRET_KEY`. The rest of the JSON stays readable. `internal/store/r975_config_token_seal.go`.
- **New writes sealed:** `SaveCustomerConfig` (the only writer of `config_json`). No key and a token → refused.
- **Every reader opens through the existing helper:** `openCustomerSecrets`, which the three readers
(`GetCustomerConfig`, `GetCustomerConfigByAPIKey`, `ListCustomerConfigs`) already call. A leaf that does not open is
blanked and sets `SecretsUnreadable` (R-879's rule: never served, a save refuses the record, `configgen.Generate` refuses).
- **Old rows sealed once at start-up:** `SealLegacyConfigTokens`, logged as `config tokens sealed at rest (N legacy
plaintext token(s) sealed now)` — counts only. **No `config_version` bump** — the box's config is byte-for-byte the
same, so no box re-pulls or restarts. Expected on the live hub: N = 8 on the first start, 0 after.
- **Then one `VACUUM` + WAL checkpoint** (only when N > 0): an `UPDATE` leaves the old plaintext row in a freed block of
`hub.db` (the SQLite driver's `secure_delete` is 0 — measured). Timed on a copy of the live 534 MB database: **2.8 s**,
well inside the liveness probe's ~95 s. The volume has 2.4 GB free for it.
- **Roll-back:** `felhom-hub -unseal-box-secrets` now also opens these leaves (all or nothing), so going back to
0.167.0 stays the documented procedure (`05` §16.2). Without it an older hub would hand the box the sealed string as its
tunnel token.
**Tests, each red-proved** (the rule broken on purpose → the test failed → restored):
| Test | Pins | Red-proof (mutation → failed) |
|---|---|---|
| `TestR975_FreshWriteIsStoredSealed` | a fresh write is sealed; non-secret fields intact; no key → refused | write path unsealed → FAIL (with 5 others) |
| `TestR975_ReaderGetsTheSameValue` | all three readers + a load-modify-save return the same value | open on read removed → FAIL |
| `TestR975_MigrationSealsOnceThenNoOp` | 3 sealed, then 0; no `config_version`/`updated_at` change | migration no-op → FAIL; migration bumps the version → FAIL |
| `TestR975_DBFileWithoutKeyRevealsNoToken` | **a copy of `hub.db` + `-wal` + `-shm` greps clean**; positive control: the pre-0.168.0 rows DO show in the file | VACUUM removed → FAIL (the old row stays in a freed block) |
| `TestR975_WrongKeyBlanksAndRefusesSave` | wrong key → blanked, flagged, save refused, right key restores | not blanked → FAIL; flag ignores the tokens → FAIL |
| `TestR975_UnsealRestoresPlaintextForAnOlderHub` | roll-back opens the tokens, all or nothing | the config half skipped → FAIL |
| `TestR975_EveryFormSecretIsSealed` (web) | every leaf the operator form writes is either on a 2-name non-secret list or sealed | write path unsealed → FAIL |
| `TestR975_GeneratedConfigCarriesThePlainTunnelToken` (configgen) | the box still gets the REAL token in `controller.yaml` | open on read removed → FAIL |
Two first mutations broke the build instead of a test (an unused variable) and were redone so a test, not the
compiler, failed. The first version of the file test passed with the VACUUM removed — the token row was the last cell on
its page, so the new row overwrote it; a second customer written after it (as on the live hub) made the test honest.
**Run on a private copy of the real database** (the 14:00Z snapshot, in a 0700 scratch folder, with a THROWAWAY key —
the real one was never read; a temporary test file, deleted, never committed): the start-up sealing sealed **8** tokens
in **3.15 s** (incl. the VACUUM), a second run sealed **0**, all **5 of 5** customers' `config_json` read back equal to
the original (JSON-equal), and **0 of the 8** token values were found anywhere in the database files afterwards. A first
attempt compared whole records and showed „0 of 5 equal": the R-879 columns were sealed with the REAL key, so with the
throwaway key every record was flagged unreadable — the expected behaviour, not a defect; the second run compared the
JSON only. The copy was shredded after. Image: `gitea.dooplex.hu/admin/felhom-hub:0.168.0`
(`sha256:3bfdecaae527d4762059600cdfaad83daf4e4b5b20661fc47acf128180d87cb3`), from `5277d859`, CI run 2269 success.
**Measured on the live file (count of the key name only):** `cf_tunnel_token` occurs 12 times both in the live
`hub.db` and in the clean `VACUUM INTO` snapshot, so the live file holds no extra old copies today.
## 3. The backup copies — design only (Part 1.4)
**What exists today (measured):**
| Copy | Where | Encrypted? | Holds the tokens? |
|---|---|---|---|
| Hub snapshots `<data>/snapshots/` (2, 6-hourly) | the hub's Longhorn volume | no (the volume is `encrypted=false`) | after 0.168.0: sealed |
| **Longhorn backups of the hub volume** | `/mnt/5_hdd/backup/longhorn-pvc` (the NFS folder of R-1241) — **2 backups: 2026-10-18 03:00Z (weekly) and 2026-10-23 02:01Z (daily)**, ~4.1 GB each, `retain 1` each | **no** | **yes, in plaintext** — both predate 0.168.0 |
| The hub's own copy to ep0 (`felhom-hub-db-backup`, 6-hourly :30) | ep0 PBS, namespace `operator` | **yes, at rest:** 16 snapshots 2026-10-10 → 10-23, every `hubdb.pxar.didx` and catalog `crypt-mode: encrypt` (`index.json.blob` sign-only). The key `/etc/felhom-hub-backup/enc.key` is on DooPlex's **root disk (sdb1)**, not on the NFS disk, and on paper (S2). **In transit:** SSH port-forward `127.0.0.1:18007` + PBS TLS with a pinned fingerprint. Last push 14:31 CEST today, 7 s; the weekly restore-test last passed 2026-10-18 („4 sealed console password(s), 0 readable"). | sealed after 0.168.0 |
**The two options:**
| | (a) Encrypt the hub's Longhorn volume | (b) Take the hub volume out of the Longhorn NFS backup |
|---|---|---|
| What | A new Longhorn volume with `encrypted=true` (a StorageClass with a crypto Secret), copy `/data` across, point `manifests/hub.yaml` at it | Remove the volume from the `default` recurring-job group (one label on the Longhorn volume); the ep0 copy is the hub's only backup |
| Hub downtime | ~5–10 min (scale to 0, copy 1.5 GB, scale up) | none |
| Who | homelab (a StorageClass + Secret in `longhorn-system`) + a Felhom manifest change | homelab (the Longhorn volume label); no Felhom code |
| New key to keep | yes — the volume passphrase, on paper, and it lives in the cluster where the R-1241 attacker reaches the Longhorn API | none |
| What it fixes | the backups stay but are ciphertext; also the volume's freed blocks | no more hub copies in the NFS folder at all |
| What it loses | nothing | the hub's 90-day access log (`/data/access-log`, R-1140) and its local snapshots are no longer backed up anywhere; a lost volume is restored from ep0 (`RUNBOOK-hub-db-offsite-backup.md` §restore, restore-tested weekly) — at most ~6.5 h of hub data lost, the same as today's off-site promise |
| Does the encryption key sit next to the data? | yes (cluster Secret) | the PBS key is on another disk and on paper |
**CC's pick: (b)**, because the ep0 copy is already encrypted at rest and in transit (measured above), off-site, every 6
hours, and restore-tested weekly — the Longhorn copy adds a second, unencrypted copy in exactly the folder R-1241 found
open, and (a) would put its key in the same cluster. The access log's loss can be closed later by adding
`/data/access-log` to the ep0 push (small; not tonight). → decide row **R-1243**.
**The plain copies already in the folder** (the two hub-volume backups above): they hold today's tokens in plaintext.
Deleting backups is the operator's decision. Without action they rotate out by themselves after 0.168.0 is deployed —
the daily one at the next 04:00 run, the weekly one at the next Sunday 05:00 run (`retain 1` each) — **but only if the
volume stays in the backup job** (option a, or no decision). With option (b) the last two copies stay until someone
deletes them. Either way the tokens in them should then be considered exposed only if R-1241's door is used — the
Plex2Shell audit measured it was not. **Note:** Longhorn backs up the volume's blocks, so a block freed by the VACUUM can
still hold old plaintext in a later Longhorn backup; only (a) or (b) removes that — not measured, reasoned.
@@ -0,0 +1,81 @@
# Plex to the fixed version on the demo/test boxes — 2026-10-23 (Plex2Shell)
Operator ruling 2026-10-23 10:56 (recorded in `CONTEXT.md`): move the catalog's Plex to the newest fixed version at once,
without the test record of `09` §3 decision 13, and put the demo boxes on it. DooPlex and ep0 were not touched; the
incident session handles DooPlex.
## The catalog move
- Catalog `6cc317d`: `plexinc/pms-docker:1.41.4.9463-630c9f557` → `1.43.5.11029-6bf8af3f0` (Docker Hub, pushed
2026-10-20; manifest list `sha256:01bdf0ad6d53198da4331540c1e73ab65db7a72e961fff97ecb0847d46055c5f`, re-resolved at
start — still the newest plain `X.Y.Z.B-hash` tag; `public`/`beta`/`plexpass` moved on 2026-10-22 but carry no plain
tag and are excluded). `catalog_since: "2026-10-23"`.
- Gates green: image-pins, catalog-since (range), test-record, image-resolvable (plex), `catalog_gates.py --fast plex`.
`check-test-record-move.py --range ce33e3b..6cc317d` refused, as expected (verbatim in `app-catalog-felhom.eu/REPORT.md`).
Pushed with `--no-verify`, that commit only.
- Read back from the box's catalog cache on demo-hp 9201 after one sync: the new tag, `catalog_since: "2026-10-23"`,
HEAD `6cc317d`. The badge went to „Frissítés elérhető — ma" / „Update available — today" in 4.7 s.
## Which boxes run Plex
Hub `/hosts` (CC token, read only): four hosts — Tester4 (DOWN), demo-felhom, demo-hp, tester-1. The customer
**Tester 2 has 0 hosts**, so the operator's question was not needed. The hub's `/apps` page counts 2 Plex deployments;
the boxes say ONE runs it (a second channel: `docker ps -a` in every running guest):
| Box | Guest | Plex |
|---|---|---|
| demo-hp | 9201 | yes, 1.41.4.9463-630c9f557 |
| demo-hp | 9202 (scratch) | no |
| demo-felhom (N100) | 9201 | no |
| tester-1 (VM 341 on demo-hp) | 9201 | no |
| Tester4 | — | the hub host is DOWN and its VM no longer exists on demo-hp or felhom-pve (`qm list`); nothing to update. The hub's second Plex deployment is most likely this stale host's last report (not proven). |
## demo-hp 9201 — the signs check (before the update, read only) → **NOT-A-FINDING**
Scripts: `demo-hp-9201/signs.sh`, `demo-hp-9201/signs2.sh` (run inside the guest). Outputs, e-mail and token redacted:
`demo-hp-9201/signs-9201-before-update.txt`, `demo-hp-9201/signs2-9201-before-update.txt`.
| Sign | Result | Control |
|---|---|---|
| CPU, last days | whole guest 0.23–0.34 cores average of 7, max 1.04, per day 10-16 → 10-23 (PVE rrd, the HOST's channel). A miner would hold several cores flat. | — |
| Processes in the container | only s6, Plex Media Server, Plex Script Host, Plex Tuner Service | — |
| `xmrig`, `mylovelyminer`, `x12345`, `myawesomeproxy` anywhere in the guest | none | — |
| ELF files under `Codecs` | none (one file, `.device-id`; one empty codec dir from 2026-10-15) | the ELF test says ELF for `/usr/bin/docker`, not for `Preferences.xml` |
| ELF > 10 kB in the config volume newer than 2026-10-15 | none | same |
| Container layer (`docker diff plex`) | 80 entries, all s6 runtime under `/run` | — |
| `TranscoderH264Options` / `…Override` in `Preferences.xml` | absent | the attribute list printed (27 names) |
| Log lines `searchOne`, `/video/:/transcode/universal`, `?x=http…` | 0, 0, 0 | 633 `Request: [` lines in the same log |
| Open connections from the container | plex.tv / Cloudflare 443 and the box's traefik only | — |
**Limit, stated:** Plex keeps 6 rotated logs and restarted several times in the night, so the logs reach back only to
2026-10-23 00:32 UTC — not to 2026-10-16. The 10-16 → 10-22 window is covered by the CPU history and the files only,
not by the logs. The container was recreated at 04:39 UTC, so its layer has no history before that either.
## The update (the product's Update press, `POST /api/stacks/plex/update`)
`demo-hp-9201/update-press.json`: accepted 202; phases safety-dump → pulling → copying → verifying → done in 28.4 s;
no error, no hold. After (`demo-hp-9201/after-update.txt`):
- `/identity`: version `1.43.5.11029-6bf8af3f0`, `claimed: true`, the SAME `machineIdentifier` as before.
- Library: 0 sections before and after (this Plex never had a library; `demo-hp-9201/library-before-update.txt`). The
server's identity and claim are what carried over.
- Box walk: every container healthy (traefik has no health check, up), none restarting; 0 `[ERROR]` and 0 `[WARN]` lines
in the controller log since the press (control: 99 `[INFO]` lines in the same window); badge „Naprakész" / „Up to date";
pinned = installed = catalog = live compose = the running container, all the new tag.
## The guide (Part 3)
The guide's labels were read from the new image's own web client (`WebClient.bundle/.../translations/hu.json`, plex-web
4.162.1; its keys are the English labels): Home/„Kezdőképernyő", Play/„Lejátszás", Scan Library Files/„Könyvtárfájlok
beolvasása", More/„Több", Fix Match/„Találatok pontosítása", Settings/„Beállítások", Manage Library Access/„Könyvtár
hozzáférés kezelése", and the FAQ's Video Quality/„Videó minőség", Original/„Eredeti" — all present, all equal
(`demo-hp-9201/guide-labels-1.43.5.txt`; ASCII-fragment controls: `beolvas` 5, `kezel` 26, `xqzzyw` 0). The box's own
Plex wiring (`POST /api/storage/media/wire`, the household's „connect now") answered `plex: unchanged`, no error, against
the new Plex (`demo-hp-9201/guide-wiring-after-update.txt`). **Not exercised:** the wiring's PUT that adds a new
drive's folder — this box has one drive and no library, so it had nothing to add. `guide.checked_version` moved.
## Teardown
- Machine: Plex stays on the new version (that is the goal). The helper scripts were removed from the guest and host.
- Host: nothing provisioned.
- Hub: nothing changed (reads only).
@@ -0,0 +1,57 @@
identity: {"MediaContainer":{"size":0,"apiVersion":"1.2.3","claimed":true,"machineIdentifier":"fb56097105b927dd42576cd879499a50c064c9fc","version":"1.43.5.11029-6bf8af3f0"}}
sections: 0
---containers
adventurelog Up 5 hours (healthy)
adventurelog-frontend Up 5 hours (healthy)
adventurelog-postgres Up 5 hours (healthy)
bentopdf Up 5 hours (healthy)
bookstack Up 5 hours (healthy)
bookstack-db Up 5 hours (healthy)
calibre-web Up 5 hours (healthy)
cloudflared Up 2 days (healthy)
docmost Up 4 hours (healthy)
docmost-postgres Up 5 hours (healthy)
docmost-redis Up 5 hours (healthy)
felhom-controller Up 3 hours (healthy)
filebrowser Up 2 days (healthy)
home-assistant Up 4 hours (healthy)
opengist Up 4 hours (healthy)
paperless-postgres Up 4 hours (healthy)
paperless-redis Up 4 hours (healthy)
paperless-webserver Up 4 hours (healthy)
plex Up 48 seconds (healthy)
privatebin Up 4 hours (healthy)
romm Up 4 hours (healthy)
romm-db Up 4 hours (healthy)
romm-redis Up 4 hours (healthy)
traefik Up 30 hours
---not-healthy
---restarting
---ctl-errors-since-update
0
---ctl-plex-lines
2026/10/23 09:08:22 manager.go:675: [DEBUG] [stacks] ScanStacks: found stack "plex" deployed=true composePath=/opt/docker/stacks/plex/docker-compose.yml
2026/10/23 09:08:22 healthprobe.go:64: [DEBUG] [stacks] RunHealthProbes: skipping plex — last check 4s ago, effective interval 5m0s, healthy=true
2026/10/23 09:08:22 backup.go:526: [DEBUG] groupStacksByDrive: /mnt/felhom-drives/hdd_1 → [calibre-web, paperless-ngx, plex, romm]
2026/10/23 09:08:23 dbdump.go:149: [DEBUG] DiscoverDatabases: docker ps output: e94565919cd7 plex plex plexinc/pms-docker:1.43.5.11029-6bf8af3f0
f8900ef8917f felhom-controller gitea.dooplex.hu/admin/felhom-controller:0.340.0
2026/10/23 09:08:23 dbdump.go:171: [DEBUG] DiscoverDatabases: skipping container plex (image=plexinc/pms-docker:1.43.5.11029-6bf8af3f0, not a database)
2026/10/23 09:08:23 dbdump.go:171: [DEBUG] DiscoverDatabases: skipping container felhom-controller (image=gitea.dooplex.hu/admin/felhom-controller:0.340.0, not a database)
2026/10/23 09:08:23 sync.go:559: [DEBUG] [sync] plex/docker-compose.yml: hash match, skipped
2026/10/23 09:08:23 sync.go:559: [DEBUG] [sync] plex/.felhom.yml: hash match, skipped
2026/10/23 09:08:23 [INFO] [stacks] ParseComposeHDDMounts: found 0 HDD mounts for /opt/docker/stacks/plex/docker-compose.yml
2026/10/23 09:08:23 recovery_unit.go:248: [INFO] [backup] plex: the app now runs [plexinc/pms-docker:1.43.5.11029-6bf8af3f0]; the unit keeps the definition of its data ([plexinc/pms-docker:1.41.4.9463-630c9f557], written 2026-10-23T02:16:55Z) until the next backup replaces the data
2026/10/23 09:08:23 recovery_unit.go:289: [INFO] [backup] Recovery unit captured for plex → /mnt/felhom-drives/hdd_1/backups/primary/plex (images=1, secrets-referenced=0, data_keys=0, portable-carried=0/0, withheld=0)
2026/10/23 09:08:24 auth.go:144: [DEBUG] [web] auth: valid session for GET /apps/plex
2026/10/23 09:08:24 server.go:637: [DEBUG] [web] ServeHTTP: GET /apps/plex from 172.18.0.10:45638
2026/10/23 09:08:24 handlers.go:421: [DEBUG] [web] deployPageData: stack=plex method=GET
2026/10/23 09:08:24 auth.go:144: [DEBUG] [web] auth: valid session for GET /apps/plex
2026/10/23 09:08:24 server.go:637: [DEBUG] [web] ServeHTTP: GET /apps/plex from 172.18.0.10:45638
2026/10/23 09:08:24 handlers.go:421: [DEBUG] [web] deployPageData: stack=plex method=GET
2026/10/23 09:08:24 auth.go:144: [DEBUG] [web] auth: valid session for GET /api/stacks/plex
2026/10/23 09:08:24 router.go:78: [DEBUG] [api] GET /api/stacks/plex (path=/stacks/plex)
2026/10/23 09:08:25 logscanner.go:69: [DEBUG] [metrics] logscanner: scanned plex: errors=0 warnings=0 issues=0 (took 28ms)
2026/10/23 09:08:32 healthprobe.go:64: [DEBUG] [stacks] RunHealthProbes: skipping plex — last check 13s ago, effective interval 5m0s, healthy=true
2026/10/23 09:08:42 healthprobe.go:64: [DEBUG] [stacks] RunHealthProbes: skipping plex — last check 23s ago, effective interval 5m0s, healthy=true
2026/10/23 09:08:52 healthprobe.go:64: [DEBUG] [stacks] RunHealthProbes: skipping plex — last check 33s ago, effective interval 5m0s, healthy=true
2026/10/23 09:09:02 healthprobe.go:64: [DEBUG] [stacks] RunHealthProbes: skipping plex — last check 43s ago, effective interval 5m0s, healthy=true
@@ -0,0 +1,10 @@
Plex web client translations/hu.json from plexinc/pms-docker:1.43.5.11029-6bf8af3f0 (WebClient plex-4.162.1), keys = the English UI string
EN key 'Home': present=True; HU in Plex='Kezdőképernyő'; guide HU='Kezdőképernyő'; match=True
EN key 'Play': present=True; HU in Plex='Lejátszás'; guide HU='Lejátszás'; match=True
EN key 'Scan Library Files': present=True; HU in Plex='Könyvtárfájlok beolvasása'; guide HU='Könyvtárfájlok beolvasása'; match=True
EN key 'More': present=True; HU in Plex='Több'; guide HU='Több'; match=True
EN key 'Fix Match': present=True; HU in Plex='Találatok pontosítása'; guide HU='Találatok pontosítása'; match=True
EN key 'Settings': present=True; HU in Plex='Beállítások'; guide HU='Beállítások'; match=True
EN key 'Manage Library Access': present=True; HU in Plex='Könyvtár hozzáférés kezelése'; guide HU='Könyvtár hozzáférés kezelése'; match=True
EN key 'Video Quality': present=True; HU in Plex='Videó minőség'; guide HU='Videó minőség'; match=True
EN key 'Original': present=True; HU in Plex='Eredeti'; guide HU='Eredeti'; match=True
@@ -0,0 +1,2 @@
status 200 {"data": {"pending": false, "drives": null, "apps": ["plex"], "wiring": [{"app": "folders", "state": "done"}, {"app": "plex", "state": "unchanged"}], "wired_at": "2026-10-23T09:10:30Z"}, "ok": true}
wire 200 {"data": [{"app": "folders", "state": "done"}, {"app": "plex", "state": "unchanged"}], "ok": true}
@@ -0,0 +1,2 @@
identity: {"MediaContainer":{"size":0,"apiVersion":"0.1.0","claimed":true,"machineIdentifier":"fb56097105b927dd42576cd879499a50c064c9fc","version":"1.41.4.9463-630c9f557"}}
sections: 0
@@ -0,0 +1,63 @@
### 1. processes in the plex container (docker top)
PID USER ELAPSED TIME %CPU COMMAND
1493203 root 04:25:08 00:00:00 0.0 s6-svscan
1493262 root 04:25:08 00:00:00 0.0 s6-supervise
1493541 root 04:25:08 00:00:00 0.0 s6-supervise
1493544 1000 04:25:08 00:00:21 0.1 Plex Media Serv
1493588 1000 04:25:08 00:00:15 0.0 Plex Script Hos
1494146 1000 04:25:05 00:00:12 0.0 Plex Tuner Serv
### 1b. suspect names anywhere in the guest
none
### 1c. top CPU processes in the guest
PID USER %CPU ELAPSED COMMAND
235 root 1.7 2-06:15:22 dockerd
183 root 0.8 2-06:15:23 containerd
1493858 999 0.7 04:25:07 redis-server
1489649 999 0.6 04:25:33 redis-server
1492193 999 0.6 04:25:19 redis-server
1717354 root 0.3 02:26:14 felhom-controll
1496145 root 0.3 04:24:23 gunicorn
1698 65532 0.3 2-06:15:16 cloudflared
1496141 root 0.3 04:24:23 gunicorn
1492308 1000 0.2 04:25:19 node-MainThread
1495252 1000 0.2 04:24:46 [celeryd: celer
### 2. ELF files under Codecs (path size mtime sha256)
all files under Codecs: 1
total 16
drwxr-xr-x 3 1000 1000 4096 2026-10-15 08:46:05.701113471 +0000 .
drwxr-xr-x 11 1000 1000 4096 2026-10-23 08:39:53.737639828 +0000 ..
-rw-r--r-- 1 1000 1000 36 2026-10-15 08:46:05.701113471 +0000 .device-id
drwxr-xr-x 2 1000 1000 4096 2026-10-15 08:46:05.700807513 +0000 e613bce-97f23d579c1001d8e9cc0d2e-linux-x86_64
### 2b. any ELF in the config volume outside Plex's own folders, newer than 2026-10-15
(end 2b)
### 3. Preferences.xml transcoder attributes
TranscoderH264Options*: absent
attribute names present:
AcceptedEULA AnonymousMachineIdentifier CertificateUUID CertificateVersion DlnaEnabled FSEventLibraryPartialScanEnabled FSEventLibraryUpdatesEnabled GlobalMusicVideoPathMigrated LanguageInCloud LastAutomaticMappedPort MachineIdentifier MetricsEpoch OldestPreviousVersion PlexOnlineHome PlexOnlineMail PlexOnlineToken PlexOnlineUsername ProcessedMachineIdentifier PubSubServer PubSubServerPing PubSubServerRegion PublishServerOnPlexOnlineKey TranscoderTempDirectory customConnections encoding version
### 4. log lines: searchOne / transcode/universal (tokens redacted)
total 940
drwxr-xr-x 3 1000 1000 4096 2026-10-23 04:39:29.306642337 +0000 .
drwxr-xr-x 11 1000 1000 4096 2026-10-23 08:39:53.737639828 +0000 ..
drwxr-xr-x 2 1000 1000 4096 2026-10-23 04:39:30.774964086 +0000 PMS Plugin Logs
-rw-r--r-- 1 1000 1000 880 2026-10-23 04:38:23.878139505 +0000 Plex Crash Uploader.1.log
-rw-r--r-- 1 1000 1000 561 2026-10-23 03:34:34.438792292 +0000 Plex Crash Uploader.2.log
-rw-r--r-- 1 1000 1000 880 2026-10-23 03:33:23.603543601 +0000 Plex Crash Uploader.3.log
-rw-r--r-- 1 1000 1000 561 2026-10-23 02:59:31.142955018 +0000 Plex Crash Uploader.4.log
-rw-r--r-- 1 1000 1000 880 2026-10-23 02:58:23.855206791 +0000 Plex Crash Uploader.5.log
-rw-r--r-- 1 1000 1000 561 2026-10-23 04:39:28.559376452 +0000 Plex Crash Uploader.log
-rw-r--r-- 1 1000 1000 122590 2026-10-23 04:38:23.956828290 +0000 Plex Media Server.1.log
-rw-r--r-- 1 1000 1000 95344 2026-10-23 03:33:23.650544218 +0000 Plex Media Server.2.log
-rw-r--r-- 1 1000 1000 97012 2026-10-23 02:58:23.959207947 +0000 Plex Media Server.3.log
-rw-r--r-- 1 1000 1000 96861 2026-10-23 02:38:23.762270724 +0000 Plex Media Server.4.log
-rw-r--r-- 1 1000 1000 157007 2026-10-23 02:16:45.904202135 +0000 Plex Media Server.5.log
-rw-r--r-- 1 1000 1000 311157 2026-10-23 09:04:06.104368626 +0000 Plex Media Server.log
-rw-r--r-- 1 1000 1000 2769 2026-10-23 04:38:23.939140257 +0000 Plex Tuner Service.1.log
-rw-r--r-- 1 1000 1000 2769 2026-10-23 03:33:23.635544021 +0000 Plex Tuner Service.2.log
-rw-r--r-- 1 1000 1000 2769 2026-10-23 02:58:23.938207713 +0000 Plex Tuner Service.3.log
-rw-r--r-- 1 1000 1000 2769 2026-10-23 02:38:23.745270485 +0000 Plex Tuner Service.4.log
-rw-r--r-- 1 1000 1000 2769 2026-10-23 02:16:45.852201461 +0000 Plex Tuner Service.5.log
-rw-r--r-- 1 1000 1000 1855 2026-10-23 04:39:39.105066764 +0000 Plex Tuner Service.log
count searchOne: 0
count transcode/universal: 0
count lines with http(s):// in a query: 0
oldest log line: Oct 23, 2026 02:32:13.754 [1343875524390
@@ -0,0 +1,34 @@
#!/bin/sh
# Read-only Plex2Shell signs check, run INSIDE the guest. Prints no token.
V=/var/lib/docker/volumes/plex_plex_config/_data
P="$V/Library/Application Support/Plex Media Server"
echo "### 1. processes in the plex container (docker top)"
docker top plex -eo pid,user,etime,time,pcpu,comm
echo "### 1b. suspect names anywhere in the guest"
ps -eo pid,user,comm,args | grep -i -E 'xmrig|mylovelyminer|x12345|myawesomeproxy' | grep -v grep || echo "none"
echo "### 1c. top CPU processes in the guest"
ps -eo pid,user,pcpu,etime,comm --sort=-pcpu | head -12
echo "### 2. ELF files under Codecs (path size mtime sha256)"
if [ -d "$P/Codecs" ]; then
find "$P/Codecs" -type f | while read -r f; do
if head -c 4 "$f" | grep -q 'ELF'; then
printf '%s\t%s\t%s\t%s\n' "$f" "$(stat -c %s "$f")" "$(stat -c %y "$f")" "$(sha256sum "$f" | cut -c1-64)"
fi
done
echo "all files under Codecs: $(find "$P/Codecs" -type f | wc -l)"
ls -la --time-style=full-iso "$P/Codecs"
else echo "no Codecs dir"; fi
echo "### 2b. any ELF in the config volume outside Plex's own folders, newer than 2026-10-15"
find "$V" -type f -newermt 2026-10-15 -size +10k 2>/dev/null | while read -r f; do head -c 4 "$f" | grep -q ELF && printf '%s\t%s\t%s\n' "$f" "$(stat -c %s "$f")" "$(sha256sum "$f"|cut -c1-64)"; done; echo "(end 2b)"
echo "### 3. Preferences.xml transcoder attributes"
grep -o -E 'TranscoderH264Options(Override)?="[^"]*"' "$P/Preferences.xml" || echo "TranscoderH264Options*: absent"
echo "attribute names present:"; grep -o -E ' [A-Za-z]+="' "$P/Preferences.xml" | tr -d ' ="' | sort | tr '\n' ' '; echo
echo "### 4. log lines: searchOne / transcode/universal (tokens redacted)"
ls -la --time-style=full-iso "$P/Logs/" | head -30
for f in "$P/Logs/"Plex\ Media\ Server*.log; do
grep -h -E 'searchOne|/video/:/transcode/universal' "$f" 2>/dev/null
done | sed -E 's/(X-Plex-Token|PlexOnlineToken|token)=[^&" ]*/\1=REDACTED/gI' | head -200
echo "count searchOne: $(cat "$P/Logs/"Plex\ Media\ Server*.log 2>/dev/null | grep -c searchOne)"
echo "count transcode/universal: $(cat "$P/Logs/"Plex\ Media\ Server*.log 2>/dev/null | grep -c '/video/:/transcode/universal')"
echo "count lines with http(s):// in a query: $(cat "$P/Logs/"Plex\ Media\ Server*.log 2>/dev/null | grep -c -E '[?&][a-zA-Z]+=https?(%3A|:)')"
echo "oldest log line: $(head -1 "$P/Logs/Plex Media Server.5.log" 2>/dev/null | cut -c1-40)"
File diff suppressed because one or more lines are too long
@@ -0,0 +1,21 @@
#!/bin/sh
V=/var/lib/docker/volumes/plex_plex_config/_data
P="$V/Library/Application Support/Plex Media Server"
echo "### controls"
printf 'ELF detector on /usr/bin/docker (positive): '; head -c 4 /usr/bin/docker | grep -q ELF && echo ELF || echo not-ELF
printf 'ELF detector on Preferences.xml (negative): '; head -c 4 "$P/Preferences.xml" | grep -q ELF && echo ELF || echo not-ELF
echo "log grep positive control (lines with 'Request: [' in current log): $(grep -c 'Request: \[' "$P/Logs/Plex Media Server.log")"
echo "### docker diff plex (files changed in the container layer)"
docker diff plex | head -60; echo "total changes: $(docker diff plex | wc -l)"
echo "### created / started / restarts"
docker inspect plex --format 'created={{.Created}} started={{.State.StartedAt}} restarts={{.RestartCount}}'
echo "### transcode volume: files"
find /var/lib/docker/volumes/plex_plex_transcode/_data -type f | head; echo "(n=$(find /var/lib/docker/volumes/plex_plex_transcode/_data -type f | wc -l))"
echo "### crash uploader log (latest)"
sed -E 's/(token|Token)[=:" ]+[A-Za-z0-9_-]{8,}/\1=REDACTED/g' "$P/Logs/Plex Crash Uploader.1.log"
echo "### first lines of each PMS log (start time)"
for f in "$P/Logs/"Plex\ Media\ Server*.log; do echo "$(basename "$f"): $(head -1 "$f" | cut -c1-24)"; done
echo "### outbound connections now from plex netns"
PID=$(docker inspect -f '{{.State.Pid}}' plex); nsenter -t $PID -n ss -tnp 2>/dev/null | head -20
echo "### docker logs plex (tail, redacted)"
docker logs --tail 30 plex 2>&1 | sed -E 's/(claim-|token=)[A-Za-z0-9_-]+/\1REDACTED/g'
@@ -0,0 +1,78 @@
{
"update": {
"accepted": true,
"http": "202",
"phases": [
{
"t": 0.0,
"phase": "safety-dump",
"label": "Adatbázis pillanatkép…",
"updating": true,
"error": null,
"hold": null
},
{
"t": 4.1,
"phase": "pulling",
"label": "Új verzió letöltése…",
"updating": true,
"error": null,
"hold": null
},
{
"t": 10.1,
"phase": "copying",
"label": "Az adatok másolása a frissítés előtt…",
"updating": true,
"error": null,
"hold": null
},
{
"t": 22.3,
"phase": "verifying",
"label": "Működés ellenőrzése…",
"updating": true,
"error": null,
"hold": null
},
{
"t": 28.4,
"phase": "done",
"label": "Frissítve",
"updating": false,
"error": null,
"hold": null
}
],
"duration_s": 28.4,
"final_phase": "done",
"update_error": null,
"hold_reason": null,
"state": "running"
},
"observables": {
"pinned_images": {
"plex": "plexinc/pms-docker:1.43.5.11029-6bf8af3f0"
},
"installed_images": {
"plex": "plexinc/pms-docker:1.43.5.11029-6bf8af3f0"
},
"catalog_images": {
"plex": "plexinc/pms-docker:1.43.5.11029-6bf8af3f0"
},
"live_compose_image_lines": [
"image: plexinc/pms-docker:1.43.5.11029-6bf8af3f0"
],
"docker_inspect": [
"plex plexinc/pms-docker:1.43.5.11029-6bf8af3f0 running=true restarts=0"
]
},
"log": [
"11:07:51 [6] Update -> 202 {'ok': True, 'data': {'accepted': True, 'completed': False}, 'message': 'Frissítés elindult – az állapot a kártyán követhető'}",
"11:07:51 + 0.0s phase=safety-dump label=Adatbázis pillanatkép… err=None hold=None",
"11:07:55 + 4.1s phase=pulling label=Új verzió letöltése… err=None hold=None",
"11:08:01 + 10.1s phase=copying label=Az adatok másolása a frissítés előtt… err=None hold=None",
"11:08:14 + 22.3s phase=verifying label=Működés ellenőrzése… err=None hold=None",
"11:08:20 + 28.4s phase=done label=Frissítve err=None hold=None"
]
}
@@ -0,0 +1,148 @@
# Plex2Shell on DooPlex — did the attack reach Felhom's secrets? (2026-10-23)
Read-only investigation. Source of the incident facts: `~/incident-plex-2026-10-23/INCIDENT.md` on DooPlex (HM-040,
homelab session). Architecture read first: `architecture/01-topology-and-trust.md`, `04-control-plane-authorization.md`
§3.1, `05-hub-architecture.md` §16.2, `13-threat-model.md`, `runbooks/secrets.md`, `runbooks/total-loss-of-dooplex.md`,
`runbooks/target-selection.md` (DooPlex = Tier 2). Window: **2026-10-17 04:00Z → 2026-10-23 08:04:34Z** (the isolation
NetworkPolicy `incident-2026-10-23-plex-isolate`, `creationTimestamp` in INCIDENT.md Phase 2a).
## Verdict: **NOT REACHED**
Two open paths led from the hacked Plex pod to Felhom secrets. Each would have left a trace in a record that survived,
and neither trace exists:
1. **NFS export** (`/mnt/5_hdd/backup/longhorn-pvc`, `*(rw,no_root_squash,no_subtree_check)`): the NFS server accepted
**zero new TCP connections from 2026-10-10 00:00Z to 2026-10-23 13:05Z** — `node_nfsd_connections_total` flat at 288,
3902 five-minute samples, no gap. Every NFS request needs a TCP connection (nfsd listens on TCP only: `portlist`,
`rpcinfo`). **Positive control:** after this session's probe pod made three TCP connections to :2049 today the counter
read 4 (one Longhorn client + three probes), in `/proc/net/rpc/nfsd` and in Prometheus alike. The only NFS client in
the window was Longhorn's own manager (one long-lived NFSv4.2 connection). Read operations happened only in Longhorn's
backup hours; bytes read per day stayed at 18–39 MiB.
2. **Longhorn manager API** (no login, port 9500 — can create backups, backup targets, volumes): no backup was created
outside the two recurring jobs' times (`longhorn_backup_state` series, 1-minute scrape); every scheduled night of the
window wrote its backups to DooPlex's own NFS store (so the target was local each night); no volume existed in the
window that is not explained; the backup target object is the one created 2025-11-29; DooPlex's network card sent
no more than the Plex pod itself sent.
**What would change this verdict:** evidence of a container escape to the host (the incident session found none,
`INCIDENT.md` „Anything OUTSIDE the Plex pod"), or a Longhorn target swap + backup + delete inside one minute (no
record either way; Longhorn manager logs were lost, below).
## Part 1 — the shared backup folder
| what | value | evidence |
|---|---|---|
| export (before) | `/mnt/5_hdd/backup/longhorn-pvc *(rw,sync,no_subtree_check,no_root_squash)` | `p1-nfs-exports-clients.txt` |
| who can reach :2049 | the host firewall accepts 192.168.0.0/24, 10.42.0.0/16 (pods), 10.43.0.0/16, 100.64.0.0/10 (tailnet) | `nft list ruleset`, input chain |
| `secure` option | **no protection inside a pod**: containerd 2.x sets `net.ipv4.ip_unprivileged_port_start=0` in every pod; a uid-1000 probe with CapEff 0 bound port 700 and connected to :2049 | `p2-targeted-probes.txt` (last line), sysctl read in the Plex pod netns = 0, host = 1024 |
| filesystem | the export is a sub-directory of `/dev/sda1` (ext4, mounted at `/mnt/5_hdd`); root inode 2 has generation 0 | `findmnt`, `lsattr -vd /mnt/5_hdd` |
| contents | Longhorn backup store, 119 GB: nightly backups of every Longhorn volume, **including `felhom-system/hub-data` (the hub database), NOT encrypted** (`spec.encrypted=false` on all four felhom-system volumes) | `p1-backup-folder-listing.txt` |
| v4 pseudo-root | `/`, `/mnt`, `/mnt/5_hdd`, `/mnt/5_hdd/backup` appear read-only as path components only; no other directory under `/mnt/5_hdd/backup` is exported | `/proc/fs/nfsd/exports` |
| clients now | one: `longhorn-manager-w4tf6` 10.42.0.214, NFSv4.2 | `/proc/fs/nfsd/clients/*/info` |
| NFS logging | NFSv3 mounts are logged only at debug level; NFSv4 attaches are not logged at all (**positive control:** client 3 is attached and the journal has no attach line); detaches are logged (2 lines in boot -1, none in the window); illegal-port refusals are logged (none). An absent line proves nothing for v4. | `journalctl -t rpc.mountd`, `strings rpc.mountd` |
**No subtree check matters beyond the folder.** With `no_subtree_check` on a sub-directory export, the server checks
only that a file handle belongs to the exported *filesystem*. A published technique (HvS-Consulting's
`nfs-security-tooling`, 2024) builds the handle of the filesystem's root directory and walks the whole disk; with
`no_root_squash` it does so as root. On `/dev/sda1` that reaches the **operator signing keys** (`/mnt/5_hdd/felhom.eu/
felhom-op-operational`, `felhom-rec-recovery`, `felhom_op_ed25519`, no passphrase, R-924), the private security-review
evidence, the workspace, the encrypted `sec` store (its age key is on `/dev/sdb1`, not reachable) and the other backup
trees. **Grade: documented technique, every precondition measured here, NOT exercised** (doing it would be an attack on
a Tier-2 machine).
**The change (operator yes, 2026-10-23 ~15:18Z):** the line became
`/mnt/5_hdd/backup/longhorn-pvc 10.42.0.0/16(rw,sync,no_subtree_check,no_root_squash)`; `exportfs -ra` rc 0. Read back:
`exportfs -v` and `/proc/fs/nfsd/exports` show `10.42.0.0/16`; Longhorn's backup target synced at 15:20:10Z with
`available: true`; the Longhorn client is still attached. Backup of the old file: `/etc/exports.bak-2026-10-23-plex2shell`.
Undo: `sudo cp -p /etc/exports.bak-2026-10-23-plex2shell /etc/exports && sudo exportfs -ra`. **This closes the folder to
the home network and the tailnet. It does NOT close it to a hacked pod** — Longhorn connects from its pod address, so
the pod network must stay allowed; limiting it to DooPlex itself would break Longhorn. Root squash is not possible either
(the store is root-owned 0700 and Longhorn writes as root). `p1-export-change.txt`.
## Part 2 — what the hacked Plex could reach without a login
Measured from probe pod `default/cc-p2s-probe` (uid 1000, CapEff 0, no service-account token, no NetworkPolicy in
`default` — the Plex pod's position before the isolation). Created 15:19:46Z, removed 15:33:44Z
(`p2-probe-lifecycle.txt`, before/after listings). 186 of 196 TCP Service ports answered (`p2-service-sweep.txt`).
| target | no-login result | what a no-login caller gets |
|---|---|---|
| Longhorn manager API `longhorn-backend:9500`, UI `longhorn-frontend:80` | 200 | every volume (234 names), backup targets, backup volumes; actions `snapshotCreate`, `snapshotBackup`, `attach`, `detach`, `pvcCreate`, `activate` offered on `hub-data` |
| NFS on the node :2049, :111 | open | see Part 1 |
| Felhom hub `hub:8080` (bypasses the ingress geo filter) | `/healthz` 200, `/login` 200, every data path 401/403/302 | nothing (matches `13` §4: health, login, register, armed re-enroll) |
| kube-apiserver 10.43.0.1:443 / 192.168.0.180:6443 | 401 | nothing (k3s `config.yaml` unchanged since 2026-08-05) |
| kubelet :10250 | 401; :10255 closed | nothing |
| Prometheus, Grafana (anonymous Viewer), Alertmanager, node-exporter, kube-state-metrics | 200 | metrics and dashboards; Alertmanager also lets anyone create a silence. No secret values |
| Gitea | 200 | the public repos (R-925 ruling); registry `/v2/` 401 |
| Vaultwarden | `/alive`, `/api/config`, `/admin` login page 200 | nothing without the master password |
| ArgoCD, Headlamp, the filebrowsers | 401 on the API | nothing (Headlamp's own service account can read every Secret — behind OIDC) |
| `felhom-system/umami-db` 5432, other databases | open | password needed |
| LAN | router admin (.1), a TP-Link (.254), a printer (.20), **demo-felhom's Proxmox UI and SSH (.162)**, PBS UI on DooPlex :8007, Samba :445 | logins needed; `p2-lan-reach.txt` |
## Part 3 — evidence of use in the window, per path
| path | best record that exists | result |
|---|---|---|
| NFS | nfsd counters in Prometheus (connections, ops by method, bytes, RPC errors) — `p3-nfsd-*.json` | **unused** (verdict 1). RPC errors (auth/fmt/cInt) 0 |
| Longhorn API | `longhorn_backup_state`, `longhorn_volume_state` series; nfsd bytes written per night; Backup/Snapshot/BackupTarget/Volume `creationTimestamp` — `p3-longhorn-*` | **no sign of use**: 106 backups in the window = 53 daily (10-23 02:00Z) + 53 weekly (10-18 03:00Z), all to the local URL; 0 backups first seen off-schedule; no unexplained volume. Longhorn CRs carry **no managedFields**, so who changed what is not recorded there (`p3-longhorn-objects.txt`, CORRECTION) |
| Longhorn manager/UI logs | — | **no record: lost.** DooPlex was rebooted at 13:20Z by the maintenance session (`~/maintenance/2026-10-window`); the pre-reboot container logs of longhorn-manager, longhorn-ui, the hub, the ingress, Gitea, Vaultwarden, Grafana and Prometheus are gone. The incident session's earlier greps (before the reboot) found 10.42.0.52 in none of longhorn-manager, CNPG, Gitea (from 10-21 20:59), authentik; that is their record, not re-verifiable |
| hub | `/data/access-log` (R-1140), 10-18 10:25Z → now, 12 764 lines — `p3-hub-access-log.txt` | **no call from the Plex pod** (10.42.0.52: 0; positive control: the probe's 10.42.0.107 is logged). Credentialed requests come only from the boxes' LAN addresses, the home WAN and the operator's sessions. **Gap:** 10-17 04:00Z → 10-18 10:25Z no record (the log started then) — but no hub route gives a secret without a credential |
| SSH to DooPlex | journal (boot -1 survives) | 0 sshd lines from 10.42/10.43 in the window (control: 61 lines from 192.168.x) |
| Samba | per-client log files `log.%m` | no file for 10.42.0.52 (positive control: `log.10.42.0.107` appeared when the probe touched :445) — `p3-samba-clients.txt` |
| Alertmanager | silences API (keeps expired ones) | only two silences, both CC's, both outside the attack |
| DNS | CoreDNS keeps **no query log**; only upstream-timeout lines name a domain, without the client | names in `p3-coredns-error-names.txt`; `hand.genddos.st` looked up 10 times on 10-19 08:31–09:50Z (client unknown) |
| network bytes | cAdvisor per pod (no peer label) — `p3-network-bytes.txt` | **the Plex pod sent ~1.5 TB** (143 / 202 / 528 / 441 / 206 GiB per day, 10-18 → 10-22; before: 0.04 GiB/day) and received ≤ 7.9 GiB/day. DooPlex's NIC `eno1` sent the same extra out. Outbound-heavy: the shape of a flood tool or of streaming, not of a download. It did **not** come from the NFS store (nfsd reads flat) or from other pods (bridge-to-pod bytes flat) |
## Part 4 — Felhom's secrets on DooPlex
Exposure = what a path could read, judged with Part 3. „Possible path" means the door existed; it does not mean it was used.
| secret | where it lives | path that could read it (Part 2) | evidence of use | exposure |
|---|---|---|---|---|
| hub DB: Cloudflare API tokens, tunnel tokens, git tokens (**unsealed**, R-975) | `hub.db` on Longhorn `hub-data`; **unencrypted nightly copies in the NFS store** | NFS export (direct, no escape needed); Longhorn API backup to an outside target | none (Part 3) | **none** |
| hub DB: box API keys, controller keys, owner passphrases, PBS-DR tokens, break-glass passwords, Storage Box sub-account passwords (**sealed**, AES-GCM, key `OFFSITE_SECRET_KEY`) | same | same — but the key is a k8s Secret, not in the DB or its backups | none | **none** (sealed values useless without the key) |
| escrow blobs `host_escrow.blob` / `identity_blob` | same | same | none | **none** — sealed means: wrapped by each household's recovery code, which the hub never holds (`03-host-agent.md`, escrow retention: „the hub never decrypts either table") |
| hub tokens (`api_tokens.token_hash`), self-bind / claim codes | same, hashed | same | none | **none** (hashes) |
| k8s Secrets in `felhom-system` (report-api global key, offsite-secret-key, storagebox = main Storage Box/Hetzner login, resend-api, tenantsync, agent-poke, wg-endpoint-ssh, gitea-creds, umami, TLS keys) | etcd/k3s datastore (`/var/lib/rancher`, sdb1); also the nightly GPG secrets export on sda1 (`/mnt/5_hdd/backup/secrets/exports`, symmetric, passphrase file on sdb1) | k8s API anonymous: 401. NFS escape → the `.gpg` files only (key not on sda1) | none | **none** |
| hub session / signing material | k8s Secret / hub DB | as above | none | **none** |
| **operator signing keys** (operational + recovery + `felhom_op_ed25519`, no passphrase) | `/mnt/5_hdd/felhom.eu/` on **sda1** | NFS export → file-handle escape (documented, not exercised) | none (no NFS connection at all) | **none** — but the door is still open to any pod (row filed) |
| `sec` store | `cc-secrets/store/cc.sops.yaml` on sda1, age key `~/.config/sops/age/keys.txt` on sdb1 | escape → ciphertext only | none | **none** |
| registry login, Gitea tokens | `~/.docker/config.json`, `~/.git-credentials` (sdb1, 0600) | none from the pod network (registry 401, Gitea API anonymous = public repos only) | — | **none** |
| Vaultwarden (operator's password manager, R-923) | Longhorn volume; nightly unencrypted Longhorn copy in the NFS store (vault items stay encrypted by the master password) | login page; NFS export → encrypted vault DB | none for NFS; login logs lost | **none** (no record of login attempts — logs lost, and the vault is encrypted at rest) |
| off-site ciphertext (ep0 copy, demo-felhom backups) | sda1 | escape → ciphertext only | none | **none** |
## Part 5 — plan
Verdict NOT REACHED → **no rotation plan.** The open doors are filed instead (rows below). Nothing was rotated.
## Observations
- **A hacked pod on DooPlex can still read the hub's unencrypted nightly backups and, by the file-handle escape, the
operator signing keys through the NFS export.** → FILED: R-1241 (P1).
- **The Felhom demo NAS export `/mnt/5_hdd/felhom-data → 192.168.0.162` is a sub-directory of the same disk with
`no_subtree_check`**: a compromised demo-felhom host could walk all of sda1 as uid 101000 (world-readable files only,
e.g. the `.gpg` secrets exports and every repo). → FILED: R-1242 (P3).
- The hub answers pods directly, without the ingress geo filter. → NOT-A-FINDING: the geo filter is not an
authentication control; every no-token path refused (measured).
- demo-felhom's Proxmox UI and SSH are reachable from any DooPlex pod (masqueraded as 192.168.0.180). → NOT-A-FINDING:
same door as R-982 (root password SSH from the LAN), now with „a hacked DooPlex pod" as one more LAN attacker; added
to `13` §3.
- Pre-reboot pod logs were erased by the 13:20Z reboot. → NOT-A-FINDING for Felhom: the hub's own access log
persisted (R-1140 did its job). Homelab item, below.
## For the homelab session (no HM numbers minted; evidence paths in this folder)
1. **The NFS export is still open to every pod**, `no_root_squash`, `no_subtree_check`, on the disk that holds the
Felhom signing keys. `secure` does nothing in pods (containerd sets `ip_unprivileged_port_start=0`). Options: an
egress NetworkPolicy so only `longhorn-system` reaches :2049/:111, and/or move the store to its own filesystem
(LV or loop) so the subtree escape has nothing else to reach. Not managed by Ansible — the narrowed line persists.
2. **Longhorn manager API and UI need no login** from any pod (create backups/targets/volumes, delete volumes).
3. **The old Plex volume was deleted through Longhorn's API at 11:24:15Z** by nobody identified (`INCIDENT.md`
EVIDENCE NOTE). Ask the operator whether it was them; if not, it is an unattributed write on an open API.
4. **The Plex pod sent ~1.5 TB out on 10-18 → 10-22** (not in INCIDENT.md); and CoreDNS saw `hand.genddos.st`
lookups on 10-19. Possibly a flood tool riding the same compromise.
5. **The maintenance reboot at 13:20Z erased the window's pod logs** (longhorn-manager, ingress, hub, Gitea, …): no log
shipping, kubelet keeps one previous container log. Evidence rule R-320 applies to the homelab too.
6. Prometheus, Alertmanager (silences!), Grafana (anonymous Viewer), kube-state-metrics, node-exporter, MinIO console,
Headlamp (its service account can read every Secret and write RBAC — behind OIDC) all answer every pod.
7. A user process `python3 main.py -d -i` (kisfenyo) listens on 0.0.0.0:8443 on DooPlex.
@@ -0,0 +1,49 @@
# captured 2026-10-23T14:24:03Z
$ sudo ls -la /mnt/5_hdd/backup
total 64
drwxr-xr-x 16 root root 4096 2026-10-03 21:12 .
drwxr-xr-x 17 kisfenyo kisfenyo 4096 2026-10-23 11:01 ..
drwxr-xr-x 3 root root 4096 2026-01-05 16:07 data
drwxr-xr-x 5 backup backup 4096 2026-07-10 19:42 demo-felhom
drwxr-xr-x 4 backup backup 4096 2026-10-18 08:30 ep0-copy
drwxr-xr-x 4 root root 4096 2026-10-23 03:01 homelab-manifests
drwxrwxr-x 3 kisfenyo kisfenyo 4096 2026-10-23 04:00 jarrs.eu
drwxr-xr-x 3 root root 4096 2026-01-05 16:07 k3s
drwxr-xr-x 2 root root 4096 2026-01-05 16:35 logs
drwxr-xr-x 3 root root 4096 2026-01-06 04:00 longhorn-pvc
drwxr-x--- 2 kisfenyo kisfenyo 4096 2026-10-23 15:55 minecraft-tlauncher
drwxr-xr-x 2 root root 4096 2026-08-10 18:28 paperless
drwxr-xr-x 4 26 tape 4096 2026-06-25 11:32 postgresql
drwxr-xr-x 2 root root 4096 2026-08-10 18:16 romm
drwxr-xr-x 4 root root 4096 2026-01-05 16:07 secrets
drwxr-xr-x 2 root root 4096 2026-10-08 07:24 sparkyfitness
$ sudo ls /mnt/5_hdd/backup/longhorn-pvc
total 12
drwxr-xr-x 3 root root 4096 2026-01-06 04:00 .
drwxr-xr-x 16 root root 4096 2026-10-03 21:12 ..
drwx------ 3 root root 4096 2026-01-06 04:00 backupstore
$ dirs depth<=4
/mnt/5_hdd/backup/longhorn-pvc
/mnt/5_hdd/backup/longhorn-pvc/backupstore
/mnt/5_hdd/backup/longhorn-pvc/backupstore/volumes
/mnt/5_hdd/backup/longhorn-pvc/backupstore/volumes/4f
/mnt/5_hdd/backup/longhorn-pvc/backupstore/volumes/4f/33
/mnt/5_hdd/backup/longhorn-pvc/backupstore/volumes/9f
/mnt/5_hdd/backup/longhorn-pvc/backupstore/volumes/9f/fc
/mnt/5_hdd/backup/longhorn-pvc/backupstore/volumes/1d
/mnt/5_hdd/backup/longhorn-pvc/backupstore/volumes/1d/5c
/mnt/5_hdd/backup/longhorn-pvc/backupstore/volumes/a9
/mnt/5_hdd/backup/longhorn-pvc/backupstore/volumes/a9/95
/mnt/5_hdd/backup/longhorn-pvc/backupstore/volumes/3b
/mnt/5_hdd/backup/longhorn-pvc/backupstore/volumes/3b/f9
/mnt/5_hdd/backup/longhorn-pvc/backupstore/volumes/5f
/mnt/5_hdd/backup/longhorn-pvc/backupstore/volumes/5f/21
/mnt/5_hdd/backup/longhorn-pvc/backupstore/volumes/bb
/mnt/5_hdd/backup/longhorn-pvc/backupstore/volumes/bb/3f
/mnt/5_hdd/backup/longhorn-pvc/backupstore/volumes/0e
/mnt/5_hdd/backup/longhorn-pvc/backupstore/volumes/0e/6e
/mnt/5_hdd/backup/longhorn-pvc/backupstore/volumes/11
$ du per backup volume (sizes only)
@@ -0,0 +1,29 @@
# Part 1 change, operator OK 'Yes, narrow it' — 2026-10-23T15:18:52Z
$ sha256sum /etc/exports (before)
bb9047fd8bf9cebd589ac680dbbb45746bc621591c68add15f0ae410e0c6cd76 /etc/exports
$ backup copy: /etc/exports.bak-2026-10-23-plex2shell
$ diff old new
12c12
< /mnt/5_hdd/backup/longhorn-pvc *(rw,sync,no_subtree_check,no_root_squash)
---
> /mnt/5_hdd/backup/longhorn-pvc 10.42.0.0/16(rw,sync,no_subtree_check,no_root_squash)
rc=1
$ sudo exportfs -ra
rc=0
$ sudo exportfs -v
/mnt/5_hdd/felhom-data
192.168.0.162(sync,wdelay,hide,no_subtree_check,anonuid=101000,anongid=101000,sec=sys,rw,secure,root_squash,all_squash)
/mnt/5_hdd/backup/longhorn-pvc
10.42.0.0/16(sync,wdelay,hide,no_subtree_check,sec=sys,rw,secure,no_root_squash,no_all_squash)
# read-back 2026-10-23T15:21:36Z
$ backuptarget default: available lastSyncedAt (sync AFTER the 15:18:52Z change)
true 2026-10-23T15:20:10Z
$ nfsd v4 clients now
address: "10.42.0.214:669"
seconds from last renew: 16
name: "Linux NFSv4.2 longhorn-manager-w4tf6"
callback address: "10.42.0.214:0"
$ grep longhorn-pvc /proc/fs/nfsd/exports
/mnt/5_hdd/backup/longhorn-pvc 10.42.0.0/16(rw,no_root_squash,sync,wdelay,no_subtree_check,uuid=2fb0cf66:1b3d4fcc:850508ca:f5a7f8fc,sec=1)
UNDO: sudo cp -p /etc/exports.bak-2026-10-23-plex2shell /etc/exports && sudo exportfs -ra
@@ -0,0 +1,126 @@
# captured 2026-10-23T14:21:56Z on dooplex
$ cat /etc/exports (comments stripped)
/mnt/5_hdd/backup/longhorn-pvc *(rw,sync,no_subtree_check,no_root_squash)
/mnt/5_hdd/felhom-data 192.168.0.162(rw,all_squash,anonuid=101000,anongid=101000,no_subtree_check)
ls: cannot access '/etc/exports.d': No such file or directory
-rw-r--r-- 1 root root 680 Aug 14 06:59 /etc/exports
$ sudo exportfs -v
/mnt/5_hdd/felhom-data
192.168.0.162(sync,wdelay,hide,no_subtree_check,anonuid=101000,anongid=101000,sec=sys,rw,secure,root_squash,all_squash)
/mnt/5_hdd/backup/longhorn-pvc
<world>(sync,wdelay,hide,no_subtree_check,sec=sys,rw,secure,no_root_squash,no_all_squash)
$ showmount -a localhost
All mount points on localhost:
$ /var/lib/nfs/rmtab
$ /proc/fs/nfsd/clients/*/info
== /proc/fs/nfsd/clients/*/info
cat: '/proc/fs/nfsd/clients/*/info': No such file or directory
$ /proc/fs/nfsd/versions
+3 +4 +4.1 +4.2
$ /etc/nfs.conf (non-comment)
[general]
pipefs-directory=/run/rpc_pipefs
[nfsrahead]
[exports]
[exportfs]
[gssd]
[lockd]
[exportd]
[mountd]
manage-gids=y
[nfsdcld]
[nfsd]
[statd]
[sm-notify]
[svcgssd]
$ ss -tnp sport/dport 2049, 111, 20048
State Recv-Q Send-Q Local Address:Port Peer Address:PortProcess
LISTEN 0 4096 0.0.0.0:2049 0.0.0.0:*
LISTEN 0 4096 0.0.0.0:111 0.0.0.0:* users:(("rpcbind",pid=1932,fd=4),("systemd",pid=1,fd=47))
ESTAB 0 0 192.168.0.180:38514 10.43.69.49:2049
ESTAB 0 0 192.168.0.180:58280 10.43.31.240:2049
ESTAB 0 0 192.168.0.180:2049 10.42.0.214:669
LISTEN 0 4096 [::]:2049 [::]:*
LISTEN 0 4096 [::]:111 [::]:* users:(("rpcbind",pid=1932,fd=6),("systemd",pid=1,fd=49))
$ ss -lntup nfs/rpc listeners
udp UNCONN 0 0 0.0.0.0:111 0.0.0.0:* users:(("rpcbind",pid=1932,fd=5),("systemd",pid=1,fd=48))
udp UNCONN 0 0 0.0.0.0:33506 0.0.0.0:* users:(("tailscaled",pid=86160,fd=19))
udp UNCONN 0 0 0.0.0.0:34514 0.0.0.0:* users:(("rpc.mountd",pid=2203,fd=8))
udp UNCONN 0 0 0.0.0.0:38607 0.0.0.0:* users:(("rpc.mountd",pid=2203,fd=4))
udp UNCONN 0 0 [::]:111 [::]:* users:(("rpcbind",pid=1932,fd=7),("systemd",pid=1,fd=50))
udp UNCONN 0 0 [::]:34707 [::]:* users:(("tailscaled",pid=86160,fd=18))
tcp LISTEN 0 64 0.0.0.0:37541 0.0.0.0:*
tcp LISTEN 0 4096 0.0.0.0:36457 0.0.0.0:* users:(("rpc.mountd",pid=2203,fd=9))
tcp LISTEN 0 4096 0.0.0.0:2049 0.0.0.0:*
tcp LISTEN 0 4096 0.0.0.0:111 0.0.0.0:* users:(("rpcbind",pid=1932,fd=4),("systemd",pid=1,fd=47))
tcp LISTEN 0 4096 [::]:2049 [::]:*
tcp LISTEN 0 4096 [::]:111 [::]:* users:(("rpcbind",pid=1932,fd=6),("systemd",pid=1,fd=49))
tcp LISTEN 0 4096 [fd7a:115c:a1e0::fc01:579a]%tailscale0:33516 [::]:* users:(("tailscaled",pid=86160,fd=24))
tcp LISTEN 0 4096 *:31983 *:* users:(("k3s-server",pid=2231,fd=41))
tcp LISTEN 0 4096 *:31433 *:* users:(("k3s-server",pid=2231,fd=80))
tcp LISTEN 0 4096 *:30196 *:* users:(("k3s-server",pid=2231,fd=324))
tcp LISTEN 0 4096 *:30239 *:* users:(("k3s-server",pid=2231,fd=320))
tcp LISTEN 0 4096 *:30627 *:* users:(("k3s-server",pid=2231,fd=317))
$ rpcinfo -p
program vers proto port service
100000 4 tcp 111 portmapper
100000 3 tcp 111 portmapper
100000 2 tcp 111 portmapper
100000 4 udp 111 portmapper
100000 3 udp 111 portmapper
100000 2 udp 111 portmapper
100005 1 udp 38607 mountd
100005 1 tcp 51925 mountd
100005 2 udp 34514 mountd
100005 2 tcp 36457 mountd
100005 3 udp 42427 mountd
100005 3 tcp 57549 mountd
100024 1 udp 56119 status
100024 1 tcp 52519 status
100003 3 tcp 2049 nfs
100003 4 tcp 2049 nfs
100227 3 tcp 2049 nfs_acl
100021 1 udp 45443 nlockmgr
100021 3 udp 45443 nlockmgr
100021 4 udp 45443 nlockmgr
100021 1 tcp 37541 nlockmgr
100021 3 tcp 37541 nlockmgr
100021 4 tcp 37541 nlockmgr
# appended 2026-10-23T14:22:12Z
$ sudo ls /proc/fs/nfsd/clients; cat */info
== client 3
clientid: 0x6c6ec1426adb63eb
address: "10.42.0.214:669"
status: confirmed
seconds from last renew: 49
name: "Linux NFSv4.2 longhorn-manager-w4tf6"
minor version: 2
Implementation domain: "kernel.org"
Implementation name: "Linux 6.12.113+deb13-amd64 #1 SMP PREEMPT_DYNAMIC Debian 6.12.113-1 (2026-10-15) x86_64"
Implementation time: [0, 0]
callback state: UP
callback address: "10.42.0.214:0"
admin-revoked states: 0
$ sudo cat /proc/fs/nfsd/exports
# Version 1.1
# Path Client(Flags) # IPs
/mnt/5_hdd *(ro,insecure,no_root_squash,sync,no_wdelay,no_subtree_check,v4root,uuid=d2423144:e2585cd2:bcf24caa:707cadf0,sec=1)
/mnt *(ro,insecure,no_root_squash,sync,no_wdelay,no_subtree_check,v4root,uuid=0a4bfb73:2e6b5931:9b78e97b:7691fb97,sec=1)
/mnt/5_hdd/backup/longhorn-pvc *(rw,no_root_squash,sync,wdelay,no_subtree_check,uuid=2fb0cf66:1b3d4fcc:850508ca:f5a7f8fc,sec=1)
/mnt/5_hdd/backup *(ro,insecure,no_root_squash,sync,no_wdelay,no_subtree_check,v4root,uuid=a14fb08e:93ef58c9:8e149646:540a8430,sec=1)
/ *(ro,insecure,no_root_squash,sync,no_wdelay,no_subtree_check,v4root,fsid=0,sec=1)
$ peer 10.42.0.214 = pod longhorn-system/longhorn-manager-w4tf6 (kubectl get pods -A -o wide)
$ 10.43.31.240 / 10.43.69.49 = longhorn-system ClusterIP services pvc-1d4ec717 / pvc-8ed5eea5 (RWX share-managers; DooPlex is the CLIENT there)
$ uptime / nfs-server active since
16:22:12 up 41 min, 7 users, load average: 3.38, 4.81, 5.47
ActiveEnterTimestamp=Fri 2026-10-23 15:40:59 CEST
ActiveEnterTimestamp=Fri 2026-10-23 15:40:56 CEST
@@ -0,0 +1,21 @@
# P2 LAN reach from cc-p2s-probe (pod egress, masqueraded to 192.168.0.180), TCP connect only, 16 ports, 2026-10-23T15:22:57Z
192.168.0.1 open: 22 53 80 443
192.168.0.20 open: 80 631 9100
192.168.0.110 open: 22 139 445
192.168.0.149 open: 22 80 443
192.168.0.162 open: 22 53 111 8006
192.168.0.180 open: 22 111 139 445 2049 8007 8443 9100
192.168.0.192 open: 80 443
192.168.0.203 open: 3000
192.168.0.209 open: 80
192.168.0.250 open: 53 80
192.168.0.254 open: 22 80
# end 2026-10-23T15:24:51Z
# identification (GET / title, no login), 2026-10-23T15:26Z
# 192.168.0.162:8006 demo-felhom - Proxmox Virtual Environment (the lived-in N100 box's host; also the felhom-data NFS client)
# 192.168.0.180:8007 dooplex - Proxmox Backup Server (login page)
# 192.168.0.180:8443 a user process `python3 main.py -d -i` (kisfenyo), 302
# 192.168.0.180:139/445 smbd; :111/:2049 NFS; :6443 k3s API (401 anonymous); :10250 kubelet (401 anonymous)
# 192.168.0.254 TP-LINK Archer C5 admin page; 192.168.0.1 router admin (200)
# 192.168.0.20 printer-shaped (80, 631 IPP, 9100 JetDirect)
# 192.168.0.192/.203/.209/.250 k3s LoadBalancer IPs (ingress, gitea ssh/3000, pihole)
@@ -0,0 +1,23 @@
# 2026-10-23T15:19:46Z BEFORE: pods in default
No resources found in default namespace.
networkpolicies in default:
No resources found in default namespace.
pod/cc-p2s-probe created
pod/cc-p2s-probe condition met
NAME READY STATUS RESTARTS AGE IP NODE NOMINATED NODE READINESS GATES
cc-p2s-probe 1/1 Running 0 1s 10.42.0.107 dooplex <none> <none>
# 2026-10-23T15:33:44Z TEARDOWN
before:
NAME READY STATUS RESTARTS AGE IP NODE NOMINATED NODE READINESS GATES
cc-p2s-probe 1/1 Running 0 13m 10.42.0.107 dooplex <none> <none>
pod "cc-p2s-probe" deleted
after:
No resources found in default namespace.
No resources found in default namespace.
no namespace, NetworkPolicy, ServiceAccount or other object was created; the incident's NetworkPolicies were not touched:
networkpolicy.networking.k8s.io/allow-acme-solver
networkpolicy.networking.k8s.io/allow-dns
networkpolicy.networking.k8s.io/allow-plex-clients
networkpolicy.networking.k8s.io/allow-plex-egress-https
networkpolicy.networking.k8s.io/default-deny-all
@@ -0,0 +1,20 @@
apiVersion: v1
kind: Pod
metadata:
name: cc-p2s-probe
namespace: default
labels: {purpose: plex2shell-felhom-impact-probe}
annotations: {note: "read-only reach probe, CC 2026-10-23; removed after"}
spec:
automountServiceAccountToken: false
enableServiceLinks: false
activeDeadlineSeconds: 5400
restartPolicy: Never
securityContext: {runAsUser: 1000, runAsGroup: 1000, runAsNonRoot: true}
containers:
- name: probe
image: docker.io/curlimages/curl:8.11.1
imagePullPolicy: IfNotPresent
command: ["sleep", "5400"]
securityContext: {allowPrivilegeEscalation: false, capabilities: {drop: ["ALL"]}}
resources: {limits: {cpu: "500m", memory: "128Mi"}}
@@ -0,0 +1,201 @@
# P2 in-cluster service sweep from cc-p2s-probe (10.42.0.107, uid 1000, CapEff 0, no SA token, ns default, no NetworkPolicy) 2026-10-23T15:20:04Z
# format: ns/service ip:port OPEN scheme http_code <title> — GET / only, no credentials
actualbudget-system/actualbudget 10.43.212.93:5006 OPEN http 200 Actual
admin-system/smartctl-exporter 10.43.107.224:9633 OPEN http 200 smartctl_exporter
admin-system/upsnap 10.43.71.31:8090 OPEN http 200 UpSnap
admin-system/wan-monitor 10.43.247.236:9115 OPEN http 200 Blackbox Exporter
admin-system/wan-monitor 10.43.247.236:9116 OPEN http 404 404 Not Found
adventurelog-system/adventurelog-backend 10.43.25.95:80 OPEN http 200 AdventureLog API Server
adventurelog-system/adventurelog-frontend 10.43.144.156:3000 OPEN http 200 AdventureLog
adventurelog-system/adventurelog-postgres 10.43.27.145:5432 OPEN https 000 AdventureLog
arcade-system/romm 10.43.212.194:8080 OPEN http 200 RomM
arcade-system/romm-db 10.43.59.10:3306 OPEN https 000 RomM
arcade-system/romm-redis 10.43.2.16:6379 OPEN https 000 RomM
argocd/argocd-applicationset-controller 10.43.107.242:7000 OPEN http 404
argocd/argocd-applicationset-controller 10.43.107.242:8080 OPEN http 404
argocd/argocd-dex-server 10.43.116.227:5556 closed-or-filtered
argocd/argocd-dex-server 10.43.116.227:5557 closed-or-filtered
argocd/argocd-dex-server 10.43.116.227:5558 OPEN http 404
argocd/argocd-metrics 10.43.211.46:8082 OPEN http 404
argocd/argocd-notifications-controller-metrics 10.43.213.199:9001 OPEN http 404
argocd/argocd-redis 10.43.241.255:6379 closed-or-filtered
argocd/argocd-repo-server 10.43.146.85:8081 closed-or-filtered
argocd/argocd-repo-server 10.43.146.85:8084 OPEN http 404
argocd/argocd-server 10.43.16.170:80 OPEN http 200 Argo CD
argocd/argocd-server 10.43.16.170:443 OPEN http 200 Argo CD
argocd/argocd-server-metrics 10.43.225.99:8083 OPEN http 404
audiobookshelf-system/audiobookshelf 10.43.219.190:80 OPEN http 200 Audiobookshelf
auth-system/ak-outpost-arr-outpost 10.43.47.195:9000 OPEN http 400
auth-system/ak-outpost-arr-outpost 10.43.47.195:9443 OPEN http 400
auth-system/ak-outpost-arr-outpost-metrics 10.43.233.224:9300 OPEN http 404
auth-system/ak-outpost-authentik-embedded-outpost 10.43.101.194:9000 OPEN http 302
auth-system/ak-outpost-authentik-embedded-outpost 10.43.101.194:9443 OPEN http 400
auth-system/ak-outpost-code-outpost 10.43.148.172:9000 OPEN http 404
auth-system/ak-outpost-code-outpost 10.43.148.172:9443 OPEN http 400
auth-system/ak-outpost-code-outpost-metrics 10.43.58.49:9300 OPEN http 404
auth-system/ak-outpost-crafty-outpost 10.43.44.155:9000 OPEN http 404
auth-system/ak-outpost-crafty-outpost 10.43.44.155:9443 OPEN http 400
auth-system/ak-outpost-crafty-outpost-metrics 10.43.27.113:9300 OPEN http 404
auth-system/ak-outpost-filebrowser-outpost 10.43.7.249:9000 OPEN http 404
auth-system/ak-outpost-filebrowser-outpost 10.43.7.249:9443 OPEN http 400
auth-system/ak-outpost-filebrowser-outpost-metrics 10.43.85.99:9300 OPEN http 404
auth-system/ak-outpost-glance-orsi-outpost 10.43.196.9:9000 OPEN http 404
auth-system/ak-outpost-glance-orsi-outpost 10.43.196.9:9443 OPEN http 400
auth-system/ak-outpost-glance-orsi-outpost-metrics 10.43.196.125:9300 OPEN http 404
auth-system/ak-outpost-glance-outpost 10.43.142.74:9000 OPEN http 404
auth-system/ak-outpost-glance-outpost 10.43.142.74:9443 OPEN http 400
auth-system/ak-outpost-glance-outpost-metrics 10.43.201.140:9300 OPEN http 404
auth-system/ak-outpost-homepage-orsi-outpost 10.43.66.136:9000 OPEN http 404
auth-system/ak-outpost-homepage-orsi-outpost 10.43.66.136:9443 OPEN http 400
auth-system/ak-outpost-homepage-orsi-outpost-metrics 10.43.244.43:9300 OPEN http 404
auth-system/ak-outpost-homepage-outpost 10.43.199.21:9000 OPEN http 404
auth-system/ak-outpost-homepage-outpost 10.43.199.21:9443 OPEN http 400
auth-system/ak-outpost-homepage-outpost-metrics 10.43.187.161:9300 OPEN http 404
auth-system/ak-outpost-kisfenyo-outpost 10.43.176.115:9000 OPEN http 404
auth-system/ak-outpost-kisfenyo-outpost 10.43.176.115:9443 OPEN http 400
auth-system/ak-outpost-kisfenyo-outpost-metrics 10.43.233.48:9300 OPEN http 404
auth-system/ak-outpost-ldap-outpost 10.43.162.147:389 OPEN https 000
auth-system/ak-outpost-ldap-outpost 10.43.162.147:636 OPEN https 000
auth-system/ak-outpost-ldap-outpost 10.43.162.147:9300 OPEN http 404
auth-system/ak-outpost-ldap-outpost-metrics 10.43.108.223:9300 OPEN http 404
auth-system/ak-outpost-orsi-outpost 10.43.208.171:9000 OPEN http 404
auth-system/ak-outpost-orsi-outpost 10.43.208.171:9443 OPEN http 400
auth-system/ak-outpost-orsi-outpost-metrics 10.43.112.181:9300 OPEN http 404
auth-system/ak-outpost-pihole-outpost 10.43.89.237:9000 OPEN http 404
auth-system/ak-outpost-pihole-outpost 10.43.89.237:9443 OPEN http 400
auth-system/ak-outpost-pihole-outpost-metrics 10.43.161.157:9300 OPEN http 404
auth-system/ak-outpost-plantit-outpost 10.43.20.58:9000 OPEN http 404
auth-system/ak-outpost-plantit-outpost 10.43.20.58:9443 OPEN http 400
auth-system/ak-outpost-plantit-outpost-metrics 10.43.253.17:9300 OPEN http 404
auth-system/ak-outpost-privatebin-outpost 10.43.41.96:9000 OPEN http 404
auth-system/ak-outpost-privatebin-outpost 10.43.41.96:9443 OPEN http 400
auth-system/ak-outpost-privatebin-outpost-metrics 10.43.87.152:9300 OPEN http 404
auth-system/ak-outpost-uptimekuma-outpost 10.43.15.220:9000 OPEN http 404
auth-system/ak-outpost-uptimekuma-outpost 10.43.15.220:9443 OPEN http 400
auth-system/ak-outpost-uptimekuma-outpost-metrics 10.43.77.209:9300 OPEN http 404
auth-system/authentik-server 10.43.142.123:80 OPEN http 302
auth-system/authentik-server 10.43.142.123:443 OPEN http 400
auth-system/authentik-server-metrics 10.43.224.102:9300 OPEN http 404
auth-system/authentik-worker-metrics 10.43.107.115:9300 OPEN http 200
booking-system/calcom 10.43.105.14:3000 OPEN http 307
booking-system/calcom-redis 10.43.160.2:6379 OPEN https 000
bookstack-system/bookstack 10.43.209.167:80 OPEN http 302 Redirecting to https://bookstack.dooplex.hu/login
bookstack-system/bookstack-mariadb 10.43.65.20:3306 OPEN https 000 Redirecting to https://bookstack.dooplex.hu/login
calibre-system/calibre-web-automated 10.43.232.53:8083 OPEN http 302 Redirecting...
cert-manager/cert-manager 10.43.71.177:9402 OPEN http 404
cert-manager/cert-manager-cainjector 10.43.152.171:9402 OPEN http 404
cert-manager/cert-manager-webhook 10.43.210.109:443 OPEN http 400
cert-manager/cert-manager-webhook 10.43.210.109:9402 OPEN http 404
cnpg-system/cnpg-webhook-service 10.43.220.80:8080 OPEN http 400
code-system/code-server 10.43.200.176:8080 OPEN http 302
crafty-system/craftycontroller-https 10.43.35.97:8443 OPEN https 302
crafty-system/serverpackcreator 10.43.246.127:8080 OPEN http 200 ServerPackCreator
database-system/postgresql-r 10.43.232.70:5432 OPEN https 000 ServerPackCreator
database-system/postgresql-ro 10.43.242.254:5432 closed-or-filtered
database-system/postgresql-rw 10.43.190.86:5432 OPEN https 000 ServerPackCreator
default/kubernetes 10.43.0.1:443 OPEN http 400
felhom-system/contact-mailer 10.43.202.255:80 OPEN http 404
felhom-system/felhom-webpage 10.43.10.226:80 OPEN http 200 Felhom.eu — Saját felhőd, saját szabályaid | Otthoni szerver
felhom-system/filebrowser 10.43.219.38:80 OPEN http 200 File Browser
felhom-system/hub 10.43.52.34:8080 OPEN http 302
felhom-system/umami 10.43.41.11:80 OPEN http 200 Umami
felhom-system/umami-db 10.43.90.120:5432 OPEN https 000 Umami
fileshare-system/gokapi 10.43.217.203:53842 OPEN http 200
gitea-system/gitea 10.43.8.106:3000 OPEN http 200 Gitea: Git with a cup of tea
gitea-system/gitea 10.43.8.106:2222 OPEN https 000 Gitea: Git with a cup of tea
glance-system/glance-helper 10.43.236.190:8000 OPEN http 404
glance-system/glance-kisfenyo 10.43.96.155:8080 OPEN http 200 Home
glance-system/glance-orsi 10.43.42.102:8080 OPEN http 200 Home
glance-system/idokep-scraper 10.43.34.231:8000 OPEN http 404
headlamp-system/headlamp 10.43.47.50:80 OPEN http 200 Headlamp
homepage-system/homepage 10.43.34.4:3000 OPEN http 200
homepage-system/homepage-orsi 10.43.33.155:3000 OPEN http 200
immich-system/immich-machine-learning 10.43.134.146:3003 OPEN http 200
immich-system/immich-postgres 10.43.216.166:5432 OPEN https 000
immich-system/immich-server 10.43.69.28:2283 OPEN http 200
immich-system/immich-valkey 10.43.245.230:6379 OPEN https 000
jarr-nightly-system/nightly-jarr 10.43.41.156:3000 closed-or-filtered
jarr-nightly-system/nightly-jarr-postgres 10.43.212.186:5432 closed-or-filtered
jarr-nightly-system/nightly-jarr-redis 10.43.46.139:6379 closed-or-filtered
jarrs-system/dev-jarr 10.43.3.168:3000 OPEN http 200 JARR — Just A Random Result
jarrs-system/dev-jarr-postgres 10.43.28.40:5432 OPEN https 000 JARR — Just A Random Result
jarrs-system/dev-jarr-redis 10.43.168.17:6379 OPEN https 000 JARR — Just A Random Result
kisfenyo-system/guacamole 10.43.198.33:8080 OPEN http 200
kisfenyo-system/guacd 10.43.84.231:4822 OPEN https 000
kisfenyo-system/kisfenyo-filebrowser 10.43.14.45:80 OPEN http 200 "FileBrowser Quantum"
kube-system/kube-dns 10.43.0.10:53 UDP skip-udp
kube-system/kube-dns 10.43.0.10:53 OPEN https 000 "FileBrowser Quantum"
kube-system/kube-dns 10.43.0.10:9153 OPEN http 404
kube-system/metrics-server 10.43.183.127:443 OPEN http 400
longhorn-system/longhorn-admission-webhook 10.43.91.126:9502 OPEN http 400
longhorn-system/longhorn-backend 10.43.241.105:9500 OPEN http 200
longhorn-system/longhorn-frontend 10.43.195.177:80 OPEN http 200
longhorn-system/longhorn-recovery-backend 10.43.98.183:9503 OPEN http 404
longhorn-system/pvc-1d4ec717-7ee5-40a0-b093-3a62fd2a81a4 10.43.31.240:2049 OPEN https 000
longhorn-system/pvc-8ed5eea5-67d4-46fc-9806-6b8fdd61e42e 10.43.69.49:2049 OPEN https 000
mediaserver-system/plex-plex-media-server 10.43.190.78:32400 closed-or-filtered
metallb-system/metallb-webhook-service 10.43.36.127:443 OPEN http 400
mon-system/alertmanager 10.43.143.131:9093 OPEN http 200 Alertmanager
mon-system/exportarr-prowlarr 10.43.171.82:9709 OPEN http 200
mon-system/exportarr-radarr 10.43.126.173:9708 OPEN http 200
mon-system/exportarr-sonarr 10.43.232.101:9707 OPEN http 200
mon-system/grafana 10.43.32.171:3000 OPEN http 200 Grafana
mon-system/kube-state-metrics 10.43.77.239:8080 OPEN http 200 kube-state-metrics
mon-system/kube-state-metrics 10.43.77.239:8081 OPEN http 200 kube-state-metrics
mon-system/node-exporter 10.43.42.73:9100 OPEN http 200 Node Exporter
mon-system/prometheus 10.43.75.209:9090 OPEN http 302
nextcloud-system/nextcloud 10.43.181.86:80 OPEN http 400 Nextcloud
nextcloud-system/nextcloud-postgresql 10.43.18.100:5432 OPEN https 000 Nextcloud
nginx-system/ingress-nginx-internal-controller 10.43.166.147:80 OPEN http 404 404 Not Found
nginx-system/ingress-nginx-internal-controller 10.43.166.147:443 OPEN http 400 400 The plain HTTP request was sent to HTTPS port
nginx-system/ingress-nginx-internal-controller-admission 10.43.90.248:443 OPEN http 400
nginx-system/ingress-nginx-internal-controller-metrics 10.43.83.22:10254 OPEN http 404
office-system/bentopdf 10.43.169.90:8080 OPEN http 200 BentoPDF - Free Online PDF Tools | Privacy-First PDF Toolkit
office-system/onlyoffice 10.43.79.155:80 OPEN http 302 302 Found
opengist-system/opengist 10.43.253.238:80 OPEN http 302
opengist-system/opengist 10.43.253.238:2222 OPEN https 000
orsi-system/orsi-filebrowser 10.43.188.12:80 OPEN http 200 File Browser
orsi-system/revfulop-calendar 10.43.213.82:3000 OPEN http 200 Révfülöp · Nyaraló Naptár
outline-system/outline 10.43.46.49:3000 OPEN http 301
outline-system/outline-minio 10.43.166.151:9000 OPEN http 403
outline-system/outline-minio 10.43.166.151:9001 OPEN http 200 MinIO Console
outline-system/outline-redis 10.43.65.17:6379 OPEN https 000 MinIO Console
paperless-system/paperless 10.43.218.141:8000 OPEN http 302
paperless-system/paperless-redis 10.43.183.83:6379 OPEN https 000
pihole-system/external-dns-pihole 10.43.18.28:7979 OPEN http 404
pihole-system/pihole-dhcp 10.43.72.243:67 UDP skip-udp
pihole-system/pihole-dns-tcp 10.43.236.96:53 OPEN https 000
pihole-system/pihole-dns-udp 10.43.192.211:53 UDP skip-udp
pihole-system/pihole-exporter 10.43.102.172:9617 OPEN http 404
pihole-system/pihole-web 10.43.182.233:80 OPEN http 403 Pi-hole pihole-786ff65bd7-5zhzx
pihole-system/pihole-web 10.43.182.233:443 closed-or-filtered
plantit-system/plantit 10.43.56.143:3000 OPEN http 200 app
plantit-system/plantit 10.43.56.143:8080 OPEN http 404 HTTP Status 404 – Not Found
plantit-system/plantit-cache 10.43.134.91:6379 OPEN https 000 HTTP Status 404 – Not Found
plantit-system/plantit-db 10.43.105.32:3306 OPEN https 000 HTTP Status 404 – Not Found
privatebin-system/privatebin 10.43.30.60:80 OPEN http 200 Dooplex Paste
servarr-system/ak-outpost-arr-outpost null:9000 closed-or-filtered
servarr-system/prowlarr 10.43.41.42:9696 OPEN http 200 Prowlarr
servarr-system/qbittorrent 10.43.174.87:8080 OPEN http 200 qBittorrent WebUI
servarr-system/qbittorrent 10.43.174.87:6881 OPEN https 000 qBittorrent WebUI
servarr-system/radarr 10.43.45.108:7878 OPEN http 200 Radarr
servarr-system/radarrkids 10.43.244.174:7879 OPEN http 200 Radarr
servarr-system/seerr 10.43.135.162:5055 OPEN http 307
servarr-system/sonarr 10.43.176.56:8989 OPEN http 200 Sonarr
servarr-system/tautulli 10.43.36.206:8181 OPEN http 303
tandoor-system/recipe-importer 10.43.182.17:8000 OPEN http 401
tandoor-system/tandoor 10.43.31.47:8080 OPEN http 302
termix-system/termix 10.43.236.34:8080 OPEN http 200 Termix
uptimekuma-system/uptimekuma 10.43.214.117:3001 OPEN http 302
vaultwarden-system/vaultwarden 10.43.38.33:80 OPEN http 200
version-checker-system/version-checker 10.43.124.2:8080 OPEN http 404
wanderer-system/wanderer-db 10.43.111.144:8090 OPEN http 404
wanderer-system/wanderer-meilisearch 10.43.152.86:7700 OPEN http 200
wanderer-system/wanderer-web 10.43.207.245:3000 OPEN http 200 Home | wanderer
web-system/filebrowser 10.43.204.98:80 OPEN http 200 File Browser
web-system/static-server 10.43.92.56:80 OPEN http 403 403 Forbidden
workout-system/sparkyfitness-db 10.43.190.119:5432 OPEN https 000 403 Forbidden
workout-system/sparkyfitness-export 10.43.253.80:80 OPEN http 200 SparkyFitness export
workout-system/sparkyfitness-frontend 10.43.83.16:80 OPEN http 200 SparkyFitness
workout-system/sparkyfitness-server 10.43.66.255:3010 OPEN http 401
zipline-system/zipline 10.43.175.211:80 OPEN http 301
@@ -0,0 +1,88 @@
# P2 targeted no-login probes from cc-p2s-probe 2026-10-23T15:22:24Z. Response bodies stay in the pod's /tmp; only codes, sizes and counts are recorded.
== Longhorn manager API (longhorn-backend 9500) and UI proxy (longhorn-frontend 80) — GET only
http://10.43.241.105:9500/v1 200 bytes=6028
http://10.43.241.105:9500/v1/volumes 200 bytes=797538
http://10.43.241.105:9500/v1/backuptargets 200 bytes=638
http://10.43.241.105:9500/v1/backupvolumes 200 bytes=196193
http://10.43.241.105:9500/v1/settings/backup-target 500 bytes=245
http://10.43.241.105:9500/v1/recurringjobs 200 bytes=667
volumes listed via API: 234
hub-data volume visible via API: 1
actions offered on a volume (names only): "activate" "attach" "detach" "pvcCreate" "snapshotBackup" "snapshotCreate" "updateReplicaCount"
http://10.43.195.177/v1/volumes 200 bytes=781928
== Felhom hub (service hub:8080, bypasses the ingress geo filter) — GET, no token
http://10.43.52.34:8080/healthz 200 bytes=2
http://10.43.52.34:8080/ 302 bytes=29
http://10.43.52.34:8080/login 200 bytes=554
http://10.43.52.34:8080/api/v1/customers 403 bytes=31
http://10.43.52.34:8080/api/v1/hosts 404 bytes=19
http://10.43.52.34:8080/api/v1/preferences 401 bytes=13
http://10.43.52.34:8080/api/v1/box-config/x 401 bytes=13
http://10.43.52.34:8080/api/v1/artifacts/x 401 bytes=51
http://10.43.52.34:8080/api/v1/assets/file/x 401 bytes=13
http://10.43.52.34:8080/api/v1/wait 401 bytes=13
http://10.43.52.34:8080/api/v1/appliance/poll 401 bytes=13
http://10.43.52.34:8080/metrics 302 bytes=29
http://10.43.52.34:8080/hosts 302 bytes=29
http://10.43.52.34:8080/configs 302 bytes=29
http://10.43.52.34:8080/customers 302 bytes=29
http://10.43.52.34:8080/escrow 302 bytes=29
http://10.43.52.34:8080/export 302 bytes=29
http://10.43.52.34:8080/backup 302 bytes=29
== kube-apiserver anonymous
https://10.43.0.1:443/version 401 bytes=157
https://10.43.0.1:443/api 401 bytes=157
https://10.43.0.1:443/api/v1/namespaces 401 bytes=157
https://10.43.0.1:443/api/v1/namespaces/felhom-system/secrets 401 bytes=157
https://192.168.0.180:6443/version 401 bytes=157
https://192.168.0.180:6443/api/v1/namespaces/felhom-system/secrets 401 bytes=157
== kubelet anonymous
https://192.168.0.180:10250/pods 401 bytes=12
https://192.168.0.180:10250/healthz 401 bytes=12
https://192.168.0.180:10250/metrics 401 bytes=12
http://192.168.0.180:10255/pods 000 bytes=0
== monitoring
http://10.43.75.209:9090/api/v1/status/buildinfo 200 bytes=205
http://10.43.75.209:9090/api/v1/query?query=up 200 bytes=5924
http://10.43.143.131:9093/api/v2/status 200 bytes=3340
http://10.43.143.131:9093/api/v2/silences 200 bytes=758
http://10.43.32.171:3000/api/health 200 bytes=101
http://10.43.32.171:3000/api/search 200 bytes=7276
http://10.43.32.171:3000/api/datasources 200 bytes=1053
http://10.43.42.73:9100/metrics 200 bytes=880412
== Gitea + registry
http://10.43.8.106:3000/api/v1/repos/search?limit=50 200 bytes=16231
anon-visible repos: "full_name":"authentik Default Admin" "full_name":"admin/app-catalog-felhom.eu" "full_name":"authentik Default Admin" "full_name":"admin/felhom-agent" "full_name":"authentik Default Admin" "full_name":"admin/felhom-controller" "full_name":"authentik Default Admin" "full_name":"admin/felhom.eu" "full_name":"authentik Default Admin" "full_name":"admin/misc-scripts" "full_name":"authentik Default Admin" "full_name":"admin/recipe-importer" "full_name":"authentik Default Admin" "full_name":"admin/revfulop-calendar"
http://10.43.8.106:3000/v2/ 401 bytes=49
http://10.43.8.106:3000/v2/_catalog 401 bytes=49
http://10.43.8.106:3000/v2/admin/felhom-hub/tags/list 401 bytes=49
http://10.43.8.106:3000/v2/admin/felhom-controller/tags/list 401 bytes=49
== Vaultwarden
http://10.43.38.33/alive 200 bytes=29
http://10.43.38.33/api/config 200 bytes=596
http://10.43.38.33/admin 200 bytes=6364
== ArgoCD
http://10.43.16.170/api/v1/applications 401 bytes=79
http://10.43.16.170/api/version 200 bytes=28
== filebrowsers (felhom-system one + others): API without login
http://10.43.219.38/api/resources/ 401 bytes=17
http://10.43.204.98/api/resources/ 401 bytes=17
http://10.43.188.12/api/resources/ 401 bytes=17
http://10.43.14.45/api/resources 401 bytes=54
== felhom-system/umami + contact-mailer
http://10.43.41.11/api/auth/verify 405 bytes=0
http://10.43.202.255/healthz 200 bytes=55
== DooPlex node ports from the pod (TCP connect only)
node 192.168.0.180:22 open
node 192.168.0.180:111 open
node 192.168.0.180:2049 open
node 192.168.0.180:3000 closed
node 192.168.0.180:5000 closed
node 192.168.0.180:6443 open
node 192.168.0.180:8006 closed
node 192.168.0.180:9100 open
node 192.168.0.180:10250 open
node 192.168.0.180:10255 closed
node 192.168.0.180:32400 closed
== NFS from a PRIVILEGED source port as uid 1000 (connect only; the 'secure' option checks this)
bind :700 + connect 2049: SUCCESS
@@ -0,0 +1,57 @@
# CoreDNS has NO query log (Corefile: errors/health/ready/kubernetes/hosts/prometheus/cache/loop/reload/loadbalance/forward — no 'log' plugin). Only upstream-timeout ERROR lines name a domain, and they carry the COREDNS pod's upstream socket, not the client. Names below: ERROR lines 2026-10-17T06:00+02 .. 2026-10-23T10:06+02, counted. Source: /var/log/pods/kube-system_coredns-65d746d599-d56mt_77a81c54-d56d-4921-8043-db05a3138b17/coredns/3.log (survived the 13:20Z reboot).
391 metrics.jarrs.eu.
372 _grpc_config.argocd-repo-server.
259 authentik.dooplex.hu.
247 store.steampowered.com.
234 _grpc_config.localhost.
224 hetzner.abonet.hu.
208 api.github.com.
184 gitea.dooplex.hu.
153 telex.hu.
142 outline.dooplex.hu.
137 pb.wanderer.dooplex.hu.
135 jarrs.eu.
127 bookstack.dooplex.hu.
122 nextcloud.dooplex.hu.
82 quay.io.
69 registry.hub.docker.com.
64 log.tailscale.com.
63 smtp.gmail.com.
48 pubsub00.pop.fra.plex.bz.
40 plex.enkisfelhom.hu.
39 pubsub13.pop.fra.plex.bz.
23 plex.tv.
22 ncore.pro.
16 grafana.com.
16 dl.k8s.io.
15 v4.plex.tv.
11 smtp.resend.com.
11 pubsub07.pop.fra.plex.bz.
10 pubsub01.pop.atl.plex.bz.
10 pubsub00.pop.dfw.plex.bz.
10 hand.genddos.st.
9 api.hetzner.com.
8 t.ncore.sh.
8 registry.k8s.io.
8 raw.githubusercontent.com.
7 version.goauthentik.io.
4 t.ncore.pro.
4 api.segment.io.
4 10-42-0-52.abcdefghijklmnopqrstuvwxyz012345.plex.direct.
3 version.immich.cloud.
3 controlplane.tailscale.com.
2 scrobbles.plex.tv.
2 pubsub08.pop.ewr.plex.bz.
1 thexem.info.
1 api.resend.com.
# hand.genddos.st lookups (all, local time +02:00):
2026-10-19T10:31:55
2026-10-19T10:48:24
2026-10-19T10:49:27
2026-10-19T11:43:02
2026-10-19T11:43:19
2026-10-19T11:43:36
2026-10-19T11:43:45
2026-10-19T11:43:47
2026-10-19T11:50:01
2026-10-19T11:50:48
@@ -0,0 +1,98 @@
# P3 hub access log (/data/access-log, R-1140) aggregates, read in the running hub pod 2026-10-23T15:28:30Z. Lines carry path/status/remote/xff/cred/auth only.
files: access-2026-10-18.log
access-2026-10-19.log
access-2026-10-20.log
access-2026-10-21.log
access-2026-10-22.log
access-2026-10-23.log
first line: 2026-10-18T10:25:05Z
lines total: 12764
== remote= values (count)
12481 remote=10.42.0.200
210 remote=10.42.0.1
54 remote=10.42.0.213
19 remote=10.42.0.107
== xff= first hop, grouped by /24 (count) — positive control: ingress traffic must show a client here
11728 192.168.0.x
762 37.191.56.x
38 176.77.140.x
4 176.77.139.x
3 10.42.0.x
== any remote or xff in the pod CIDR 10.42.x other than the ingress 10.42.0.200 (count, then lines)
283
2026-10-18T10:28:45Z GET /healthz 200 0ms remote=10.42.0.1 xff=- cred=- auth=-
2026-10-18T10:28:45Z GET /bind/[redacted] 200 0ms remote=10.42.0.1 xff=- cred=- auth=-
2026-10-18T10:28:45Z GET /configuration 302 0ms remote=10.42.0.1 xff=- cred=- auth=-
2026-10-18T10:28:45Z GET /api/v1/wait 401 0ms remote=10.42.0.1 xff=- cred=bearer+session-cookie auth=-
2026-10-18T10:28:45Z POST /login 401 187ms remote=10.42.0.1 xff=- cred=- auth=-
2026-10-18T10:29:00Z GET /configuration 200 1403ms remote=10.42.0.1 xff=- cred=token auth=token
2026-10-18T10:29:02Z GET /configuration/artifacts 403 0ms remote=10.42.0.1 xff=- cred=token auth=-
2026-10-18T10:29:10Z GET /configuration 200 7ms remote=10.42.0.1 xff=- cred=token auth=token
2026-10-18T10:39:55Z GET /api/v1/admin/hosts/demo-hp-bb76ea/recovery-credential 200 9ms remote=10.42.0.1 xff=- cred=bearer auth=global
2026-10-18T10:43:43Z GET /api/v1/admin/hosts/demo-hp-bb76ea/recovery-credential 200 0ms remote=10.42.0.1 xff=- cred=bearer auth=global
2026-10-18T10:55:13Z POST /api/v1/admin/hosts/demo-hp-bb76ea/jobs 201 26ms remote=10.42.0.1 xff=- cred=bearer auth=global
2026-10-18T10:55:13Z POST /api/v1/admin/hosts/demo-hp-bb76ea/jobs 201 4ms remote=10.42.0.1 xff=- cred=bearer auth=global
2026-10-18T11:09:23Z POST /customers/tester-1/floor 303 13ms remote=10.42.0.1 xff=- cred=token auth=token
2026-10-18T11:09:24Z POST /customers/demo-hp/floor 303 11ms remote=10.42.0.1 xff=- cred=token auth=token
2026-10-18T11:09:24Z POST /customers/demo-felhom/floor 303 9ms remote=10.42.0.1 xff=- cred=token auth=token
2026-10-18T11:10:59Z POST /configuration/global-floor 303 39ms remote=10.42.0.1 xff=- cred=token auth=token
2026-10-18T11:10:59Z POST /customers/tester-1/floor 303 8ms remote=10.42.0.1 xff=- cred=token auth=token
2026-10-18T11:11:00Z POST /customers/demo-hp/floor 303 11ms remote=10.42.0.1 xff=- cred=token auth=token
2026-10-18T11:11:00Z POST /customers/demo-felhom/floor 303 7ms remote=10.42.0.1 xff=- cred=token auth=token
2026-10-18T12:22:00Z POST /api/v1/admin/hosts/tester-1-d70be4/jobs 201 14ms remote=10.42.0.1 xff=- cred=bearer auth=global
== negative-control search: plex pod IP 10.42.0.52 anywhere
0
== credentialed requests (cred!=none) by xff and auth (count)
2511 xff=192.168.0.155 cred=bearer auth=customer
2444 xff=192.168.0.149 cred=bearer auth=customer
1889 xff=192.168.0.148 cred=bearer auth=customer
1272 xff=192.168.0.110 cred=session-cookie auth=session
552 xff=192.168.0.104 cred=bearer auth=host
549 xff=37.191.56.193 cred=bearer auth=host
531 xff=192.168.0.154 cred=bearer auth=host
523 xff=192.168.0.101 cred=bearer auth=customer
444 xff=192.168.0.133 cred=bearer auth=customer
263 xff=192.168.0.134 cred=bearer auth=-
261 xff=192.168.0.151 cred=bearer auth=customer
241 xff=192.168.0.125 cred=bearer auth=customer
173 xff=37.191.56.193 cred=bearer auth=customer
160 xff=- cred=token auth=token
130 xff=192.168.0.139 cred=bearer auth=customer
112 xff=192.168.0.128 cred=bearer auth=host
95 xff=192.168.0.134 cred=bearer auth=host
48 xff=192.168.0.128 cred=bearer auth=-
42 xff=192.168.0.159 cred=bearer auth=-
32 xff=192.168.0.110 cred=session-cookie auth=-
32 xff=- cred=bearer auth=global
27 xff=192.168.0.133 cred=bearer auth=host
23 xff=176.77.140.26 cred=session-cookie auth=session
22 xff=192.168.0.157 cred=bearer auth=customer
22 xff=192.168.0.135 cred=bearer auth=customer
20 xff=192.168.0.109 cred=bearer auth=-
15 xff=176.77.140.26 cred=session-cookie auth=-
14 xff=192.168.0.128 cred=passphrase auth=-
13 xff=- cred=token auth=-
9 xff=37.191.56.193 cred=session-cookie auth=session
== lines with xff in 10.42.x (all)
2026-10-23T13:00:38Z GET / 302 0ms remote=10.42.0.200 xff=10.42.0.1 cred=- auth=-
2026-10-23T13:02:09Z GET / 302 0ms remote=10.42.0.200 xff=10.42.0.1 cred=- auth=-
2026-10-23T14:00:08Z GET / 302 0ms remote=10.42.0.213 xff=10.42.0.1 cred=- auth=-
== remote=10.42.0.213: first/last and path set
2026-10-23T14:00:08Z GET / 302 0ms remote=10.42.0.213 xff=10.42.0.1 cred=- auth=-
2026-10-23T15:21:24Z GET /api/v1/wait 200 240000ms remote=10.42.0.213 xff=37.191.56.193 cred=bearer auth=customer
8 GET / 200
2 GET / 302
22 GET /api/v1/wait 200
1 GET /configuration 200
4 GET /hosts 200
1 GET /login 200
1 GET /style.css 200
6 POST /api/v1/host-report 200
7 POST /api/v1/report 200
1 POST /appliances/49/discard 303
1 POST /login 303
== remote=10.42.0.107 = this session's probe pod cc-p2s-probe (positive control: a direct pod call is logged with the pod IP)
2026-10-23T15:20:21Z GET / 302 0ms remote=10.42.0.107 xff=- cred=- auth=-
2026-10-23T15:22:25Z GET /healthz 200 0ms remote=10.42.0.107 xff=- cred=- auth=-
2026-10-23T15:22:25Z GET / 302 0ms remote=10.42.0.107 xff=- cred=- auth=-
File diff suppressed because one or more lines are too long
@@ -0,0 +1,370 @@
# P3 Longhorn objects created or changed in the window 2026-10-17T04:00:00Z .. 2026-10-23T08:05:00Z (and to now), 2026-10-23T15:26:52Z
== backuptargets: total 1
== volumes: total 78
2026-10-23T10:29:26Z pvc-625fd054-e576-46bb-89df-44df916705d0 created-in-window=true changes=[] {"longhornvolume":"pvc-625fd054-e576-46bb-89df-44df916705d0","recurring-job-group.longhorn.io/default":"enabled"}
== engines: total 78
2026-10-23T10:29:26Z pvc-625fd054-e576-46bb-89df-44df916705d0-e-0 created-in-window=true changes=[] {"longhornvolume":"pvc-625fd054-e576-46bb-89df-44df916705d0"}
== replicas: total 78
2026-10-23T10:29:26Z pvc-625fd054-e576-46bb-89df-44df916705d0-r-39bf02b9 created-in-window=true changes=[] {"longhornvolume":"pvc-625fd054-e576-46bb-89df-44df916705d0"}
== backups: total 178
2026-10-18T03:00:06Z backup-83f5ca7773d241dd created-in-window=true changes=[] {"backup-volume":"pvc-486c9809-4672-4b56-b70e-0bf01d0c3628"}
2026-10-18T03:00:06Z backup-9cb157e9f9404406 created-in-window=true changes=[] {"backup-volume":"pvc-1ae51535-0b2b-4975-bd9f-e651cc7a1edd"}
2026-10-18T03:00:21Z backup-831843c912bf4b12 created-in-window=true changes=[] {"backup-volume":"pvc-4e3fd336-9f09-4251-bd90-cdc259ef739e"}
2026-10-18T03:00:26Z backup-8b2ca7e2fbe34bf0 created-in-window=true changes=[] {"backup-volume":"pvc-71cbab32-86f9-40a5-8f3b-220ad626c492"}
2026-10-18T03:00:42Z backup-6e03f6813d7748cb created-in-window=true changes=[] {"backup-volume":"pvc-4e4aba1e-b414-4016-8895-ecdf0fb04a6b"}
2026-10-18T03:01:17Z backup-c64693c622f34710 created-in-window=true changes=[] {"backup-volume":"pvc-4fdd6da2-e795-4fa9-9e36-96f212c7018b"}
2026-10-18T03:01:22Z backup-1929a083d7244abc created-in-window=true changes=[] {"backup-volume":"pvc-11b257b2-8edc-4bf6-b846-00979feb195f"}
2026-10-18T03:01:33Z backup-68391531c3af4b10 created-in-window=true changes=[] {"backup-volume":"pvc-297c20e6-4ac0-42c4-9c69-24580a7f12ee"}
2026-10-18T03:01:42Z backup-11c551d5375b4b73 created-in-window=true changes=[] {"backup-volume":"pvc-1c47727a-d5ac-4171-ac36-26c2df3d0d63"}
2026-10-18T03:01:48Z backup-e830ec38da3e4aa0 created-in-window=true changes=[] {"backup-volume":"pvc-202e3bf2-9e61-4c59-ae0c-43fa6a42b403"}
2026-10-18T03:01:58Z backup-f7f8ab0ab97d4123 created-in-window=true changes=[] {"backup-volume":"pvc-42695a34-d921-4007-b5e5-e40aa728e104"}
2026-10-18T03:02:03Z backup-4388930c28b249ac created-in-window=true changes=[] {"backup-volume":"pvc-22343573-266d-492e-bd0a-37296217b523"}
2026-10-18T03:02:13Z backup-265f326237f943bc created-in-window=true changes=[] {"backup-volume":"pvc-459e6d2a-92b8-438e-a339-ff7e40089f3d"}
2026-10-18T03:02:38Z backup-31058e4d796843e0 created-in-window=true changes=[] {"backup-volume":"pvc-2e2e8c4c-4ba3-4dcf-9ed4-78acaf7ef92b"}
2026-10-18T03:02:49Z backup-d118ae8350584600 created-in-window=true changes=[] {"backup-volume":"pvc-6ed74c1a-3f10-4638-9baa-9330cbff980d"}
2026-10-18T03:02:54Z backup-6cc7894ae5d548e1 created-in-window=true changes=[] {"backup-volume":"pvc-38e8c624-5717-483b-8da1-613e703e36c8"}
2026-10-18T03:03:04Z backup-f9ef84c50f2a4f64 created-in-window=true changes=[] {"backup-volume":"pvc-b359d7de-1c7c-4b6a-9f6d-6776c2f876ef"}
2026-10-18T03:03:09Z backup-247107e8a9f4438a created-in-window=true changes=[] {"backup-volume":"pvc-79478678-07e4-4140-aef1-771ff763ab3f"}
2026-10-18T03:03:25Z backup-ef8d1e513d754e0a created-in-window=true changes=[] {"backup-volume":"pvc-7d6dec2c-0cda-43c7-ad1d-44ffebcb8cb6"}
2026-10-18T03:03:29Z backup-e0e842ed504b47f6 created-in-window=true changes=[] {"backup-volume":"pvc-cbfd55b0-4f44-487d-90fd-9c80b916ced7"}
2026-10-18T03:03:40Z backup-3c9743af9aba4880 created-in-window=true changes=[] {"backup-volume":"pvc-c6b9ab63-24b8-46f2-b52a-06da86393de8"}
2026-10-18T03:03:50Z backup-c6b2adafd1104326 created-in-window=true changes=[] {"backup-volume":"pvc-c8c0d0f1-c9ea-4ed3-9e22-1e254a026c49"}
2026-10-18T03:03:55Z backup-d43ed113492441e9 created-in-window=true changes=[] {"backup-volume":"pvc-c911715e-56ee-4d97-836e-89efc448ad9d"}
2026-10-18T03:04:16Z backup-64df95594d61410e created-in-window=true changes=[] {"backup-volume":"pvc-d9f09398-17cf-44b0-b3a2-9475bc773fec"}
2026-10-18T03:04:30Z backup-ddb8de7a110845a8 created-in-window=true changes=[] {"backup-volume":"pvc-d2ea5b66-d251-4467-9829-14654fab7a2f"}
2026-10-18T03:04:31Z backup-642f2c4d5e1f46e4 created-in-window=true changes=[] {"backup-volume":"pvc-e2151b14-2b24-4128-993a-c392c8d9706a"}
2026-10-18T03:04:46Z backup-324ef5fac7c04cf3 created-in-window=true changes=[] {"backup-volume":"pvc-8401df55-4668-40e3-97d2-d53e2c1090f1"}
2026-10-18T03:04:52Z backup-3df2312ae5834927 created-in-window=true changes=[] {"backup-volume":"pvc-7fc61dcd-52f0-45b4-97f1-9c82b28ab714"}
2026-10-18T03:05:01Z backup-36eb129a7fa340bf created-in-window=true changes=[] {"backup-volume":"pvc-a9dd6c7c-19eb-4a0a-935d-d2c30545c378"}
2026-10-18T03:05:07Z backup-affa5f905744417d created-in-window=true changes=[] {"backup-volume":"pvc-e3b26fdc-fd52-4fdf-9fa2-1d1ecfd029e4"}
2026-10-18T03:05:21Z backup-7954dead7a2f4ac0 created-in-window=true changes=[] {"backup-volume":"pvc-9ca6a486-40bb-46ac-ac48-bd49d4399f4b"}
2026-10-18T03:05:22Z backup-2c527e242af3442c created-in-window=true changes=[] {"backup-volume":"pvc-85be87dc-3351-4459-9f82-55f8cc598a2f"}
2026-10-18T03:05:43Z backup-05d9bbb684154607 created-in-window=true changes=[] {"backup-volume":"pvc-e5b8f824-7720-454c-b546-a098608df24a"}
2026-10-18T03:05:57Z backup-d8f19882fa7d464f created-in-window=true changes=[] {"backup-volume":"pvc-e57c220f-bc92-4815-89c9-0dee35eab3c3"}
2026-10-18T03:05:58Z backup-158db9819d8940a9 created-in-window=true changes=[] {"backup-volume":"pvc-8ed5eea5-67d4-46fc-9806-6b8fdd61e42e"}
2026-10-18T03:06:12Z backup-8ae6abaa0da54230 created-in-window=true changes=[] {"backup-volume":"pvc-88b4d7b4-cb5d-48e0-871e-9e150872d0bd"}
2026-10-18T03:06:13Z backup-12a5c7d715754fe4 created-in-window=true changes=[] {"backup-volume":"pvc-be9d7813-1881-462e-8951-1bd1315f7dc5"}
2026-10-18T03:06:27Z backup-935a9c3d36d7480a created-in-window=true changes=[] {"backup-volume":"pvc-ea977627-fb0a-4dee-8678-9ceceea448da"}
2026-10-18T03:06:29Z backup-c8d9e42845514f20 created-in-window=true changes=[] {"backup-volume":"pvc-b10da48e-6fcc-42ef-8414-d5d617028d68"}
2026-10-18T03:06:44Z backup-b9301ac86e494ac4 created-in-window=true changes=[] {"backup-volume":"pvc-beb0ad8a-755a-4152-a0af-f7367b32b19c"}
2026-10-18T03:06:48Z backup-50ba4beb9ca741d3 created-in-window=true changes=[] {"backup-volume":"pvc-b0e94be5-7cd8-4a4c-9295-901614e9eeb7"}
2026-10-18T03:07:00Z backup-7c33f6000bba49ad created-in-window=true changes=[] {"backup-volume":"pvc-8931072a-e34e-4333-9ab5-9629b6078505"}
2026-10-18T03:07:08Z backup-25ffadfcb65a4236 created-in-window=true changes=[] {"backup-volume":"pvc-c4dfbc43-2c35-4ef0-9cfe-39b3dc885dae"}
2026-10-18T03:07:30Z backup-f377a53003b44ec2 created-in-window=true changes=[] {"backup-volume":"pvc-7eb1f195-6a35-46c3-bbb1-5bab48209624"}
2026-10-18T03:07:34Z backup-5bc64db7e1854620 created-in-window=true changes=[] {"backup-volume":"pvc-17e3b3cc-9c6a-4d70-85cc-c2ae72e0b4ec"}
2026-10-18T03:07:49Z backup-70a99267481e466a created-in-window=true changes=[] {"backup-volume":"pvc-0113bbbf-fd5c-441b-9d58-6943ffa8c133"}
2026-10-18T03:07:50Z backup-2a7db97121514867 created-in-window=true changes=[] {"backup-volume":"pvc-5fbd3bbc-fb14-406d-954c-1a232ce313ce"}
2026-10-18T03:08:04Z backup-b736b062e3244ec5 created-in-window=true changes=[] {"backup-volume":"pvc-63f3b34f-3ac6-41a5-8790-3a27db0b5a2b"}
2026-10-18T03:08:06Z backup-d1654988274b4ef6 created-in-window=true changes=[] {"backup-volume":"pvc-2382e7bb-9514-409b-a2cc-e97c9725512a"}
2026-10-18T03:08:20Z backup-99f7cf4d8a6843c4 created-in-window=true changes=[] {"backup-volume":"pvc-3b23c214-ea15-40f8-aac5-61f783bf5beb"}
2026-10-18T03:08:21Z backup-d357833443b84351 created-in-window=true changes=[] {"backup-volume":"pvc-5acabaa7-6017-4793-b45e-f1f4fd80ab97"}
2026-10-18T03:08:35Z backup-0172504296ed493e created-in-window=true changes=[] {"backup-volume":"pvc-fc3d2f7f-6569-473c-acb4-002c613e5f18"}
2026-10-18T03:08:47Z backup-5bbbc3ddca4b4a62 created-in-window=true changes=[] {"backup-volume":"pvc-0eae2db7-47f1-477b-b9a9-9968c2d49a6d"}
2026-10-23T02:00:06Z backup-81b6314085e24457 created-in-window=true changes=[] {"backup-volume":"pvc-486c9809-4672-4b56-b70e-0bf01d0c3628"}
2026-10-23T02:00:06Z backup-e77c1fd337bb456b created-in-window=true changes=[] {"backup-volume":"pvc-71cbab32-86f9-40a5-8f3b-220ad626c492"}
2026-10-23T02:00:22Z backup-eb26a242694a4235 created-in-window=true changes=[] {"backup-volume":"pvc-5acabaa7-6017-4793-b45e-f1f4fd80ab97"}
2026-10-23T02:00:42Z backup-45644a4760604077 created-in-window=true changes=[] {"backup-volume":"pvc-4e3fd336-9f09-4251-bd90-cdc259ef739e"}
2026-10-23T02:01:08Z backup-3a373d05a9764a36 created-in-window=true changes=[] {"backup-volume":"pvc-4e4aba1e-b414-4016-8895-ecdf0fb04a6b"}
2026-10-23T02:01:32Z backup-9ccd1d94f68c485e created-in-window=true changes=[] {"backup-volume":"pvc-4fdd6da2-e795-4fa9-9e36-96f212c7018b"}
2026-10-23T02:01:33Z backup-1a5d5f5f6f254880 created-in-window=true changes=[] {"backup-volume":"pvc-22343573-266d-492e-bd0a-37296217b523"}
== backupvolumes: total 91
== backupbackingimages: total 0
== systembackups: total 0
== systemrestores: total 0
== recurringjobs: total 2
== volumeattachments: total 78
2026-10-23T10:29:26Z pvc-625fd054-e576-46bb-89df-44df916705d0 created-in-window=true changes=[] {"longhornvolume":"pvc-625fd054-e576-46bb-89df-44df916705d0"}
== snapshots: total 149
2026-10-18T03:00:01Z backup-w-9e561c5f-39bf-4de0-b86d-4154538ced31 created-in-window=true changes=[] {"longhornvolume":"pvc-1ae51535-0b2b-4975-bd9f-e651cc7a1edd"}
2026-10-18T03:00:01Z backup-w-c9cb53aa-4359-4309-9976-530a6faf3310 created-in-window=true changes=[] {"longhornvolume":"pvc-486c9809-4672-4b56-b70e-0bf01d0c3628"}
2026-10-18T03:00:16Z backup-w-8822d0fe-6849-4df1-bed1-7ea948861d7b created-in-window=true changes=[] {"longhornvolume":"pvc-71cbab32-86f9-40a5-8f3b-220ad626c492"}
2026-10-18T03:00:16Z backup-w-ce5a0dec-ec88-4da1-b14f-7acf37cda9e2 created-in-window=true changes=[] {"longhornvolume":"pvc-4e3fd336-9f09-4251-bd90-cdc259ef739e"}
2026-10-18T03:00:37Z backup-w-f36ce009-f2ec-4da5-bef2-e72746c50eae created-in-window=true changes=[] {"longhornvolume":"pvc-4e4aba1e-b414-4016-8895-ecdf0fb04a6b"}
2026-10-18T03:01:12Z backup-w-152bc04c-cfb0-494e-a020-b8edceb99208 created-in-window=true changes=[] {"longhornvolume":"pvc-4fdd6da2-e795-4fa9-9e36-96f212c7018b"}
2026-10-18T03:01:17Z backup-w-7be4c31e-99c9-4858-abc0-8b2b102fa6eb created-in-window=true changes=[] {"longhornvolume":"pvc-11b257b2-8edc-4bf6-b846-00979feb195f"}
2026-10-18T03:01:28Z backup-w-492c52b6-af58-4b56-b031-e1a2f610e656 created-in-window=true changes=[] {"longhornvolume":"pvc-297c20e6-4ac0-42c4-9c69-24580a7f12ee"}
2026-10-18T03:01:32Z backup-w-500c8206-b274-4c95-adc1-7dbf77b41806 created-in-window=true changes=[] {"longhornvolume":"pvc-1c47727a-d5ac-4171-ac36-26c2df3d0d63"}
2026-10-18T03:01:43Z backup-w-477bb594-f177-4d5b-be17-2db7fc908486 created-in-window=true changes=[] {"longhornvolume":"pvc-202e3bf2-9e61-4c59-ae0c-43fa6a42b403"}
2026-10-18T03:01:52Z backup-w-5a54721b-bdfc-48ae-8f5f-8612bff3525d created-in-window=true changes=[] {"longhornvolume":"pvc-42695a34-d921-4007-b5e5-e40aa728e104"}
2026-10-18T03:01:53Z backup-w-dea6667f-c93f-4bb7-ad59-b8b3bc772476 created-in-window=true changes=[] {"longhornvolume":"pvc-22343573-266d-492e-bd0a-37296217b523"}
2026-10-18T03:02:08Z backup-w-069a5b3f-1600-4147-9566-29f351d2bb39 created-in-window=true changes=[] {"longhornvolume":"pvc-459e6d2a-92b8-438e-a339-ff7e40089f3d"}
2026-10-18T03:02:33Z backup-w-a493d271-9d5e-41d5-a93c-7954e173eb0f created-in-window=true changes=[] {"longhornvolume":"pvc-2e2e8c4c-4ba3-4dcf-9ed4-78acaf7ef92b"}
2026-10-18T03:02:44Z backup-w-34fa0b60-8201-4c21-aad1-f73656d1fc4c created-in-window=true changes=[] {"longhornvolume":"pvc-6ed74c1a-3f10-4638-9baa-9330cbff980d"}
2026-10-18T03:02:44Z backup-w-db1904d5-7bfe-45f4-81c6-e17010691225 created-in-window=true changes=[] {"longhornvolume":"pvc-38e8c624-5717-483b-8da1-613e703e36c8"}
2026-10-18T03:02:59Z backup-w-e06ba46d-8847-4f8c-9a9c-ad67982d4f5c created-in-window=true changes=[] {"longhornvolume":"pvc-b359d7de-1c7c-4b6a-9f6d-6776c2f876ef"}
2026-10-18T03:03:04Z backup-w-cac58903-1e3d-4c60-95ed-72e4d7ac4662 created-in-window=true changes=[] {"longhornvolume":"pvc-79478678-07e4-4140-aef1-771ff763ab3f"}
2026-10-18T03:03:14Z backup-w-80d619fb-2f32-4af8-aa0c-7d6c034896a7 created-in-window=true changes=[] {"longhornvolume":"pvc-7d6dec2c-0cda-43c7-ad1d-44ffebcb8cb6"}
2026-10-18T03:03:19Z backup-w-34af7ebb-cca6-47a6-a668-541a5f4124a3 created-in-window=true changes=[] {"longhornvolume":"pvc-cbfd55b0-4f44-487d-90fd-9c80b916ced7"}
2026-10-18T03:03:35Z backup-w-ec972d0f-02f6-47de-8252-f3471a63d29a created-in-window=true changes=[] {"longhornvolume":"pvc-c6b9ab63-24b8-46f2-b52a-06da86393de8"}
2026-10-18T03:03:40Z backup-w-336bb191-b457-432c-8b3b-a49b8fbcb844 created-in-window=true changes=[] {"longhornvolume":"pvc-c8c0d0f1-c9ea-4ed3-9e22-1e254a026c49"}
2026-10-18T03:03:50Z backup-w-132be759-46d9-48f4-9b7f-731dbf00aa5a created-in-window=true changes=[] {"longhornvolume":"pvc-c911715e-56ee-4d97-836e-89efc448ad9d"}
2026-10-18T03:04:06Z backup-w-81d52611-6488-4b98-aced-cb0dd836c4c0 created-in-window=true changes=[] {"longhornvolume":"pvc-d9f09398-17cf-44b0-b3a2-9475bc773fec"}
2026-10-18T03:04:25Z backup-w-f12dd015-e375-4aeb-903d-a6d24adb621a created-in-window=true changes=[] {"longhornvolume":"pvc-d2ea5b66-d251-4467-9829-14654fab7a2f"}
2026-10-18T03:04:26Z backup-w-b5f21af2-a32d-4a2d-954d-4853baf4520b created-in-window=true changes=[] {"longhornvolume":"pvc-e2151b14-2b24-4128-993a-c392c8d9706a"}
2026-10-18T03:04:40Z backup-w-501e9c93-1004-4c30-acea-26b58f69f598 created-in-window=true changes=[] {"longhornvolume":"pvc-8401df55-4668-40e3-97d2-d53e2c1090f1"}
2026-10-18T03:04:41Z backup-w-9929ed08-8a85-4c29-83a9-c0e3bfb23b33 created-in-window=true changes=[] {"longhornvolume":"pvc-7fc61dcd-52f0-45b4-97f1-9c82b28ab714"}
2026-10-18T03:04:56Z backup-w-44cb1d12-6aeb-4ced-9977-029cf9296c86 created-in-window=true changes=[] {"longhornvolume":"pvc-a9dd6c7c-19eb-4a0a-935d-d2c30545c378"}
2026-10-18T03:05:02Z backup-w-5c387443-5da4-4918-b5b7-c23f0873d081 created-in-window=true changes=[] {"longhornvolume":"pvc-e3b26fdc-fd52-4fdf-9fa2-1d1ecfd029e4"}
2026-10-18T03:05:11Z backup-w-908f1c40-5b75-4a93-bd0b-c5ec6c3b5c5a created-in-window=true changes=[] {"longhornvolume":"pvc-9ca6a486-40bb-46ac-ac48-bd49d4399f4b"}
2026-10-18T03:05:17Z backup-w-a26221ac-ad81-45a1-93cd-c730ebf48fa9 created-in-window=true changes=[] {"longhornvolume":"pvc-85be87dc-3351-4459-9f82-55f8cc598a2f"}
2026-10-18T03:05:32Z backup-w-8af31417-1f16-4ed5-9bb4-1e3ec016f766 created-in-window=true changes=[] {"longhornvolume":"pvc-e5b8f824-7720-454c-b546-a098608df24a"}
2026-10-18T03:05:52Z backup-w-24190c0e-85a4-480b-9451-91a931351415 created-in-window=true changes=[] {"longhornvolume":"pvc-e57c220f-bc92-4815-89c9-0dee35eab3c3"}
2026-10-18T03:05:53Z backup-w-ce360270-a851-4ff8-a481-ad9933848b48 created-in-window=true changes=[] {"longhornvolume":"pvc-8ed5eea5-67d4-46fc-9806-6b8fdd61e42e"}
2026-10-18T03:06:07Z backup-w-768fe287-8ac0-43ce-b7c4-017f340a6276 created-in-window=true changes=[] {"longhornvolume":"pvc-88b4d7b4-cb5d-48e0-871e-9e150872d0bd"}
2026-10-18T03:06:08Z backup-w-55284120-f572-42de-a65d-f32ce33b8d6b created-in-window=true changes=[] {"longhornvolume":"pvc-be9d7813-1881-462e-8951-1bd1315f7dc5"}
2026-10-18T03:06:22Z backup-w-89e8e1d8-e924-4911-80da-d88420c47ab6 created-in-window=true changes=[] {"longhornvolume":"pvc-ea977627-fb0a-4dee-8678-9ceceea448da"}
2026-10-18T03:06:24Z backup-w-6ec192d8-7928-4fed-bba5-8d3db7f4ccaf created-in-window=true changes=[] {"longhornvolume":"pvc-b10da48e-6fcc-42ef-8414-d5d617028d68"}
2026-10-18T03:06:39Z backup-w-5c4c2d48-70be-402d-8ef6-0665f01012cf created-in-window=true changes=[] {"longhornvolume":"pvc-beb0ad8a-755a-4152-a0af-f7367b32b19c"}
2026-10-18T03:06:43Z backup-w-073e62b6-6177-4d87-a7e2-28b55567d729 created-in-window=true changes=[] {"longhornvolume":"pvc-b0e94be5-7cd8-4a4c-9295-901614e9eeb7"}
2026-10-18T03:06:54Z backup-w-9689a569-2397-4947-b1b5-94042bc973f4 created-in-window=true changes=[] {"longhornvolume":"pvc-8931072a-e34e-4333-9ab5-9629b6078505"}
2026-10-18T03:07:03Z backup-w-47b6014f-5f34-4484-9d80-10bab2b2633f created-in-window=true changes=[] {"longhornvolume":"pvc-c4dfbc43-2c35-4ef0-9cfe-39b3dc885dae"}
2026-10-18T03:07:25Z backup-w-d0f4fe40-8c48-4990-969a-d421e45e734c created-in-window=true changes=[] {"longhornvolume":"pvc-7eb1f195-6a35-46c3-bbb1-5bab48209624"}
2026-10-18T03:07:29Z backup-w-cf531882-6842-4629-8470-97a63d9f1263 created-in-window=true changes=[] {"longhornvolume":"pvc-17e3b3cc-9c6a-4d70-85cc-c2ae72e0b4ec"}
2026-10-18T03:07:40Z backup-w-94e25d95-26b5-441f-b57c-6c38dcfd1bd5 created-in-window=true changes=[] {"longhornvolume":"pvc-5fbd3bbc-fb14-406d-954c-1a232ce313ce"}
2026-10-18T03:07:44Z backup-w-7c27529f-7e1c-4515-b4e3-5a92eef9904a created-in-window=true changes=[] {"longhornvolume":"pvc-0113bbbf-fd5c-441b-9d58-6943ffa8c133"}
2026-10-18T03:07:59Z backup-w-9e4f3b48-85bb-4b17-a504-3774ea4e6e14 created-in-window=true changes=[] {"longhornvolume":"pvc-63f3b34f-3ac6-41a5-8790-3a27db0b5a2b"}
2026-10-18T03:08:01Z backup-w-3c194f84-d8a0-4ecb-baf0-9c4a16318987 created-in-window=true changes=[] {"longhornvolume":"pvc-2382e7bb-9514-409b-a2cc-e97c9725512a"}
2026-10-18T03:08:15Z backup-w-849c9f2d-fbab-4084-998b-2dcbc5b8e3af created-in-window=true changes=[] {"longhornvolume":"pvc-3b23c214-ea15-40f8-aac5-61f783bf5beb"}
2026-10-18T03:08:16Z backup-w-6a5d4be2-a059-40b4-bee8-abf12199ae05 created-in-window=true changes=[] {"longhornvolume":"pvc-5acabaa7-6017-4793-b45e-f1f4fd80ab97"}
2026-10-18T03:08:30Z backup-w-aec12d6b-becd-4ca1-9590-a60f5f4a4f45 created-in-window=true changes=[] {"longhornvolume":"pvc-fc3d2f7f-6569-473c-acb4-002c613e5f18"}
2026-10-18T03:08:41Z backup-w-b3049de0-fe68-472b-8964-f0140a6b2c54 created-in-window=true changes=[] {"longhornvolume":"pvc-0eae2db7-47f1-477b-b9a9-9968c2d49a6d"}
2026-10-23T02:00:01Z backup-d-bcf88ff5-ab92-4511-bcd4-a4686c8941f2 created-in-window=true changes=[] {"longhornvolume":"pvc-71cbab32-86f9-40a5-8f3b-220ad626c492"}
2026-10-23T02:00:01Z backup-d-d8d68af0-acc6-4a07-bd57-1eb283dc8588 created-in-window=true changes=[] {"longhornvolume":"pvc-486c9809-4672-4b56-b70e-0bf01d0c3628"}
2026-10-23T02:00:17Z backup-d-6afe7cd9-fd63-48ff-96b7-b8bd7ba03aa0 created-in-window=true changes=[] {"longhornvolume":"pvc-5acabaa7-6017-4793-b45e-f1f4fd80ab97"}
2026-10-23T02:00:37Z backup-d-ab86b601-8c71-4e9e-ab5f-6211e6bccc2f created-in-window=true changes=[] {"longhornvolume":"pvc-4e3fd336-9f09-4251-bd90-cdc259ef739e"}
2026-10-23T02:01:03Z backup-d-723e6872-0483-4fa0-8482-2f449b038fbd created-in-window=true changes=[] {"longhornvolume":"pvc-4e4aba1e-b414-4016-8895-ecdf0fb04a6b"}
2026-10-23T02:01:27Z backup-d-532d9238-ffdd-43ae-a17e-02e263490801 created-in-window=true changes=[] {"longhornvolume":"pvc-4fdd6da2-e795-4fa9-9e36-96f212c7018b"}
2026-10-23T02:01:28Z backup-d-d2227be3-7347-4bdc-a023-9164ce5a0b0b created-in-window=true changes=[] {"longhornvolume":"pvc-22343573-266d-492e-bd0a-37296217b523"}
== settings: total 97
== nodes: total 1
== orphans: total 0
== sharemanagers: total 2
== backingimages: total 0
# CORRECTION 2026-10-23T15:27:30Z: Longhorn CRs carry NO managedFields (checked: backuptarget 'default' mf=[] while its generation is 93466). The 'changes=' column above is therefore EMPTY BY CONSTRUCTION and proves nothing. Only creationTimestamp is evidence.
== backups created in window, by volume, with target URL and labels
2026-10-18T03:00:06Z pvc-1ae51535-0b2b-4975-bd9f-e651cc7a1edd state=Completed url=nfs://192.168.0.180:/mnt/5_hdd/backup/longhorn-pvc?backup=ba target=default rj=backup-weekly snap=backup-w-9e561c5f-39bf-4de0-b86d-4154538
2026-10-18T03:00:06Z pvc-486c9809-4672-4b56-b70e-0bf01d0c3628 state=Completed url=nfs://192.168.0.180:/mnt/5_hdd/backup/longhorn-pvc?backup=ba target=default rj=backup-weekly snap=backup-w-c9cb53aa-4359-4309-9976-530a6fa
2026-10-18T03:00:21Z pvc-4e3fd336-9f09-4251-bd90-cdc259ef739e state=Completed url=nfs://192.168.0.180:/mnt/5_hdd/backup/longhorn-pvc?backup=ba target=default rj=backup-weekly snap=backup-w-ce5a0dec-ec88-4da1-b14f-7acf37c
2026-10-18T03:00:26Z pvc-71cbab32-86f9-40a5-8f3b-220ad626c492 state=Completed url=nfs://192.168.0.180:/mnt/5_hdd/backup/longhorn-pvc?backup=ba target=default rj=backup-weekly snap=backup-w-8822d0fe-6849-4df1-bed1-7ea9488
2026-10-18T03:00:42Z pvc-4e4aba1e-b414-4016-8895-ecdf0fb04a6b state=Completed url=nfs://192.168.0.180:/mnt/5_hdd/backup/longhorn-pvc?backup=ba target=default rj=backup-weekly snap=backup-w-f36ce009-f2ec-4da5-bef2-e72746c
2026-10-18T03:01:17Z pvc-4fdd6da2-e795-4fa9-9e36-96f212c7018b state=Completed url=nfs://192.168.0.180:/mnt/5_hdd/backup/longhorn-pvc?backup=ba target=default rj=backup-weekly snap=backup-w-152bc04c-cfb0-494e-a020-b8edceb
2026-10-18T03:01:22Z pvc-11b257b2-8edc-4bf6-b846-00979feb195f state=Completed url=nfs://192.168.0.180:/mnt/5_hdd/backup/longhorn-pvc?backup=ba target=default rj=backup-weekly snap=backup-w-7be4c31e-99c9-4858-abc0-8b2b102
2026-10-18T03:01:33Z pvc-297c20e6-4ac0-42c4-9c69-24580a7f12ee state=Completed url=nfs://192.168.0.180:/mnt/5_hdd/backup/longhorn-pvc?backup=ba target=default rj=backup-weekly snap=backup-w-492c52b6-af58-4b56-b031-e1a2f61
2026-10-18T03:01:42Z pvc-1c47727a-d5ac-4171-ac36-26c2df3d0d63 state=Completed url=nfs://192.168.0.180:/mnt/5_hdd/backup/longhorn-pvc?backup=ba target=default rj=backup-weekly snap=backup-w-500c8206-b274-4c95-adc1-7dbf77b
2026-10-18T03:01:48Z pvc-202e3bf2-9e61-4c59-ae0c-43fa6a42b403 state=Completed url=nfs://192.168.0.180:/mnt/5_hdd/backup/longhorn-pvc?backup=ba target=default rj=backup-weekly snap=backup-w-477bb594-f177-4d5b-be17-2db7fc9
2026-10-18T03:01:58Z pvc-42695a34-d921-4007-b5e5-e40aa728e104 state=Completed url=nfs://192.168.0.180:/mnt/5_hdd/backup/longhorn-pvc?backup=ba target=default rj=backup-weekly snap=backup-w-5a54721b-bdfc-48ae-8f5f-8612bff
2026-10-18T03:02:03Z pvc-22343573-266d-492e-bd0a-37296217b523 state=Completed url=nfs://192.168.0.180:/mnt/5_hdd/backup/longhorn-pvc?backup=ba target=default rj=backup-weekly snap=backup-w-dea6667f-c93f-4bb7-ad59-b8b3bc7
2026-10-18T03:02:13Z pvc-459e6d2a-92b8-438e-a339-ff7e40089f3d state=Completed url=nfs://192.168.0.180:/mnt/5_hdd/backup/longhorn-pvc?backup=ba target=default rj=backup-weekly snap=backup-w-069a5b3f-1600-4147-9566-29f351d
2026-10-18T03:02:38Z pvc-2e2e8c4c-4ba3-4dcf-9ed4-78acaf7ef92b state=Completed url=nfs://192.168.0.180:/mnt/5_hdd/backup/longhorn-pvc?backup=ba target=default rj=backup-weekly snap=backup-w-a493d271-9d5e-41d5-a93c-7954e17
2026-10-18T03:02:49Z pvc-6ed74c1a-3f10-4638-9baa-9330cbff980d state=Completed url=nfs://192.168.0.180:/mnt/5_hdd/backup/longhorn-pvc?backup=ba target=default rj=backup-weekly snap=backup-w-34fa0b60-8201-4c21-aad1-f73656d
2026-10-18T03:02:54Z pvc-38e8c624-5717-483b-8da1-613e703e36c8 state=Completed url=nfs://192.168.0.180:/mnt/5_hdd/backup/longhorn-pvc?backup=ba target=default rj=backup-weekly snap=backup-w-db1904d5-7bfe-45f4-81c6-e170106
2026-10-18T03:03:04Z pvc-b359d7de-1c7c-4b6a-9f6d-6776c2f876ef state=Completed url=nfs://192.168.0.180:/mnt/5_hdd/backup/longhorn-pvc?backup=ba target=default rj=backup-weekly snap=backup-w-e06ba46d-8847-4f8c-9a9c-ad67982
2026-10-18T03:03:09Z pvc-79478678-07e4-4140-aef1-771ff763ab3f state=Completed url=nfs://192.168.0.180:/mnt/5_hdd/backup/longhorn-pvc?backup=ba target=default rj=backup-weekly snap=backup-w-cac58903-1e3d-4c60-95ed-72e4d7a
2026-10-18T03:03:25Z pvc-7d6dec2c-0cda-43c7-ad1d-44ffebcb8cb6 state=Completed url=nfs://192.168.0.180:/mnt/5_hdd/backup/longhorn-pvc?backup=ba target=default rj=backup-weekly snap=backup-w-80d619fb-2f32-4af8-aa0c-7d6c034
2026-10-18T03:03:29Z pvc-cbfd55b0-4f44-487d-90fd-9c80b916ced7 state=Completed url=nfs://192.168.0.180:/mnt/5_hdd/backup/longhorn-pvc?backup=ba target=default rj=backup-weekly snap=backup-w-34af7ebb-cca6-47a6-a668-541a5f4
2026-10-18T03:03:40Z pvc-c6b9ab63-24b8-46f2-b52a-06da86393de8 state=Completed url=nfs://192.168.0.180:/mnt/5_hdd/backup/longhorn-pvc?backup=ba target=default rj=backup-weekly snap=backup-w-ec972d0f-02f6-47de-8252-f3471a6
2026-10-18T03:03:50Z pvc-c8c0d0f1-c9ea-4ed3-9e22-1e254a026c49 state=Completed url=nfs://192.168.0.180:/mnt/5_hdd/backup/longhorn-pvc?backup=ba target=default rj=backup-weekly snap=backup-w-336bb191-b457-432c-8b3b-a49b8fb
2026-10-18T03:03:55Z pvc-c911715e-56ee-4d97-836e-89efc448ad9d state=Completed url=nfs://192.168.0.180:/mnt/5_hdd/backup/longhorn-pvc?backup=ba target=default rj=backup-weekly snap=backup-w-132be759-46d9-48f4-9b7f-731dbf0
2026-10-18T03:04:16Z pvc-d9f09398-17cf-44b0-b3a2-9475bc773fec state=Completed url=nfs://192.168.0.180:/mnt/5_hdd/backup/longhorn-pvc?backup=ba target=default rj=backup-weekly snap=backup-w-81d52611-6488-4b98-aced-cb0dd83
2026-10-18T03:04:30Z pvc-d2ea5b66-d251-4467-9829-14654fab7a2f state=Completed url=nfs://192.168.0.180:/mnt/5_hdd/backup/longhorn-pvc?backup=ba target=default rj=backup-weekly snap=backup-w-f12dd015-e375-4aeb-903d-a6d24ad
2026-10-18T03:04:31Z pvc-e2151b14-2b24-4128-993a-c392c8d9706a state=Completed url=nfs://192.168.0.180:/mnt/5_hdd/backup/longhorn-pvc?backup=ba target=default rj=backup-weekly snap=backup-w-b5f21af2-a32d-4a2d-954d-4853baf
2026-10-18T03:04:46Z pvc-8401df55-4668-40e3-97d2-d53e2c1090f1 state=Completed url=nfs://192.168.0.180:/mnt/5_hdd/backup/longhorn-pvc?backup=ba target=default rj=backup-weekly snap=backup-w-501e9c93-1004-4c30-acea-26b58f6
2026-10-18T03:04:52Z pvc-7fc61dcd-52f0-45b4-97f1-9c82b28ab714 state=Completed url=nfs://192.168.0.180:/mnt/5_hdd/backup/longhorn-pvc?backup=ba target=default rj=backup-weekly snap=backup-w-9929ed08-8a85-4c29-83a9-c0e3bfb
2026-10-18T03:05:01Z pvc-a9dd6c7c-19eb-4a0a-935d-d2c30545c378 state=Completed url=nfs://192.168.0.180:/mnt/5_hdd/backup/longhorn-pvc?backup=ba target=default rj=backup-weekly snap=backup-w-44cb1d12-6aeb-4ced-9977-029cf92
2026-10-18T03:05:07Z pvc-e3b26fdc-fd52-4fdf-9fa2-1d1ecfd029e4 state=Completed url=nfs://192.168.0.180:/mnt/5_hdd/backup/longhorn-pvc?backup=ba target=default rj=backup-weekly snap=backup-w-5c387443-5da4-4918-b5b7-c23f087
2026-10-18T03:05:21Z pvc-9ca6a486-40bb-46ac-ac48-bd49d4399f4b state=Completed url=nfs://192.168.0.180:/mnt/5_hdd/backup/longhorn-pvc?backup=ba target=default rj=backup-weekly snap=backup-w-908f1c40-5b75-4a93-bd0b-c5ec6c3
2026-10-18T03:05:22Z pvc-85be87dc-3351-4459-9f82-55f8cc598a2f state=Completed url=nfs://192.168.0.180:/mnt/5_hdd/backup/longhorn-pvc?backup=ba target=default rj=backup-weekly snap=backup-w-a26221ac-ad81-45a1-93cd-c730ebf
2026-10-18T03:05:43Z pvc-e5b8f824-7720-454c-b546-a098608df24a state=Completed url=nfs://192.168.0.180:/mnt/5_hdd/backup/longhorn-pvc?backup=ba target=default rj=backup-weekly snap=backup-w-8af31417-1f16-4ed5-9bb4-1e3ec01
2026-10-18T03:05:57Z pvc-e57c220f-bc92-4815-89c9-0dee35eab3c3 state=Completed url=nfs://192.168.0.180:/mnt/5_hdd/backup/longhorn-pvc?backup=ba target=default rj=backup-weekly snap=backup-w-24190c0e-85a4-480b-9451-91a9313
2026-10-18T03:05:58Z pvc-8ed5eea5-67d4-46fc-9806-6b8fdd61e42e state=Completed url=nfs://192.168.0.180:/mnt/5_hdd/backup/longhorn-pvc?backup=ba target=default rj=backup-weekly snap=backup-w-ce360270-a851-4ff8-a481-ad99338
2026-10-18T03:06:12Z pvc-88b4d7b4-cb5d-48e0-871e-9e150872d0bd state=Completed url=nfs://192.168.0.180:/mnt/5_hdd/backup/longhorn-pvc?backup=ba target=default rj=backup-weekly snap=backup-w-768fe287-8ac0-43ce-b7c4-017f340
2026-10-18T03:06:13Z pvc-be9d7813-1881-462e-8951-1bd1315f7dc5 state=Completed url=nfs://192.168.0.180:/mnt/5_hdd/backup/longhorn-pvc?backup=ba target=default rj=backup-weekly snap=backup-w-55284120-f572-42de-a65d-f32ce33
2026-10-18T03:06:27Z pvc-ea977627-fb0a-4dee-8678-9ceceea448da state=Completed url=nfs://192.168.0.180:/mnt/5_hdd/backup/longhorn-pvc?backup=ba target=default rj=backup-weekly snap=backup-w-89e8e1d8-e924-4911-80da-d88420c
2026-10-18T03:06:29Z pvc-b10da48e-6fcc-42ef-8414-d5d617028d68 state=Completed url=nfs://192.168.0.180:/mnt/5_hdd/backup/longhorn-pvc?backup=ba target=default rj=backup-weekly snap=backup-w-6ec192d8-7928-4fed-bba5-8d3db7f
2026-10-18T03:06:44Z pvc-beb0ad8a-755a-4152-a0af-f7367b32b19c state=Completed url=nfs://192.168.0.180:/mnt/5_hdd/backup/longhorn-pvc?backup=ba target=default rj=backup-weekly snap=backup-w-5c4c2d48-70be-402d-8ef6-0665f01
2026-10-18T03:06:48Z pvc-b0e94be5-7cd8-4a4c-9295-901614e9eeb7 state=Completed url=nfs://192.168.0.180:/mnt/5_hdd/backup/longhorn-pvc?backup=ba target=default rj=backup-weekly snap=backup-w-073e62b6-6177-4d87-a7e2-28b5556
2026-10-18T03:07:00Z pvc-8931072a-e34e-4333-9ab5-9629b6078505 state=Completed url=nfs://192.168.0.180:/mnt/5_hdd/backup/longhorn-pvc?backup=ba target=default rj=backup-weekly snap=backup-w-9689a569-2397-4947-b1b5-94042bc
2026-10-18T03:07:08Z pvc-c4dfbc43-2c35-4ef0-9cfe-39b3dc885dae state=Completed url=nfs://192.168.0.180:/mnt/5_hdd/backup/longhorn-pvc?backup=ba target=default rj=backup-weekly snap=backup-w-47b6014f-5f34-4484-9d80-10bab2b
2026-10-18T03:07:30Z pvc-7eb1f195-6a35-46c3-bbb1-5bab48209624 state=Completed url=nfs://192.168.0.180:/mnt/5_hdd/backup/longhorn-pvc?backup=ba target=default rj=backup-weekly snap=backup-w-d0f4fe40-8c48-4990-969a-d421e45
2026-10-18T03:07:34Z pvc-17e3b3cc-9c6a-4d70-85cc-c2ae72e0b4ec state=Completed url=nfs://192.168.0.180:/mnt/5_hdd/backup/longhorn-pvc?backup=ba target=default rj=backup-weekly snap=backup-w-cf531882-6842-4629-8470-97a63d9
2026-10-18T03:07:49Z pvc-0113bbbf-fd5c-441b-9d58-6943ffa8c133 state=Completed url=nfs://192.168.0.180:/mnt/5_hdd/backup/longhorn-pvc?backup=ba target=default rj=backup-weekly snap=backup-w-7c27529f-7e1c-4515-b4e3-5a92eef
2026-10-18T03:07:50Z pvc-5fbd3bbc-fb14-406d-954c-1a232ce313ce state=Completed url=nfs://192.168.0.180:/mnt/5_hdd/backup/longhorn-pvc?backup=ba target=default rj=backup-weekly snap=backup-w-94e25d95-26b5-441f-b57c-6c38dcf
2026-10-18T03:08:04Z pvc-63f3b34f-3ac6-41a5-8790-3a27db0b5a2b state=Completed url=nfs://192.168.0.180:/mnt/5_hdd/backup/longhorn-pvc?backup=ba target=default rj=backup-weekly snap=backup-w-9e4f3b48-85bb-4b17-a504-3774ea4
2026-10-18T03:08:06Z pvc-2382e7bb-9514-409b-a2cc-e97c9725512a state=Completed url=nfs://192.168.0.180:/mnt/5_hdd/backup/longhorn-pvc?backup=ba target=default rj=backup-weekly snap=backup-w-3c194f84-d8a0-4ecb-baf0-9c4a163
2026-10-18T03:08:20Z pvc-3b23c214-ea15-40f8-aac5-61f783bf5beb state=Completed url=nfs://192.168.0.180:/mnt/5_hdd/backup/longhorn-pvc?backup=ba target=default rj=backup-weekly snap=backup-w-849c9f2d-fbab-4084-998b-2dcbc5b
2026-10-18T03:08:21Z pvc-5acabaa7-6017-4793-b45e-f1f4fd80ab97 state=Completed url=nfs://192.168.0.180:/mnt/5_hdd/backup/longhorn-pvc?backup=ba target=default rj=backup-weekly snap=backup-w-6a5d4be2-a059-40b4-bee8-abf1219
2026-10-18T03:08:35Z pvc-fc3d2f7f-6569-473c-acb4-002c613e5f18 state=Completed url=nfs://192.168.0.180:/mnt/5_hdd/backup/longhorn-pvc?backup=ba target=default rj=backup-weekly snap=backup-w-aec12d6b-becd-4ca1-9590-a60f5f4
2026-10-18T03:08:47Z pvc-0eae2db7-47f1-477b-b9a9-9968c2d49a6d state=Completed url=nfs://192.168.0.180:/mnt/5_hdd/backup/longhorn-pvc?backup=ba target=default rj=backup-weekly snap=backup-w-b3049de0-fe68-472b-8964-f0140a6
2026-10-23T02:00:06Z pvc-486c9809-4672-4b56-b70e-0bf01d0c3628 state=Completed url=nfs://192.168.0.180:/mnt/5_hdd/backup/longhorn-pvc?backup=ba target=default rj=backup-daily snap=backup-d-d8d68af0-acc6-4a07-bd57-1eb283d
2026-10-23T02:00:06Z pvc-71cbab32-86f9-40a5-8f3b-220ad626c492 state=Completed url=nfs://192.168.0.180:/mnt/5_hdd/backup/longhorn-pvc?backup=ba target=default rj=backup-daily snap=backup-d-bcf88ff5-ab92-4511-bcd4-a4686c8
2026-10-23T02:00:22Z pvc-5acabaa7-6017-4793-b45e-f1f4fd80ab97 state=Completed url=nfs://192.168.0.180:/mnt/5_hdd/backup/longhorn-pvc?backup=ba target=default rj=backup-daily snap=backup-d-6afe7cd9-fd63-48ff-96b7-b8bd7ba
2026-10-23T02:00:42Z pvc-4e3fd336-9f09-4251-bd90-cdc259ef739e state=Completed url=nfs://192.168.0.180:/mnt/5_hdd/backup/longhorn-pvc?backup=ba target=default rj=backup-daily snap=backup-d-ab86b601-8c71-4e9e-ab5f-6211e6b
2026-10-23T02:01:08Z pvc-4e4aba1e-b414-4016-8895-ecdf0fb04a6b state=Completed url=nfs://192.168.0.180:/mnt/5_hdd/backup/longhorn-pvc?backup=ba target=default rj=backup-daily snap=backup-d-723e6872-0483-4fa0-8482-2f449b0
2026-10-23T02:01:32Z pvc-4fdd6da2-e795-4fa9-9e36-96f212c7018b state=Completed url=nfs://192.168.0.180:/mnt/5_hdd/backup/longhorn-pvc?backup=ba target=default rj=backup-daily snap=backup-d-532d9238-ffdd-43ae-a17e-02e2634
2026-10-23T02:01:33Z pvc-22343573-266d-492e-bd0a-37296217b523 state=Completed url=nfs://192.168.0.180:/mnt/5_hdd/backup/longhorn-pvc?backup=ba target=default rj=backup-daily snap=backup-d-d2227be3-7347-4bdc-a023-9164ce5
2026-10-23T02:01:47Z pvc-0113bbbf-fd5c-441b-9d58-6943ffa8c133 state=Completed url=nfs://192.168.0.180:/mnt/5_hdd/backup/longhorn-pvc?backup=ba target=default rj=backup-daily snap=backup-d-c1f5fc70-576c-4da0-815c-aa93c64
2026-10-23T02:02:03Z pvc-0eae2db7-47f1-477b-b9a9-9968c2d49a6d state=Completed url=nfs://192.168.0.180:/mnt/5_hdd/backup/longhorn-pvc?backup=ba target=default rj=backup-daily snap=backup-d-c564cba5-6d62-49e5-b496-53b964e
2026-10-23T02:02:18Z pvc-11b257b2-8edc-4bf6-b846-00979feb195f state=Completed url=nfs://192.168.0.180:/mnt/5_hdd/backup/longhorn-pvc?backup=ba target=default rj=backup-daily snap=backup-d-54a62590-1809-41dd-9c31-b14134f
2026-10-23T02:02:33Z pvc-17e3b3cc-9c6a-4d70-85cc-c2ae72e0b4ec state=Completed url=nfs://192.168.0.180:/mnt/5_hdd/backup/longhorn-pvc?backup=ba target=default rj=backup-daily snap=backup-d-07db40a9-4578-4056-a6ab-2a8791b
2026-10-23T02:02:49Z pvc-1ae51535-0b2b-4975-bd9f-e651cc7a1edd state=Completed url=nfs://192.168.0.180:/mnt/5_hdd/backup/longhorn-pvc?backup=ba target=default rj=backup-daily snap=backup-d-bdd24928-efdd-4a6e-95c4-abf6858
2026-10-23T02:03:04Z pvc-1c47727a-d5ac-4171-ac36-26c2df3d0d63 state=Completed url=nfs://192.168.0.180:/mnt/5_hdd/backup/longhorn-pvc?backup=ba target=default rj=backup-daily snap=backup-d-66d2dfd3-666d-456d-83a4-8d22f24
2026-10-23T02:03:04Z pvc-202e3bf2-9e61-4c59-ae0c-43fa6a42b403 state=Completed url=nfs://192.168.0.180:/mnt/5_hdd/backup/longhorn-pvc?backup=ba target=default rj=backup-daily snap=backup-d-6fb4220e-6a1c-445e-92cd-a40e4c6
2026-10-23T02:03:24Z pvc-63f3b34f-3ac6-41a5-8790-3a27db0b5a2b state=Completed url=nfs://192.168.0.180:/mnt/5_hdd/backup/longhorn-pvc?backup=ba target=default rj=backup-daily snap=backup-d-4f745b2c-2216-4bff-996e-dd2baa0
2026-10-23T02:03:39Z pvc-5fbd3bbc-fb14-406d-954c-1a232ce313ce state=Completed url=nfs://192.168.0.180:/mnt/5_hdd/backup/longhorn-pvc?backup=ba target=default rj=backup-daily snap=backup-d-cc1aff9c-16cd-495a-b6b2-0e47d26
2026-10-23T02:03:40Z pvc-38e8c624-5717-483b-8da1-613e703e36c8 state=Completed url=nfs://192.168.0.180:/mnt/5_hdd/backup/longhorn-pvc?backup=ba target=default rj=backup-daily snap=backup-d-c0247496-c63a-4579-8b68-f63d205
2026-10-23T02:04:05Z pvc-2382e7bb-9514-409b-a2cc-e97c9725512a state=Completed url=nfs://192.168.0.180:/mnt/5_hdd/backup/longhorn-pvc?backup=ba target=default rj=backup-daily snap=backup-d-7ff78535-6dfa-411c-a1a4-cdbb45a
2026-10-23T02:04:31Z pvc-297c20e6-4ac0-42c4-9c69-24580a7f12ee state=Completed url=nfs://192.168.0.180:/mnt/5_hdd/backup/longhorn-pvc?backup=ba target=default rj=backup-daily snap=backup-d-a4575f47-f837-4a26-bdab-b55c1ab
2026-10-23T02:04:46Z pvc-2e2e8c4c-4ba3-4dcf-9ed4-78acaf7ef92b state=Completed url=nfs://192.168.0.180:/mnt/5_hdd/backup/longhorn-pvc?backup=ba target=default rj=backup-daily snap=backup-d-6bba495f-15a9-420f-9ea8-4bae806
2026-10-23T02:05:07Z pvc-42695a34-d921-4007-b5e5-e40aa728e104 state=Completed url=nfs://192.168.0.180:/mnt/5_hdd/backup/longhorn-pvc?backup=ba target=default rj=backup-daily snap=backup-d-a25c4421-048a-453f-ad6e-34fef26
2026-10-23T02:05:22Z pvc-3b23c214-ea15-40f8-aac5-61f783bf5beb state=Completed url=nfs://192.168.0.180:/mnt/5_hdd/backup/longhorn-pvc?backup=ba target=default rj=backup-daily snap=backup-d-95457e62-4a17-4a59-8d72-8047e00
2026-10-23T02:05:42Z pvc-459e6d2a-92b8-438e-a339-ff7e40089f3d state=Completed url=nfs://192.168.0.180:/mnt/5_hdd/backup/longhorn-pvc?backup=ba target=default rj=backup-daily snap=backup-d-4e5b167a-7310-47cb-a6b1-916168d
2026-10-23T02:06:13Z pvc-6ed74c1a-3f10-4638-9baa-9330cbff980d state=Completed url=nfs://192.168.0.180:/mnt/5_hdd/backup/longhorn-pvc?backup=ba target=default rj=backup-daily snap=backup-d-4cd91122-6d04-4a72-ad69-3b0d0a6
2026-10-23T02:06:28Z pvc-b359d7de-1c7c-4b6a-9f6d-6776c2f876ef state=Completed url=nfs://192.168.0.180:/mnt/5_hdd/backup/longhorn-pvc?backup=ba target=default rj=backup-daily snap=backup-d-8b778723-11a9-46d4-aa2b-f025a71
2026-10-23T02:06:44Z pvc-79478678-07e4-4140-aef1-771ff763ab3f state=Completed url=nfs://192.168.0.180:/mnt/5_hdd/backup/longhorn-pvc?backup=ba target=default rj=backup-daily snap=backup-d-0bd019c6-6214-4a71-9d9f-d6907b8
2026-10-23T02:06:59Z pvc-7d6dec2c-0cda-43c7-ad1d-44ffebcb8cb6 state=Completed url=nfs://192.168.0.180:/mnt/5_hdd/backup/longhorn-pvc?backup=ba target=default rj=backup-daily snap=backup-d-1585fad0-6ac0-44c7-80b2-1ec603b
2026-10-23T02:07:00Z pvc-8ed5eea5-67d4-46fc-9806-6b8fdd61e42e state=Completed url=nfs://192.168.0.180:/mnt/5_hdd/backup/longhorn-pvc?backup=ba target=default rj=backup-daily snap=backup-d-d2ce1852-9284-491e-b424-f23bfba
2026-10-23T02:07:20Z pvc-9ca6a486-40bb-46ac-ac48-bd49d4399f4b state=Completed url=nfs://192.168.0.180:/mnt/5_hdd/backup/longhorn-pvc?backup=ba target=default rj=backup-daily snap=backup-d-ad0e30e9-aff2-427c-b040-aa41144
2026-10-23T02:07:29Z pvc-a9dd6c7c-19eb-4a0a-935d-d2c30545c378 state=Completed url=nfs://192.168.0.180:/mnt/5_hdd/backup/longhorn-pvc?backup=ba target=default rj=backup-daily snap=backup-d-a3eb95b8-4c3c-40cd-a797-0b58af2
2026-10-23T02:07:54Z pvc-b0e94be5-7cd8-4a4c-9295-901614e9eeb7 state=Completed url=nfs://192.168.0.180:/mnt/5_hdd/backup/longhorn-pvc?backup=ba target=default rj=backup-daily snap=backup-d-8f350533-d46e-4bc1-afe4-698ac27
2026-10-23T02:08:25Z pvc-b10da48e-6fcc-42ef-8414-d5d617028d68 state=Completed url=nfs://192.168.0.180:/mnt/5_hdd/backup/longhorn-pvc?backup=ba target=default rj=backup-daily snap=backup-d-f6ef4e55-80ab-4e52-8c2c-1df09e7
2026-10-23T02:08:45Z pvc-8401df55-4668-40e3-97d2-d53e2c1090f1 state=Completed url=nfs://192.168.0.180:/mnt/5_hdd/backup/longhorn-pvc?backup=ba target=default rj=backup-daily snap=backup-d-e2b7b133-2dd3-4b22-bec1-bab0622
2026-10-23T02:08:56Z pvc-7fc61dcd-52f0-45b4-97f1-9c82b28ab714 state=Completed url=nfs://192.168.0.180:/mnt/5_hdd/backup/longhorn-pvc?backup=ba target=default rj=backup-daily snap=backup-d-887bfdd7-1804-4c5a-83be-80c5253
2026-10-23T02:09:11Z pvc-e5b8f824-7720-454c-b546-a098608df24a state=Completed url=nfs://192.168.0.180:/mnt/5_hdd/backup/longhorn-pvc?backup=ba target=default rj=backup-daily snap=backup-d-d7e129b7-5d88-4bc9-bfc0-7564ab7
2026-10-23T02:09:26Z pvc-e57c220f-bc92-4815-89c9-0dee35eab3c3 state=Completed url=nfs://192.168.0.180:/mnt/5_hdd/backup/longhorn-pvc?backup=ba target=default rj=backup-daily snap=backup-d-ae2f297d-5714-49a9-a712-1ce8ac6
2026-10-23T02:09:41Z pvc-c4dfbc43-2c35-4ef0-9cfe-39b3dc885dae state=Completed url=nfs://192.168.0.180:/mnt/5_hdd/backup/longhorn-pvc?backup=ba target=default rj=backup-daily snap=backup-d-9206b338-5612-421b-83a5-1c13499
2026-10-23T02:09:42Z pvc-d9f09398-17cf-44b0-b3a2-9475bc773fec state=Completed url=nfs://192.168.0.180:/mnt/5_hdd/backup/longhorn-pvc?backup=ba target=default rj=backup-daily snap=backup-d-ce08dc5f-8f83-4644-8ac0-880ee0e
2026-10-23T02:09:57Z pvc-85be87dc-3351-4459-9f82-55f8cc598a2f state=Completed url=nfs://192.168.0.180:/mnt/5_hdd/backup/longhorn-pvc?backup=ba target=default rj=backup-daily snap=backup-d-7349021f-8111-4d08-aa74-3ec18e1
2026-10-23T02:10:17Z pvc-c911715e-56ee-4d97-836e-89efc448ad9d state=Completed url=nfs://192.168.0.180:/mnt/5_hdd/backup/longhorn-pvc?backup=ba target=default rj=backup-daily snap=backup-d-f18a8f97-7fd3-4bb0-ba92-f7b5704
2026-10-23T02:10:37Z pvc-ea977627-fb0a-4dee-8678-9ceceea448da state=Completed url=nfs://192.168.0.180:/mnt/5_hdd/backup/longhorn-pvc?backup=ba target=default rj=backup-daily snap=backup-d-1b632b7b-e42c-4516-bffd-bdc6e7e
2026-10-23T02:10:38Z pvc-88b4d7b4-cb5d-48e0-871e-9e150872d0bd state=Completed url=nfs://192.168.0.180:/mnt/5_hdd/backup/longhorn-pvc?backup=ba target=default rj=backup-daily snap=backup-d-4deb82a5-7b2f-42f4-a206-9778ee9
2026-10-23T02:10:53Z pvc-beb0ad8a-755a-4152-a0af-f7367b32b19c state=Completed url=nfs://192.168.0.180:/mnt/5_hdd/backup/longhorn-pvc?backup=ba target=default rj=backup-daily snap=backup-d-2fce6324-4e8c-4cfd-9c00-f500bbd
2026-10-23T02:11:09Z pvc-c8c0d0f1-c9ea-4ed3-9e22-1e254a026c49 state=Completed url=nfs://192.168.0.180:/mnt/5_hdd/backup/longhorn-pvc?backup=ba target=default rj=backup-daily snap=backup-d-5524b832-3049-48f3-b6c9-ec8aefd
2026-10-23T02:11:27Z pvc-be9d7813-1881-462e-8951-1bd1315f7dc5 state=Completed url=nfs://192.168.0.180:/mnt/5_hdd/backup/longhorn-pvc?backup=ba target=default rj=backup-daily snap=backup-d-29a6b089-b40d-473c-bcbb-4f565c7
2026-10-23T02:11:42Z pvc-fc3d2f7f-6569-473c-acb4-002c613e5f18 state=Completed url=nfs://192.168.0.180:/mnt/5_hdd/backup/longhorn-pvc?backup=ba target=default rj=backup-daily snap=backup-d-6ad56202-8675-4dd3-9476-447b2a3
2026-10-23T02:12:03Z pvc-e2151b14-2b24-4128-993a-c392c8d9706a state=Completed url=nfs://192.168.0.180:/mnt/5_hdd/backup/longhorn-pvc?backup=ba target=default rj=backup-daily snap=backup-d-d10cb97e-7e9d-4904-970e-fd4607a
2026-10-23T02:12:23Z pvc-d2ea5b66-d251-4467-9829-14654fab7a2f state=Completed url=nfs://192.168.0.180:/mnt/5_hdd/backup/longhorn-pvc?backup=ba target=default rj=backup-daily snap=backup-d-289d6573-4b0c-4ef5-85cd-91431bf
2026-10-23T02:12:29Z pvc-7eb1f195-6a35-46c3-bbb1-5bab48209624 state=Completed url=nfs://192.168.0.180:/mnt/5_hdd/backup/longhorn-pvc?backup=ba target=default rj=backup-daily snap=backup-d-10b20200-bcf7-4388-b919-c1b66a5
2026-10-23T02:12:39Z pvc-c6b9ab63-24b8-46f2-b52a-06da86393de8 state=Completed url=nfs://192.168.0.180:/mnt/5_hdd/backup/longhorn-pvc?backup=ba target=default rj=backup-daily snap=backup-d-945b6c37-6893-49a5-a15e-41a9212
2026-10-23T02:12:54Z pvc-cbfd55b0-4f44-487d-90fd-9c80b916ced7 state=Completed url=nfs://192.168.0.180:/mnt/5_hdd/backup/longhorn-pvc?backup=ba target=default rj=backup-daily snap=backup-d-949f00a2-f4e3-475a-808e-62dc20d
2026-10-23T02:13:14Z pvc-8931072a-e34e-4333-9ab5-9629b6078505 state=Completed url=nfs://192.168.0.180:/mnt/5_hdd/backup/longhorn-pvc?backup=ba target=default rj=backup-daily snap=backup-d-25fdc074-8997-4edf-a9c6-e884269
2026-10-23T02:13:14Z pvc-e3b26fdc-fd52-4fdf-9fa2-1d1ecfd029e4 state=Completed url=nfs://192.168.0.180:/mnt/5_hdd/backup/longhorn-pvc?backup=ba target=default rj=backup-daily snap=backup-d-f04f9565-79a1-4d11-92cf-03c0ab1
== snapshots created in window (name, volume, createdBy labels)
2026-10-18T03:00:01Z pvc-1ae51535-0b2b-4975-bd9f-e651cc7a1edd backup-w-9e561c5f-39bf-4de0-b86d-4154538ced31 usercreated=true labels={"RecurringJob":"backup-weekly"}
2026-10-18T03:00:01Z pvc-486c9809-4672-4b56-b70e-0bf01d0c3628 backup-w-c9cb53aa-4359-4309-9976-530a6faf3310 usercreated=true labels={"RecurringJob":"backup-weekly"}
2026-10-18T03:00:16Z pvc-4e3fd336-9f09-4251-bd90-cdc259ef739e backup-w-ce5a0dec-ec88-4da1-b14f-7acf37cda9e2 usercreated=true labels={"RecurringJob":"backup-weekly"}
2026-10-18T03:00:16Z pvc-71cbab32-86f9-40a5-8f3b-220ad626c492 backup-w-8822d0fe-6849-4df1-bed1-7ea948861d7b usercreated=true labels={"RecurringJob":"backup-weekly"}
2026-10-18T03:00:37Z pvc-4e4aba1e-b414-4016-8895-ecdf0fb04a6b backup-w-f36ce009-f2ec-4da5-bef2-e72746c50eae usercreated=true labels={"RecurringJob":"backup-weekly"}
2026-10-18T03:01:12Z pvc-4fdd6da2-e795-4fa9-9e36-96f212c7018b backup-w-152bc04c-cfb0-494e-a020-b8edceb99208 usercreated=true labels={"RecurringJob":"backup-weekly"}
2026-10-18T03:01:17Z pvc-11b257b2-8edc-4bf6-b846-00979feb195f backup-w-7be4c31e-99c9-4858-abc0-8b2b102fa6eb usercreated=true labels={"RecurringJob":"backup-weekly"}
2026-10-18T03:01:28Z pvc-297c20e6-4ac0-42c4-9c69-24580a7f12ee backup-w-492c52b6-af58-4b56-b031-e1a2f610e656 usercreated=true labels={"RecurringJob":"backup-weekly"}
2026-10-18T03:01:32Z pvc-1c47727a-d5ac-4171-ac36-26c2df3d0d63 backup-w-500c8206-b274-4c95-adc1-7dbf77b41806 usercreated=true labels={"RecurringJob":"backup-weekly"}
2026-10-18T03:01:43Z pvc-202e3bf2-9e61-4c59-ae0c-43fa6a42b403 backup-w-477bb594-f177-4d5b-be17-2db7fc908486 usercreated=true labels={"RecurringJob":"backup-weekly"}
2026-10-18T03:01:52Z pvc-42695a34-d921-4007-b5e5-e40aa728e104 backup-w-5a54721b-bdfc-48ae-8f5f-8612bff3525d usercreated=true labels={"RecurringJob":"backup-weekly"}
2026-10-18T03:01:53Z pvc-22343573-266d-492e-bd0a-37296217b523 backup-w-dea6667f-c93f-4bb7-ad59-b8b3bc772476 usercreated=true labels={"RecurringJob":"backup-weekly"}
2026-10-18T03:02:08Z pvc-459e6d2a-92b8-438e-a339-ff7e40089f3d backup-w-069a5b3f-1600-4147-9566-29f351d2bb39 usercreated=true labels={"RecurringJob":"backup-weekly"}
2026-10-18T03:02:33Z pvc-2e2e8c4c-4ba3-4dcf-9ed4-78acaf7ef92b backup-w-a493d271-9d5e-41d5-a93c-7954e173eb0f usercreated=true labels={"RecurringJob":"backup-weekly"}
2026-10-18T03:02:44Z pvc-38e8c624-5717-483b-8da1-613e703e36c8 backup-w-db1904d5-7bfe-45f4-81c6-e17010691225 usercreated=true labels={"RecurringJob":"backup-weekly"}
2026-10-18T03:02:44Z pvc-6ed74c1a-3f10-4638-9baa-9330cbff980d backup-w-34fa0b60-8201-4c21-aad1-f73656d1fc4c usercreated=true labels={"RecurringJob":"backup-weekly"}
2026-10-18T03:02:59Z pvc-b359d7de-1c7c-4b6a-9f6d-6776c2f876ef backup-w-e06ba46d-8847-4f8c-9a9c-ad67982d4f5c usercreated=true labels={"RecurringJob":"backup-weekly"}
2026-10-18T03:03:04Z pvc-79478678-07e4-4140-aef1-771ff763ab3f backup-w-cac58903-1e3d-4c60-95ed-72e4d7ac4662 usercreated=true labels={"RecurringJob":"backup-weekly"}
2026-10-18T03:03:14Z pvc-7d6dec2c-0cda-43c7-ad1d-44ffebcb8cb6 backup-w-80d619fb-2f32-4af8-aa0c-7d6c034896a7 usercreated=true labels={"RecurringJob":"backup-weekly"}
2026-10-18T03:03:19Z pvc-cbfd55b0-4f44-487d-90fd-9c80b916ced7 backup-w-34af7ebb-cca6-47a6-a668-541a5f4124a3 usercreated=true labels={"RecurringJob":"backup-weekly"}
2026-10-18T03:03:35Z pvc-c6b9ab63-24b8-46f2-b52a-06da86393de8 backup-w-ec972d0f-02f6-47de-8252-f3471a63d29a usercreated=true labels={"RecurringJob":"backup-weekly"}
2026-10-18T03:03:40Z pvc-c8c0d0f1-c9ea-4ed3-9e22-1e254a026c49 backup-w-336bb191-b457-432c-8b3b-a49b8fbcb844 usercreated=true labels={"RecurringJob":"backup-weekly"}
2026-10-18T03:03:50Z pvc-c911715e-56ee-4d97-836e-89efc448ad9d backup-w-132be759-46d9-48f4-9b7f-731dbf00aa5a usercreated=true labels={"RecurringJob":"backup-weekly"}
2026-10-18T03:04:06Z pvc-d9f09398-17cf-44b0-b3a2-9475bc773fec backup-w-81d52611-6488-4b98-aced-cb0dd836c4c0 usercreated=true labels={"RecurringJob":"backup-weekly"}
2026-10-18T03:04:25Z pvc-d2ea5b66-d251-4467-9829-14654fab7a2f backup-w-f12dd015-e375-4aeb-903d-a6d24adb621a usercreated=true labels={"RecurringJob":"backup-weekly"}
2026-10-18T03:04:26Z pvc-e2151b14-2b24-4128-993a-c392c8d9706a backup-w-b5f21af2-a32d-4a2d-954d-4853baf4520b usercreated=true labels={"RecurringJob":"backup-weekly"}
2026-10-18T03:04:40Z pvc-8401df55-4668-40e3-97d2-d53e2c1090f1 backup-w-501e9c93-1004-4c30-acea-26b58f69f598 usercreated=true labels={"RecurringJob":"backup-weekly"}
2026-10-18T03:04:41Z pvc-7fc61dcd-52f0-45b4-97f1-9c82b28ab714 backup-w-9929ed08-8a85-4c29-83a9-c0e3bfb23b33 usercreated=true labels={"RecurringJob":"backup-weekly"}
2026-10-18T03:04:56Z pvc-a9dd6c7c-19eb-4a0a-935d-d2c30545c378 backup-w-44cb1d12-6aeb-4ced-9977-029cf9296c86 usercreated=true labels={"RecurringJob":"backup-weekly"}
2026-10-18T03:05:02Z pvc-e3b26fdc-fd52-4fdf-9fa2-1d1ecfd029e4 backup-w-5c387443-5da4-4918-b5b7-c23f0873d081 usercreated=true labels={"RecurringJob":"backup-weekly"}
2026-10-18T03:05:11Z pvc-9ca6a486-40bb-46ac-ac48-bd49d4399f4b backup-w-908f1c40-5b75-4a93-bd0b-c5ec6c3b5c5a usercreated=true labels={"RecurringJob":"backup-weekly"}
2026-10-18T03:05:17Z pvc-85be87dc-3351-4459-9f82-55f8cc598a2f backup-w-a26221ac-ad81-45a1-93cd-c730ebf48fa9 usercreated=true labels={"RecurringJob":"backup-weekly"}
2026-10-18T03:05:32Z pvc-e5b8f824-7720-454c-b546-a098608df24a backup-w-8af31417-1f16-4ed5-9bb4-1e3ec016f766 usercreated=true labels={"RecurringJob":"backup-weekly"}
2026-10-18T03:05:52Z pvc-e57c220f-bc92-4815-89c9-0dee35eab3c3 backup-w-24190c0e-85a4-480b-9451-91a931351415 usercreated=true labels={"RecurringJob":"backup-weekly"}
2026-10-18T03:05:53Z pvc-8ed5eea5-67d4-46fc-9806-6b8fdd61e42e backup-w-ce360270-a851-4ff8-a481-ad9933848b48 usercreated=true labels={"RecurringJob":"backup-weekly"}
2026-10-18T03:06:07Z pvc-88b4d7b4-cb5d-48e0-871e-9e150872d0bd backup-w-768fe287-8ac0-43ce-b7c4-017f340a6276 usercreated=true labels={"RecurringJob":"backup-weekly"}
2026-10-18T03:06:08Z pvc-be9d7813-1881-462e-8951-1bd1315f7dc5 backup-w-55284120-f572-42de-a65d-f32ce33b8d6b usercreated=true labels={"RecurringJob":"backup-weekly"}
2026-10-18T03:06:22Z pvc-ea977627-fb0a-4dee-8678-9ceceea448da backup-w-89e8e1d8-e924-4911-80da-d88420c47ab6 usercreated=true labels={"RecurringJob":"backup-weekly"}
2026-10-18T03:06:24Z pvc-b10da48e-6fcc-42ef-8414-d5d617028d68 backup-w-6ec192d8-7928-4fed-bba5-8d3db7f4ccaf usercreated=true labels={"RecurringJob":"backup-weekly"}
2026-10-18T03:06:39Z pvc-beb0ad8a-755a-4152-a0af-f7367b32b19c backup-w-5c4c2d48-70be-402d-8ef6-0665f01012cf usercreated=true labels={"RecurringJob":"backup-weekly"}
2026-10-18T03:06:43Z pvc-b0e94be5-7cd8-4a4c-9295-901614e9eeb7 backup-w-073e62b6-6177-4d87-a7e2-28b55567d729 usercreated=true labels={"RecurringJob":"backup-weekly"}
2026-10-18T03:06:54Z pvc-8931072a-e34e-4333-9ab5-9629b6078505 backup-w-9689a569-2397-4947-b1b5-94042bc973f4 usercreated=true labels={"RecurringJob":"backup-weekly"}
2026-10-18T03:07:03Z pvc-c4dfbc43-2c35-4ef0-9cfe-39b3dc885dae backup-w-47b6014f-5f34-4484-9d80-10bab2b2633f usercreated=true labels={"RecurringJob":"backup-weekly"}
2026-10-18T03:07:25Z pvc-7eb1f195-6a35-46c3-bbb1-5bab48209624 backup-w-d0f4fe40-8c48-4990-969a-d421e45e734c usercreated=true labels={"RecurringJob":"backup-weekly"}
2026-10-18T03:07:29Z pvc-17e3b3cc-9c6a-4d70-85cc-c2ae72e0b4ec backup-w-cf531882-6842-4629-8470-97a63d9f1263 usercreated=true labels={"RecurringJob":"backup-weekly"}
2026-10-18T03:07:40Z pvc-5fbd3bbc-fb14-406d-954c-1a232ce313ce backup-w-94e25d95-26b5-441f-b57c-6c38dcfd1bd5 usercreated=true labels={"RecurringJob":"backup-weekly"}
2026-10-18T03:07:44Z pvc-0113bbbf-fd5c-441b-9d58-6943ffa8c133 backup-w-7c27529f-7e1c-4515-b4e3-5a92eef9904a usercreated=true labels={"RecurringJob":"backup-weekly"}
2026-10-18T03:07:59Z pvc-63f3b34f-3ac6-41a5-8790-3a27db0b5a2b backup-w-9e4f3b48-85bb-4b17-a504-3774ea4e6e14 usercreated=true labels={"RecurringJob":"backup-weekly"}
2026-10-18T03:08:01Z pvc-2382e7bb-9514-409b-a2cc-e97c9725512a backup-w-3c194f84-d8a0-4ecb-baf0-9c4a16318987 usercreated=true labels={"RecurringJob":"backup-weekly"}
2026-10-18T03:08:15Z pvc-3b23c214-ea15-40f8-aac5-61f783bf5beb backup-w-849c9f2d-fbab-4084-998b-2dcbc5b8e3af usercreated=true labels={"RecurringJob":"backup-weekly"}
2026-10-18T03:08:16Z pvc-5acabaa7-6017-4793-b45e-f1f4fd80ab97 backup-w-6a5d4be2-a059-40b4-bee8-abf12199ae05 usercreated=true labels={"RecurringJob":"backup-weekly"}
2026-10-18T03:08:30Z pvc-fc3d2f7f-6569-473c-acb4-002c613e5f18 backup-w-aec12d6b-becd-4ca1-9590-a60f5f4a4f45 usercreated=true labels={"RecurringJob":"backup-weekly"}
2026-10-18T03:08:41Z pvc-0eae2db7-47f1-477b-b9a9-9968c2d49a6d backup-w-b3049de0-fe68-472b-8964-f0140a6b2c54 usercreated=true labels={"RecurringJob":"backup-weekly"}
2026-10-23T02:00:01Z pvc-486c9809-4672-4b56-b70e-0bf01d0c3628 backup-d-d8d68af0-acc6-4a07-bd57-1eb283dc8588 usercreated=true labels={"RecurringJob":"backup-daily"}
2026-10-23T02:00:01Z pvc-71cbab32-86f9-40a5-8f3b-220ad626c492 backup-d-bcf88ff5-ab92-4511-bcd4-a4686c8941f2 usercreated=true labels={"RecurringJob":"backup-daily"}
2026-10-23T02:00:17Z pvc-5acabaa7-6017-4793-b45e-f1f4fd80ab97 backup-d-6afe7cd9-fd63-48ff-96b7-b8bd7ba03aa0 usercreated=true labels={"RecurringJob":"backup-daily"}
2026-10-23T02:00:37Z pvc-4e3fd336-9f09-4251-bd90-cdc259ef739e backup-d-ab86b601-8c71-4e9e-ab5f-6211e6bccc2f usercreated=true labels={"RecurringJob":"backup-daily"}
2026-10-23T02:01:03Z pvc-4e4aba1e-b414-4016-8895-ecdf0fb04a6b backup-d-723e6872-0483-4fa0-8482-2f449b038fbd usercreated=true labels={"RecurringJob":"backup-daily"}
2026-10-23T02:01:27Z pvc-4fdd6da2-e795-4fa9-9e36-96f212c7018b backup-d-532d9238-ffdd-43ae-a17e-02e263490801 usercreated=true labels={"RecurringJob":"backup-daily"}
2026-10-23T02:01:28Z pvc-22343573-266d-492e-bd0a-37296217b523 backup-d-d2227be3-7347-4bdc-a023-9164ce5a0b0b usercreated=true labels={"RecurringJob":"backup-daily"}
2026-10-23T02:01:42Z pvc-0113bbbf-fd5c-441b-9d58-6943ffa8c133 backup-d-c1f5fc70-576c-4da0-815c-aa93c6462d62 usercreated=true labels={"RecurringJob":"backup-daily"}
2026-10-23T02:01:58Z pvc-0eae2db7-47f1-477b-b9a9-9968c2d49a6d backup-d-c564cba5-6d62-49e5-b496-53b964ed07eb usercreated=true labels={"RecurringJob":"backup-daily"}
2026-10-23T02:02:13Z pvc-11b257b2-8edc-4bf6-b846-00979feb195f backup-d-54a62590-1809-41dd-9c31-b14134f340df usercreated=true labels={"RecurringJob":"backup-daily"}
2026-10-23T02:02:28Z pvc-17e3b3cc-9c6a-4d70-85cc-c2ae72e0b4ec backup-d-07db40a9-4578-4056-a6ab-2a8791bb14d1 usercreated=true labels={"RecurringJob":"backup-daily"}
2026-10-23T02:02:39Z pvc-1ae51535-0b2b-4975-bd9f-e651cc7a1edd backup-d-bdd24928-efdd-4a6e-95c4-abf68582861a usercreated=true labels={"RecurringJob":"backup-daily"}
2026-10-23T02:02:58Z pvc-1c47727a-d5ac-4171-ac36-26c2df3d0d63 backup-d-66d2dfd3-666d-456d-83a4-8d22f24ee2c9 usercreated=true labels={"RecurringJob":"backup-daily"}
2026-10-23T02:02:59Z pvc-202e3bf2-9e61-4c59-ae0c-43fa6a42b403 backup-d-6fb4220e-6a1c-445e-92cd-a40e4c66351c usercreated=true labels={"RecurringJob":"backup-daily"}
2026-10-23T02:03:19Z pvc-63f3b34f-3ac6-41a5-8790-3a27db0b5a2b backup-d-4f745b2c-2216-4bff-996e-dd2baa03838e usercreated=true labels={"RecurringJob":"backup-daily"}
2026-10-23T02:03:34Z pvc-5fbd3bbc-fb14-406d-954c-1a232ce313ce backup-d-cc1aff9c-16cd-495a-b6b2-0e47d2674a7b usercreated=true labels={"RecurringJob":"backup-daily"}
2026-10-23T02:03:35Z pvc-38e8c624-5717-483b-8da1-613e703e36c8 backup-d-c0247496-c63a-4579-8b68-f63d2051b3f4 usercreated=true labels={"RecurringJob":"backup-daily"}
2026-10-23T02:04:00Z pvc-2382e7bb-9514-409b-a2cc-e97c9725512a backup-d-7ff78535-6dfa-411c-a1a4-cdbb45a179d3 usercreated=true labels={"RecurringJob":"backup-daily"}
2026-10-23T02:04:21Z pvc-297c20e6-4ac0-42c4-9c69-24580a7f12ee backup-d-a4575f47-f837-4a26-bdab-b55c1abba818 usercreated=true labels={"RecurringJob":"backup-daily"}
2026-10-23T02:04:41Z pvc-2e2e8c4c-4ba3-4dcf-9ed4-78acaf7ef92b backup-d-6bba495f-15a9-420f-9ea8-4bae8064b71e usercreated=true labels={"RecurringJob":"backup-daily"}
2026-10-23T02:04:57Z pvc-42695a34-d921-4007-b5e5-e40aa728e104 backup-d-a25c4421-048a-453f-ad6e-34fef264c2b7 usercreated=true labels={"RecurringJob":"backup-daily"}
2026-10-23T02:05:17Z pvc-3b23c214-ea15-40f8-aac5-61f783bf5beb backup-d-95457e62-4a17-4a59-8d72-8047e00b8cc0 usercreated=true labels={"RecurringJob":"backup-daily"}
2026-10-23T02:05:32Z pvc-459e6d2a-92b8-438e-a339-ff7e40089f3d backup-d-4e5b167a-7310-47cb-a6b1-916168db3f2b usercreated=true labels={"RecurringJob":"backup-daily"}
2026-10-23T02:06:08Z pvc-6ed74c1a-3f10-4638-9baa-9330cbff980d backup-d-4cd91122-6d04-4a72-ad69-3b0d0a625622 usercreated=true labels={"RecurringJob":"backup-daily"}
2026-10-23T02:06:23Z pvc-b359d7de-1c7c-4b6a-9f6d-6776c2f876ef backup-d-8b778723-11a9-46d4-aa2b-f025a714fd31 usercreated=true labels={"RecurringJob":"backup-daily"}
2026-10-23T02:06:39Z pvc-79478678-07e4-4140-aef1-771ff763ab3f backup-d-0bd019c6-6214-4a71-9d9f-d6907b8703ce usercreated=true labels={"RecurringJob":"backup-daily"}
2026-10-23T02:06:53Z pvc-7d6dec2c-0cda-43c7-ad1d-44ffebcb8cb6 backup-d-1585fad0-6ac0-44c7-80b2-1ec603b5df27 usercreated=true labels={"RecurringJob":"backup-daily"}
2026-10-23T02:06:55Z pvc-8ed5eea5-67d4-46fc-9806-6b8fdd61e42e backup-d-d2ce1852-9284-491e-b424-f23bfba48b39 usercreated=true labels={"RecurringJob":"backup-daily"}
2026-10-23T02:07:10Z pvc-9ca6a486-40bb-46ac-ac48-bd49d4399f4b backup-d-ad0e30e9-aff2-427c-b040-aa41144177ea usercreated=true labels={"RecurringJob":"backup-daily"}
2026-10-23T02:07:24Z pvc-a9dd6c7c-19eb-4a0a-935d-d2c30545c378 backup-d-a3eb95b8-4c3c-40cd-a797-0b58af2c8bbb usercreated=true labels={"RecurringJob":"backup-daily"}
2026-10-23T02:07:44Z pvc-b0e94be5-7cd8-4a4c-9295-901614e9eeb7 backup-d-8f350533-d46e-4bc1-afe4-698ac2730f06 usercreated=true labels={"RecurringJob":"backup-daily"}
2026-10-23T02:08:20Z pvc-b10da48e-6fcc-42ef-8414-d5d617028d68 backup-d-f6ef4e55-80ab-4e52-8c2c-1df09e712ffe usercreated=true labels={"RecurringJob":"backup-daily"}
2026-10-23T02:08:40Z pvc-8401df55-4668-40e3-97d2-d53e2c1090f1 backup-d-e2b7b133-2dd3-4b22-bec1-bab062295efa usercreated=true labels={"RecurringJob":"backup-daily"}
2026-10-23T02:08:46Z pvc-7fc61dcd-52f0-45b4-97f1-9c82b28ab714 backup-d-887bfdd7-1804-4c5a-83be-80c52535d5e2 usercreated=true labels={"RecurringJob":"backup-daily"}
2026-10-23T02:09:06Z pvc-e5b8f824-7720-454c-b546-a098608df24a backup-d-d7e129b7-5d88-4bc9-bfc0-7564ab7a8d11 usercreated=true labels={"RecurringJob":"backup-daily"}
2026-10-23T02:09:16Z pvc-e57c220f-bc92-4815-89c9-0dee35eab3c3 backup-d-ae2f297d-5714-49a9-a712-1ce8ac64913a usercreated=true labels={"RecurringJob":"backup-daily"}
2026-10-23T02:09:31Z pvc-d9f09398-17cf-44b0-b3a2-9475bc773fec backup-d-ce08dc5f-8f83-4644-8ac0-880ee0e7c662 usercreated=true labels={"RecurringJob":"backup-daily"}
2026-10-23T02:09:36Z pvc-c4dfbc43-2c35-4ef0-9cfe-39b3dc885dae backup-d-9206b338-5612-421b-83a5-1c13499d9263 usercreated=true labels={"RecurringJob":"backup-daily"}
2026-10-23T02:09:52Z pvc-85be87dc-3351-4459-9f82-55f8cc598a2f backup-d-7349021f-8111-4d08-aa74-3ec18e12e05a usercreated=true labels={"RecurringJob":"backup-daily"}
2026-10-23T02:10:07Z pvc-c911715e-56ee-4d97-836e-89efc448ad9d backup-d-f18a8f97-7fd3-4bb0-ba92-f7b5704c0b9a usercreated=true labels={"RecurringJob":"backup-daily"}
2026-10-23T02:10:26Z pvc-ea977627-fb0a-4dee-8678-9ceceea448da backup-d-1b632b7b-e42c-4516-bffd-bdc6e7e2ba57 usercreated=true labels={"RecurringJob":"backup-daily"}
2026-10-23T02:10:28Z pvc-88b4d7b4-cb5d-48e0-871e-9e150872d0bd backup-d-4deb82a5-7b2f-42f4-a206-9778ee95aeab usercreated=true labels={"RecurringJob":"backup-daily"}
2026-10-23T02:10:48Z pvc-beb0ad8a-755a-4152-a0af-f7367b32b19c backup-d-2fce6324-4e8c-4cfd-9c00-f500bbdc44c8 usercreated=true labels={"RecurringJob":"backup-daily"}
2026-10-23T02:11:03Z pvc-c8c0d0f1-c9ea-4ed3-9e22-1e254a026c49 backup-d-5524b832-3049-48f3-b6c9-ec8aefd868b4 usercreated=true labels={"RecurringJob":"backup-daily"}
2026-10-23T02:11:22Z pvc-be9d7813-1881-462e-8951-1bd1315f7dc5 backup-d-29a6b089-b40d-473c-bcbb-4f565c70b062 usercreated=true labels={"RecurringJob":"backup-daily"}
2026-10-23T02:11:37Z pvc-fc3d2f7f-6569-473c-acb4-002c613e5f18 backup-d-6ad56202-8675-4dd3-9476-447b2a36d07a usercreated=true labels={"RecurringJob":"backup-daily"}
2026-10-23T02:11:53Z pvc-e2151b14-2b24-4128-993a-c392c8d9706a backup-d-d10cb97e-7e9d-4904-970e-fd4607adf4f4 usercreated=true labels={"RecurringJob":"backup-daily"}
2026-10-23T02:12:13Z pvc-d2ea5b66-d251-4467-9829-14654fab7a2f backup-d-289d6573-4b0c-4ef5-85cd-91431bfe3ac4 usercreated=true labels={"RecurringJob":"backup-daily"}
2026-10-23T02:12:24Z pvc-7eb1f195-6a35-46c3-bbb1-5bab48209624 backup-d-10b20200-bcf7-4388-b919-c1b66a5ae153 usercreated=true labels={"RecurringJob":"backup-daily"}
2026-10-23T02:12:33Z pvc-c6b9ab63-24b8-46f2-b52a-06da86393de8 backup-d-945b6c37-6893-49a5-a15e-41a9212638e2 usercreated=true labels={"RecurringJob":"backup-daily"}
2026-10-23T02:12:49Z pvc-cbfd55b0-4f44-487d-90fd-9c80b916ced7 backup-d-949f00a2-f4e3-475a-808e-62dc20d59bf5 usercreated=true labels={"RecurringJob":"backup-daily"}
2026-10-23T02:13:09Z pvc-8931072a-e34e-4333-9ab5-9629b6078505 backup-d-25fdc074-8997-4edf-a9c6-e88426915a57 usercreated=true labels={"RecurringJob":"backup-daily"}
2026-10-23T02:13:09Z pvc-e3b26fdc-fd52-4fdf-9fa2-1d1ecfd029e4 backup-d-f04f9565-79a1-4d11-92cf-03c0ab1fdcc2 usercreated=true labels={"RecurringJob":"backup-daily"}
== volumeattachment tickets (all), with ticket ids and types
pvc-1d4ec717-7ee5-40a0-b093-3a62fd2a81a4 ticket=share-manager-controller-pvc-1d4ec717-7ee5-40a0-b093-3a62fd2a81a4 type=share-manager-controller node=dooplex
pvc-8ed5eea5-67d4-46fc-9806-6b8fdd61e42e ticket=share-manager-controller-pvc-8ed5eea5-67d4-46fc-9806-6b8fdd61e42e type=share-manager-controller node=dooplex
== recurring jobs
2026-01-05T18:23:17Z backup-daily 0 4 * * * backup
2026-01-05T18:23:17Z backup-weekly 0 5 * * 0 backup
== backuptargets
2025-11-29T10:22:32Z default nfs://192.168.0.180:/mnt/5_hdd/backup/longhorn-pvc?nfsOptions=soft,timeo=330,retrans=3
@@ -0,0 +1,45 @@
# P3.5 container network bytes (cAdvisor), window 2026-10-17T04:00Z..10-23T08:05Z, 2026-10-23T15:30:10Z
== transmit bytes per day, Plex pod (GiB)
2026-10-11T00:00:00Z 0.04
2026-10-12T00:00:00Z 0.04
2026-10-13T00:00:00Z 0.04
2026-10-14T00:00:00Z 0.04
2026-10-15T00:00:00Z 0.26
2026-10-16T00:00:00Z 0.08
2026-10-17T00:00:00Z 2.25
2026-10-18T00:00:00Z 142.97
2026-10-19T00:00:00Z 202.37
2026-10-20T00:00:00Z 528.45
2026-10-21T00:00:00Z 441.46
2026-10-22T00:00:00Z 206.1
2026-10-23T00:00:00Z 0.09
== receive bytes per day, Plex pod (GiB)
2026-10-11T00:00:00Z 0.01
2026-10-12T00:00:00Z 0.01
2026-10-13T00:00:00Z 0.01
2026-10-14T00:00:00Z 0.01
2026-10-15T00:00:00Z 0.03
2026-10-16T00:00:00Z 0.02
2026-10-17T00:00:00Z 0.03
2026-10-18T00:00:00Z 2.25
2026-10-19T00:00:00Z 7.87
2026-10-20T00:00:00Z 1.03
2026-10-21T00:00:00Z 0.04
2026-10-22T00:00:00Z 1.05
2026-10-23T00:00:00Z 0.02
== labels available on the metric (does any give the PEER?)
["__name__","beta_kubernetes_io_arch","beta_kubernetes_io_instance_type","beta_kubernetes_io_os","id","image","instance","interface","job","kubernetes_io_arch","kubernetes_io_hostname","kubernetes_io_os","name","namespace","node_kubernetes_io_instance_type","node_role_kubernetes_io_control_plane","node_role_kubernetes_io_master","pod"]
== longhorn-system pods: transmit bytes per day (GiB) — an off-site backup would show here
2026-10-11T00:00:00Z 25.56
2026-10-12T00:00:00Z 22.86
2026-10-13T00:00:00Z 25.3
2026-10-14T00:00:00Z 26.44
2026-10-15T00:00:00Z 29.03
2026-10-16T00:00:00Z 44.67
2026-10-17T00:00:00Z 45.61
2026-10-18T00:00:00Z 36.08
2026-10-19T00:00:00Z 66.68
2026-10-20T00:00:00Z 76.98
2026-10-21T00:00:00Z 39.77
2026-10-22T00:00:00Z 35.41
2026-10-23T00:00:00Z 38.63
File diff suppressed because one or more lines are too long
File diff suppressed because one or more lines are too long
File diff suppressed because one or more lines are too long
File diff suppressed because one or more lines are too long
File diff suppressed because one or more lines are too long
@@ -0,0 +1,4 @@
# Samba per-client logs (log file = /var/log/samba/log.%m) 2026-10-23T15:31:45Z
# positive control: this session's probe pod 10.42.0.107 connected to :445 during the LAN scan (15:22-15:24Z) and a file log.10.42.0.107 appeared at 17:24 CEST.
-rw-r--r-- 1 root root 0 2026-10-23 17:24 log.10.42.0.107
# files named for any 10.42.x address: 1
@@ -0,0 +1,19 @@
{
"app": "plex",
"walk": "security",
"box_walk_version": 1,
"verdict": "inconclusive",
"venue": "box 9202 (drill catalog), the guarded Update",
"from": {
"plex": "plexinc/pms-docker:1.43.4.10903-e5521bd8c"
},
"to": {
"plex": "busybox:1.36.1"
},
"why": "the install at FROM did not complete — nothing was tested",
"log": [
"12:26:15 [1] made the drive paths this app requires: ['/mnt/felhom-drives/scratch_hdd/userdata/plex']",
"12:26:15 [1] required fields filled beyond DOMAIN/SUBDOMAIN: ['PLEX_CLAIM', 'HDD_PATH']",
"12:26:15 [1] deploy -> 409 {'ok': False, 'error': 'Az alkalmazás adatainak helye egy meghajtó lehet, nem egy mappa a meghajtón belül. Válaszd ezt: "
]
}
@@ -0,0 +1,5 @@
12:26:15 [1] made the drive paths this app requires: ['/mnt/felhom-drives/scratch_hdd/userdata/plex']
12:26:15 [1] required fields filled beyond DOMAIN/SUBDOMAIN: ['PLEX_CLAIM', 'HDD_PATH']
12:26:15 [1] deploy -> 409 {'ok': False, 'error': 'Az alkalmazás adatainak helye egy meghajtó lehet, nem egy mappa a meghajtón belül. Válaszd ezt:
12:26:15 [9] verdict inconclusive -> /mnt/5_hdd/felhom.eu/git/felhom.eu/documentation/audits/security-lane-2026-10-23/P2-negative/verdict.json
12:26:15 RESULT inconclusive — the install at FROM did not complete — nothing was tested
@@ -0,0 +1,188 @@
{
"app": "plex",
"walk": "security",
"box_walk_version": 1,
"verdict": "failed",
"venue": "box 9202 (drill catalog), the guarded Update",
"from": {
"plex": "plexinc/pms-docker:1.43.4.10903-e5521bd8c"
},
"to": {
"plex": "busybox:1.36.1"
},
"observables_before": {
"pinned_images": {
"plex": "plexinc/pms-docker:1.43.4.10903-e5521bd8c"
},
"installed_images": {
"plex": "plexinc/pms-docker:1.43.4.10903-e5521bd8c"
},
"catalog_images": null,
"live_compose_image_lines": [
"image: plexinc/pms-docker:1.43.4.10903-e5521bd8c"
],
"docker_inspect": [
"plex plexinc/pms-docker:1.43.4.10903-e5521bd8c running=true restarts=0"
]
},
"setup_gate_before": {
"browser": {
"status": "302",
"redirect": "https://felhom.enkisfelhom.hu/__gate/start?…"
},
"script": {
"status": "401",
"redirect": null
}
},
"seed": "none",
"seed_why": "the first-run claim needs a token minted at plex.tv by a real Plex account; no account exists for this venue",
"drill_commit": "577947198bff",
"sync_waited_s": 4.5,
"badge_before": {
"hu": [
{
"title": "Újabb változat érhető el ehhez az alkalmazáshoz. A frissítés indításához nyomd meg a Frissítés gombot.",
"text": "Frissítés elérhető — ma"
}
],
"en": [
{
"title": "A newer version of this app is available. Select the Update button to start it.",
"text": "Update available — today"
}
]
},
"measured_at": "2026-10-23T10:27:24Z",
"update": {
"accepted": true,
"http": "202",
"phases": [
{
"t": 0.0,
"phase": "backing-up",
"label": "Biztonsági mentés készül a frissítés előtt…",
"updating": true,
"error": null,
"hold": null
},
{
"t": 11.3,
"phase": "safety-dump",
"label": "Adatbázis pillanatkép…",
"updating": true,
"error": null,
"hold": null
},
{
"t": 12.3,
"phase": "pulling",
"label": "Új verzió letöltése…",
"updating": true,
"error": null,
"hold": null
},
{
"t": 14.4,
"phase": "copying",
"label": "Az adatok másolása a frissítés előtt…",
"updating": true,
"error": null,
"hold": null
},
{
"t": 24.7,
"phase": "starting",
"label": "Indítás az új verzióval…",
"updating": true,
"error": null,
"hold": null
},
{
"t": 25.7,
"phase": "verifying",
"label": "Működés ellenőrzése…",
"updating": true,
"error": null,
"hold": null
},
{
"t": 327.2,
"phase": "undoing",
"label": "Visszaállítás az előző változatra…",
"updating": true,
"error": null,
"hold": null
},
{
"t": 335.4,
"phase": "undone",
"label": "Visszaállítva az előző változatra",
"updating": false,
"error": null,
"hold": null
}
],
"duration_s": 335.4,
"final_phase": "undone",
"update_error": null,
"hold_reason": null,
"state": "running"
},
"observables_after": {
"pinned_images": {
"plex": "plexinc/pms-docker:1.43.4.10903-e5521bd8c"
},
"installed_images": {
"plex": "plexinc/pms-docker:1.43.4.10903-e5521bd8c"
},
"catalog_images": {
"plex": "busybox:1.36.1"
},
"live_compose_image_lines": [
"image: plexinc/pms-docker:1.43.4.10903-e5521bd8c"
],
"docker_inspect": [
"plex plexinc/pms-docker:1.43.4.10903-e5521bd8c running=true restarts=0"
]
},
"badge_after": {
"hu": [
{
"title": "Újabb változat érhető el ehhez az alkalmazáshoz. A frissítés indításához nyomd meg a Frissítés gombot.",
"text": "Frissítés elérhető — ma"
}
],
"en": [
{
"title": "A newer version of this app is available. Select the Update button to start it.",
"text": "Update available — today"
}
]
},
"state_after": "running",
"hold_after": null,
"to_digests": {
"plex": "sha256:e0ab27395614a8e1a4fdf84c6bc60ac664915cfdde70c52d030c7728a1c48e14"
},
"why": "the update ended 'undone' (error None, hold None)",
"log": [
"12:26:46 [1] required fields filled beyond DOMAIN/SUBDOMAIN: ['HDD_PATH', 'PLEX_CLAIM']",
"12:26:46 [1] deploy -> 202 {'ok': True, 'message': 'Telepítés elindítva – az állapot a kártyán követhető'}",
"12:27:06 [1] deployed, controller state=running, pinned={'plex': 'plexinc/pms-docker:1.43.4.10903-e5521bd8c'}",
"12:27:06 gate: plex is gated — passed as the household (cookie set)",
"12:27:10 [2] setup gate as installed: {'browser': {'status': '302', 'redirect': 'https://felhom.enkisfelhom.hu/__gate/start?…'}, 'script': {'status': '401', 'redirect': None}}",
"12:27:10 [3] seed: none — the first-run claim needs a token minted at plex.tv by a real Plex account; no account exists for this venue",
"12:27:11 [5] drill commit 577947198bff: plex plexinc/pms-docker:1.43.4.10903-e5521bd8c -> busybox:1.36.1 (push rc=0)",
"12:27:19 [5] the box's drill mirror now at 57794719",
"12:27:24 [6] Update -> 202 {'ok': True, 'data': {'accepted': True, 'completed': False}, 'message': 'Frissítés elindult – az állapot a kártyán követhető'}",
"12:27:24 + 0.0s phase=backing-up label=Biztonsági mentés készül a frissítés előtt… err=None hold=None",
"12:27:35 + 11.3s phase=safety-dump label=Adatbázis pillanatkép… err=None hold=None",
"12:27:37 + 12.3s phase=pulling label=Új verzió letöltése… err=None hold=None",
"12:27:39 + 14.4s phase=copying label=Az adatok másolása a frissítés előtt… err=None hold=None",
"12:27:49 + 24.7s phase=starting label=Indítás az új verzióval… err=None hold=None",
"12:27:50 + 25.7s phase=verifying label=Működés ellenőrzése… err=None hold=None",
"12:32:51 + 327.2s phase=undoing label=Visszaállítás az előző változatra… err=None hold=None",
"12:33:00 + 335.4s phase=undone label=Visszaállítva az előző változatra err=None hold=None"
]
}

Some files were not shown because too many files have changed in this diff Show More