The CA survived a reboot on a volume nobody declared — and did not come back up
A dry-run certificate authority, a host reboot, and two behaviors that were both correct and neither of which was a procedure.
The objective of the measurement was modest: confirm the state of a certificate authority that had been started once, by hand, for a demonstration, and then left on a cloud host through two unrelated experiments and a reboot. The expectation, recorded before looking, was that it was gone. It was not, and the way in which it was not is the finding.
The container had been started with a single docker run and no volume declaration. Inspecting it afterward showed one mount: an anonymous volume, a sixty-four-character hexadecimal name, at /mnt/persistent, read-write. The image declares that path as a volume, and its default database is not the in-memory H2 the chapter had assumed but a file-backed H2 on that volume, which persists its data on graceful shutdown. A sudo shutdown had given it one. The ML-DSA-87 root created in the dry run was intact.
$ docker inspect -f '{{json .Mounts}}' 274c22071c27
[{"Type":"volume","Name":"d7ff7ad0399dc9b4…","Destination":"/mnt/persistent","RW":true}]
$ docker exec 274c22071c27 ls /mnt/persistent
Error response from daemon: container 274c22071c27 is not running
The second line is the other half. The container was Exited, and had been since the reboot, because docker run had been given no restart policy. Nothing was wrong. A certificate authority that publishes certificates, a revocation list and an OCSP responder had simply stayed dark after an ordinary host event, and would have stayed dark until a relying party noticed.
Both behaviors were the engine's defaults. Both were correct. Neither was an operating procedure. The persistence was luck: an anonymous volume is deleted by docker rm -v or by --rm, and its name tells no one what it holds. The outage was the absence of one line.
Three things followed. The volume became two named volumes in a declared Compose stack, one for the database and one for the CA's own files. The restart policy became restart: unless-stopped. And the old container was kept, stopped, as the control for the reboot-survival test: same host, same reboot, no policy — it stays Exited while the declared stack comes back on its own. That comparison is Figure 18-1 in the book.
There is a quieter consequence. The CA's private keys live in that database, encrypted under values that live in an environment file that never enters the repository. Once persistence is declared, backup policy is key-custody policy: a database backup without the environment file is ciphertext; with it, it is the key. The chapter on persistence became the chapter that argues for the root in hardware.
In the book: Chapter 18 carries the full transcript, the figures and the runbook. In the apparatus: the fix is in the repository, pinned to the versions that were measured. In your estate: if this is the problem you are looking at, this is what an engagement does about it.