LAN Discovery - ptweezy/cronstable GitHub Wiki
web.bonjour is opt-in, zero-config LAN discovery. When you enable it, the
daemon advertises its web control API as a _cronstable._tcp
service over mDNS/Bonjour, so a companion app (or a service browser) on the
same network finds it without a typed URL.
The advert describes one listener a LAN peer can dial: the first bound
https:// listen entry reachable from another machine, or the first such
http:// one when no https listener qualifies. Loopback and Unix listeners
are never advertised (their ports are unreachable from any other machine),
and a listener bound to an IPv6 address cannot be advertised (the advert's
address record is IPv4-only). That includes [::], whose socket accepts
IPv6 connections only. The advert carries:
- The instance name: the node's hostname by default, or the map form's
name:override (dots are replaced with hyphens; the label is truncated to 63 bytes). - The port: the actually bound TCP port of the advertised listener, so
it is correct even for an ephemeral
listen: http://0.0.0.0:0. - The address: the listener's own IP when it is bound to one specific IPv4 address, otherwise the host's primary outbound IPv4.
- TXT records
v(the daemon version) andscheme(the advertised listener's ownhttporhttps).
The advert's SRV target is a dedicated <name>-cronstable.local. hostname,
so the daemon never contends with the machine's own <hostname>.local.
record (which Avahi or mDNSResponder may already answer for).
The advert carries no secrets: name, port, scheme, and version only. A client that discovers the daemon still needs a bearer token to read anything (see authentication).
Bonjour requires the discovery extra:
pip install "cronstable[discovery]"The extra is python-zeroconf, which is LGPL-2.1-licensed. The release
binaries and Docker images bundle it together with its license notice.
Any binary prints the notice with cronstable --third-party-licenses,
and each GitHub Release attaches the library's source archive. The full
compliance story is in
LICENSING.md.
The boolean form advertises under the hostname:
web:
listen:
- http://0.0.0.0:8080
bonjour: trueThe map form overrides the instance name (and enabled: false turns the
advert off while keeping the block):
web:
listen:
- http://0.0.0.0:8080
bonjour:
enabled: true
name: cron-prod-1Both checks fail at parse time (ConfigError), so --validate-config
catches them:
-
web.bonjourenabled without python-zeroconf installed: install thediscoveryextra or disableweb.bonjour. -
web.bonjourenabled when everyweb.listenentry is a Unix socket: the advert needs a TCP listener to point at.
The advert follows the web app's lifecycle. It is registered while (and only while) an advertisable TCP listener is actually bound, is updated on a config reload when anything it carries changed, and is withdrawn on shutdown.
A runtime mDNS failure (a registration error, no LAN-reachable listener, no non-loopback address to advertise) is logged, and the advert is skipped until the next config apply. Discovery is a convenience and never takes down the scheduler.
macOS:
dns-sd -B _cronstable._tcpLinux (Avahi):
avahi-browse -r _cronstable._tcp- HTTP Control API: the interface the advert points at
- Push Notifications: pairing the companion app the advert helps find
- Web Dashboard
- Configuration Reference