2026-02-08 16:10:37 -05:00
2026-02-04 12:45:35 -05:00
2026-02-08 16:10:02 -05:00
2026-02-08 16:05:03 -05:00
2026-02-08 16:05:03 -05:00
2026-02-08 16:05:03 -05:00
2026-02-08 14:32:12 -05:00
2026-02-06 15:19:14 -05:00
2026-02-08 16:10:02 -05:00
2026-02-08 16:05:03 -05:00
2026-02-06 12:34:59 -05:00
2022-03-05 17:28:04 -05:00
2026-02-08 16:05:03 -05:00
2026-02-08 16:10:37 -05:00

Heartbeat Daemon (hbd)

A lightweight daemon that listens for UDP heartbeat messages and acts on them: keeps host state, optionally updates DNS records via nsupdate, forwards messages to WebSocket clients, and sends notifications (email, Pushover, Mattermost, Signal). It is a refactor of a previously monolithic script into a modular Python package (hbd).


📌 Features

  • Receive and parse heartbeat datagrams (text or zlib-compressed)
  • Maintain host state and detect up/down transitions
  • Queue DNS updates via nsupdate and run them in a background thread
  • WebSocket API for live updates (hosts & messages)
  • Notification pipeline (email, Pushover, Mattermost, Signal)
  • Modular codebase suitable for unit testing and CI

⚙️ Quickstart

Prerequisites:

  • Python 3.10+ (project uses language features from recent Python)
  • nsupdate (for DNS updates) if using dynamic DNS

Install dependencies (recommended into a venv):

This project now declares its dependencies in pyproject.toml. Instead of the old requirements.txt flow, install the package into a virtualenv using pip:

See scripts/install.sh for a way to install.

Run the daemon (example):

# run with default config lookup (~/.hb.yaml)
hbd -c .hb.yaml -f -v

You can also run it directly via the package entrypoint after installation:

python -m hbd.cli -c /path/to/config.yaml

🐞 Debugging in VS Code

This repository includes a ready-to-use .vscode/launch.json with configurations to run or attach the VS Code debugger to hbd.

  • Ensure the Python extension is installed and select the project .venv as the interpreter (bottom-left of VS Code).
  • Use F5 and pick one of these configurations from the Run view:
    • Python: Run hbd (module) — runs hbd.cli as a module and sets PYTHONPATH to the workspace root (recommended).
    • Python: Run hbd with debugpy (listen) — launches debugpy and hbd together; useful when you want the process to listen for a debugger.
    • Python: Attach (localhost:5678) — attach the debugger to a running process started with debugpy.

To start hbd manually and wait for the debugger to attach, run:

PYTHONPATH=. python -m debugpy --listen 5678 --wait-for-client -m hbd.cli -c .hb.yaml -f -v

Set breakpoints in modules such as hbd/udp.py, hbd/dns.py, or hbd/server.py, and use the Attach configuration to connect. Use justMyCode: false if you need to step into third-party code.


🛠 Configuration

hbd reads YAML configuration (optional). If PyYAML is not installed, built-in defaults are used. Example configuration keys (see hbd/config.py):

  • hb_port: UDP port to listen for heartbeats (default: 50003)
  • hbd_port: internal control port (default: 50004)
  • hbd_host: bind address for HTTP/WSS
  • pickfile: path for persisted state
  • logfile: path to log file
  • logfmt: text or msg
  • pushsrv: push service (pushover|mattermost|all)
  • interval / grace: heartbeat timing configuration
  • dyndomains: list of dyndomains to update via nsupdate
  • nsupdate_bin: path to nsupdate binary
  • ws_port: port for plain WebSocket connections (default: 50005)
  • wss_port: port for secure WebSocket (WSS) connections (default: none). If set, hbd will attempt to serve WSS on this port when wss_pem and wss_key SSL files are available under cert_path (see below).
  • cert_path: directory where TLS certificate and key are looked up (default: /usr/local/etc/ssl/)
  • wss_pem: filename for the certificate chain (default: fullchain.pem)
  • wss_key: filename for the private key (default: privkey.pem)

Example .hb.yaml (minimal):

hbd_host: 0.0.0.0
hbd_port: 50004
dyndomains:
  - example.com
nsupdate_bin: /usr/bin/nsupdate
pushsrv: pushover

Tip: config.DEFAULTS in hbd/config.py contains the canonical defaults and accepted configuration keys.


🔧 Architecture & Modules

  • hbd.proto — serialization/deserialization of heartbeat messages (supports compressed payloads)
  • hbd.udp — UDP parsing and handle_datagram implementation (main state machine)
  • hbd.dnscreate_nsupdate_payload, nsupdate, and an asyncio DNS worker (start_dns_worker). The DNS worker now runs as an asyncio task and the package exposes a small thread-safe bridge so legacy synchronous code can put() updates into the queue; there is no longer a permanently-blocking background threading.Thread.
  • hbd.notify — email and push notification helpers
  • hbd.ws — WebSocket server and thread-safe broadcast helpers
  • hbd.http — HTTP handler factory for the status UI/API
  • hbd.utils — small utility helpers (shortname, dur, initlog)
  • hbd.cli — CLI entrypoint and argument parsing
  • hbd.server — async orchestration to run UDP/HTTP/WSS components

This modular layout makes the code easier to test and maintain.

Runtime & Shutdown

  • The main runtime is asyncio-based. Services (UDP listener, HTTP server, WebSocket server, monitor, and DNS worker) run as asyncio tasks.
  • On SIGINT/SIGTERM the server triggers a graceful shutdown: it cancels active tasks, signals the DNS worker via a sentinel, and cleans up resources before exit.
  • The DNS update worker is implemented as an asyncio task; synchronous producers can still enqueue DNS updates via a small thread-safe bridge available at hbd.hbdclass.Host.dnsQ.

Templates & Static Files

  • Template files are located under hbd/templates by default. The HTTP server resolves templates relative to the hbd package but the path can be overridden with the templates_dir config key.
  • Static assets (CSS/JS/images) are served from hbd/static via the /static/<path> HTTP route. Place your static files in that directory or configure the HTTP server as needed.

🧪 Testing & Dev

Tests are implemented using unittest and additional tests rely on pytest if you prefer. To run tests locally without installing anything beyond the dev requirements:

# with project root on PYTHONPATH
PYTHONPATH=. python -m unittest discover -v
# or with pytest if installed
pytest -q

Developer tooling included:

  • pyproject.toml — project metadata and dependencies
  • tox.ini — convenience wrappers for running tests, lint, and mypy

To run linters and type checks locally:

# after installing dev deps
tox -e lint
tox -e mypy

🚀 Running in production

  • Use your system service manager (systemd, launchd, etc.) to run hbd in the background.
  • Ensure nsupdate and necessary credentials are available for dynamic DNS updates.
  • Configure TLS for WSS if you enable secure websockets.

Note: The project contains a small example for obtaining DNS-verified certs (certbot with RFC2136) — see earlier commit history or ask me to re-add the example to this README if you want it documented here.


🤝 Contributing

Contributions welcome! Please:

  1. Open an issue to discuss larger changes.
  2. Create a topic branch and a clear PR.
  3. Add tests for new features and run linters.
  4. Keep changes focused and documented.

📜 License

This repository is licensed under the MIT license. See LICENSE for details.


If you'd like, I can also:

  • add a GitHub Actions workflow that runs tests and lint on push/PR 🔁
  • add a CONTRIBUTING.md template for PRs and code style 💬

Which one should I do next?

S
Description
Machine heartbeat across the internet
Readme 5.6 MiB
v5.3.10 Latest
2026-06-06 08:33:18 -04:00
Languages
Python 66.3%
HTML 25%
C 5.5%
JavaScript 1.7%
Shell 0.6%
Other 0.9%