fahrenheit/openrc: supervise-daemon orphans pihole-FTL child on restart, holding ports #3
Reference in New Issue
Block a user
Delete Branch "%!s()"
Deleting a branch is permanent. Although the deleted branch may continue to exist for a short time before it actually gets removed, it CANNOT be undone in most cases. Continue?
What happened
2026-04-29 04:29 UTC, while diagnosing a stuck pihole-FTL dashboard outage on fahrenheit (Alpine 3.23):
rc-service pihole-FTL stopreturned[ ok ].rc-service pihole-FTL startspawned a fresh FTL (PID 24450).pihole-FTLprocesses coexisted. PID 496 held port 53. PID 24450 held only 80/443 (it had failed to bind 53 because the orphan still owned it, and civetweb'somodifier on the web ports meant it didn't respawn-loop on the partial bind).kill -TERM 496had no effect. The orphan ignored SIGTERM.kill -9 496finally cleared it.rc-service pihole-FTL restartso the new FTL would retry binding port 53.Net effect: a single
rc-service restartdid the opposite of what was intended — created two daemons instead of cycling one.Why it matters
This is the upstream cause of issue #2 — every restart that orphans the previous child guarantees a port-bind conflict on the next start, which civetweb silently shrugs at.
Repro hypothesis
/etc/init.d/pihole-FTLsupervisor=supervise-daemoncommand_args_foreground="-f"command_background=truestop_pre/stop_postother thanstop_post=sh ${PI_HOLE_SCRIPT_DIR}/pihole-FTL-poststop.shPossible fixes
stop()that kills the actual child (read PID from/run/pihole-FTL_openrc.pid, send TERM, reap, fall back to KILL). This is what most modern OpenRC services do for supervise-daemon supervisors.supervise-daemonflags — verify whether--stopis being sent at all onrc-service stop, and whether it's translating to a signal on the child. Possibly an Alpine packaging quirk on the pihole-FTL aports script.pgrep pihole-FTL | xargs -r kill -9afterrc-service stopand beforerc-service start. Ugly but reliable.Investigation pointers
apk info -L pihole-FTLto find which package owns/etc/init.d/pihole-FTLand whether it's a Pi-hole-shipped or Alpine-packaged init.supervise-daemon --help | grep -A2 -- --stop: does it propagate the stop signal to the child?supervise-daemonorphan-on-stop reports (would be surprised if this is novel).Severity
Medium. Workaround is
kill -9+ restart. The real cost is that an unattended restart (e.g., from apihole -upupgrade) silently leaves a half-broken daemon, which is exactly what bit fahrenheit for ~5 days.Related: #2
Workaround documented in v0.1.9 runbook ("fahrenheit / pihole-FTL gotchas" subsection #1): explicit
rc-service stop+pgrep | kill -TERM+sleep 2+pgrep | kill -KILL+rc-service startcycle. Proper fix (service-levelstop()that propagates to the supervised child) remains parked — needs an upstream patch to pihole-FTL aports or a downstream init.d override. Closing as worked-around. Cross-ref #2 (which depended on this for the silent-failure to manifest).