Skip to content

Keep the shim from staying dead after a boot that outran DNS - #33

Merged
matuszeg merged 1 commit into
mainfrom
shim-survives-boot
Aug 23, 2026
Merged

matuszeg merged 1 commit into
mainfrom
shim-survives-boot

Conversation

@matuszeg

Copy link
Copy Markdown
Owner

Closes #32.

The shim's nginx resolves www.pumpspy.com while parsing its config, so a
boot that reaches nginx before a resolver answers ends at
[emerg] host not found in upstream — and nginx exits with nothing to retry
it. nginx -t passes once DNS is up, which is what makes it read as a mystery.

Hit for real on 2026-08-23 after host maintenance rebooted the shim LXC: it
failed this way at 14:39:45 (something restarted it a minute later) and again
at 18:03:43, where nothing did. The shim was down 3h20m.

The fail-open is what hid it — health stopped answering, the watchdog withdrew
the NAT rules, the device went straight to the vendor, and the PumpSpy app
looked healthy throughout. The only symptom was Home Assistant recording
nothing.

What this adds

shim/nginx-service-override.conf, installed as
/etc/systemd/system/nginx.service.d/override.conf:

  • After=nss-lookup.target — the ordinary case.
  • Restart=on-failure + RestartSec=10s — the actual fix, since reaching that
    target does not guarantee a resolver is answering.
  • StartLimitIntervalSec=0 — never give up. A genuinely broken config loses
    nothing by retrying: health stays silent and the redirect stays withdrawn,
    which is the fail-open outcome regardless.

Three tests in tests/test_shim_config.py, each verified to fail with the
corresponding directive removed. docs/fail-open-shim.md gains the install
step and a section explaining why booting is the dangerous case — the existing
text noted that nginx resolves the vendor only at start/reload but drew only
the stale-address conclusion.

Verification

Installed on the live shim and confirmed through systemd rather than by reading
the file back: systemctl show nginx reports Restart=on-failure,
RestartUSec=10s, StartLimitIntervalUSec=0, and both targets in After.
200 tests pass.

nginx resolves the vendor's addresses while parsing its configuration,
so a host that reaches nginx before a resolver is answering fails the
config test and exits. Nothing tries again, and nginx -t passes cleanly
once DNS is up, so it reads as a mystery rather than a race.

The fail-open is what hides it. Health stops answering, the watchdog
withdraws the redirect, the device reports to the vendor directly, and
the vendor's app looks perfectly healthy while Home Assistant records
nothing. On the reference install a routine host reboot cost 3h20m of
local monitoring before anyone looked.

Ship a systemd drop-in: ordered after nss-lookup.target for the ordinary
case, and restarting on failure for the rest, since reaching that target
does not guarantee a resolver is answering. The start limit is disabled
so it never gives up -- if the configuration is genuinely broken the
retries change nothing, because the redirect stays withdrawn either way.

The docs already noted that nginx resolves the vendor only at start or
reload, but drew only the stale-address conclusion. They now draw the
fatal one too.
@matuszeg
matuszeg merged commit d418c0a into main Aug 23, 2026
3 checks passed
@matuszeg
matuszeg deleted the shim-survives-boot branch August 23, 2026 22:41
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Labels

None yet

Projects

None yet

Development

Successfully merging this pull request may close these issues.

A boot that outruns DNS leaves the shim dead for good, and the fail-open hides it

1 participant