Build / Verification

How to Verify a Windows Docker Home Server Is Actually Stable: Soak Test, Event Audit, Reboot Cycles

It works today is not the same as stable. A repeatable three-layer verification method — a 12.57-hour soak test, a Windows event log audit and five reboot cycles — with real numbers from a Beelink EQi12.

“Everything is running” is the weakest possible claim about a home server. Docker reports Up, the containers answer on localhost, and the whole thing looks fine — right up to the day you leave for a weekend and come back to a stack that died at 2 a.m. with nobody watching. Stability is not a property you can see in a single docker ps output; it is a property you can only demonstrate over time, across reboots, and against a defined pass/fail line.

This page documents the three-layer verification method we used on our Beelink EQi12 (Intel Core i3-1215U, 16 GB RAM, Windows 11 + Docker Desktop) home server, and publishes the actual numbers from each layer. Every value below comes from our public measurement repository (eqi12-measurement-data, CC BY 4.0), with the source file named next to each table. Nothing here is estimated or invented — where we did not measure something, we say so.

If you have not yet built the stack itself, start with the Docker Compose home server stack guide, then return here once docker compose up survives a manual restart. This page is the step after “it works”: proving it keeps working.

Why a single health check is not enough

A container that is healthy at 9 p.m. tells you nothing about three failure classes that only appear over time or across restarts:

  1. Slow degradation — memory leaks, log files filling the disk, a database slowly bloating. Only a sampled timeline (CPU and available memory over hours) exposes these.
  2. Boot-order failures — a container that comes up before its dependency, or a service that only fails when Windows starts it automatically rather than when you start it by hand. Only reboot cycles expose these.
  3. Silent degradation Windows already knows about — services terminating, driver warnings, power events. The event log records these whether you look or not; auditing it turns existing evidence into a verdict.

Each layer targets one class. You do not need fancy tooling for any of them: PowerShell, Docker’s own health status and a text file of timestamps are enough.

Layer 1: the 12.57-hour soak test

The method: while the three-container stack (Nginx, PostgreSQL, Redis) ran its normal workload, a PowerShell loop sampled the machine every 5 minutes and recorded four things per sample — HTTP probe results against the public endpoints, container health/running state, cumulative container restart counters, and CPU percent plus available memory. The run was user-stopped after exceeding the 12-hour minimum, ending at 12.57 hours with 150 samples.

The result, from stability/EQi12_LongStability_12h57_Summary.txt in the measurement repository (the full annotated test log, with screenshots, lives in our 12.57-hour stability lab report — this page focuses on the reusable method and the pass lines):

MetricResult over 12.57 h / 150 samplesPass line
HTTP probe failures00
Container health/running failures00
Container restart count (max, combined)00
Maximum sampled CPU percent52%< sustained 90%
Minimum sampled available memory5,472 MB> 2,000 MB of 16 GB
Final live status3 containers Up 18 h, all HealthyAll healthy

Two of these numbers deserve interpretation rather than a checkbox:

The soak test answers the first question: given no external disturbance, does the stack hold? Zero failures across 150 samples says yes for this workload. The next two layers ask what happens when the machine itself is disturbed.

Layer 2: the 24-hour event log audit

Windows quietly records everything that goes wrong, so before inventing your own monitoring, read what already exists. The audit method: export the System and Application event logs for the last 24 hours, filter to Warning / Error / Critical, group by provider and event ID, then inspect each group once to classify it as benign noise or a real finding. Our capture is stored as stability/EQi12_Event_Summary_24h.txt.

On the EQi12, the 24-hour window contained 4 System and 28 Application warning/error/critical events. The System-side breakdown:

CountProvider / IDClassificationWhy
2DistributedCOM 10016 (Warning)Benign noiseA local activation permission complaint for a COM server — a well-known default-permission artifact on Windows, with no functional impact on a headless Docker host
1Kernel-Processor-Power 37 (Warning)Benign noiseThe processor throttling state changed; on a fanless-class mini PC this accompanies normal power management, not instability
1Service Control Manager 7024 (Error)Real finding (action taken)A vendor updater service terminated with a service-specific error at boot — identified, scheduled for removal from the host, since an updater has no business on a home server

The 28 Application-side events were dominated by similar vendor and shell noise. The value of the audit is not the count — it is that each recurring provider got a one-time classification. From now on, any new provider appearing in this filter is treated as a signal, because the baseline is known.

Two event IDs always deserve immediate attention on any Windows home server:

Layer 3: five reboot cycles

The soak test proved the stack is stable while running. Reboot cycles prove it comes back — which is the whole point of a home server you do not sit in front of. The method: script five consecutive restarts, and after each boot record three timestamps — when the OS was up enough to check, when network connectivity (Ethernet up, gateway reachable) was confirmed, and when the media server container actually answered. Source: misc/EQi12_Reboot_5cycles.log.

CycleBoot → network (s)Boot → Jellyfin answers (s)Ethernet / gateway
167.3188.0Up / True
243.1163.7Up / True
3106.0226.9Up / True
458.3178.9Up / True
542.0162.7Up / True

The pass conditions: all five cycles recovered network connectivity unattended, and all five brought the container stack back without manual intervention. Both held. The spread is also informative — boot-to-network ranged from 42 to 106 seconds, roughly a 2.5× spread on identical hardware. Single-timing claims about “my server boots in 40 seconds” are therefore noise; what matters is the range and the recovery rate (5 out of 5), not the fastest sample.

Note the gap between the two columns: network arrives about 2 minutes before Jellyfin does. That is the boot-order reality of a Windows + Docker host — Docker Desktop and WSL2 start, then Compose pulls the stack up, then health checks turn green. If you are designing around this, the Docker Desktop auto-start guide shows how each layer of that chain is configured to survive reboot.

The pass/fail checklist

Putting the three layers together, here is the reusable checklist with the thresholds we actually applied:

LayerCheckPass line
SoakHTTP probe failures over ≥12 h0
SoakContainer health/running failures0
SoakContainer restart count0
SoakMin available memory floor> ~12% of total RAM
SoakCPUNo sustained saturation across consecutive samples
Event auditKernel-Power 410
Event auditRepeating service-termination errors0 (each classified or removed)
Event auditKnown-benign providersClassified once, then ignored
Reboot ×5Network recovery rate5/5 unattended
Reboot ×5Service recovery rate5/5 unattended
Reboot ×5Boot → service spreadRecorded as a range; regressions judged against your own baseline

Run the soak test after any major stack change (new container, new volume, Compose file change), the reboot cycles after any boot-configuration change (BIOS settings, auto-start changes, Windows updates that touch drivers), and the event audit continuously as part of monthly maintenance.

What we do not claim

Honesty about scope, because measured data is only useful when its boundaries are explicit:

Source data

All numbers on this page are reproducible from the public repository:

The full build context for this machine — power draw, BIOS configuration, wake-on-LAN and the complete measured summary — lives in the EQi12 Windows home server build log.