Global Ansible credentials, applied to every run (manual + alert-triggered): - core/settings.py: ansible.ssh_private_key / become_password / vault_password (plaintext at rest, masked in UI — encryption tracked in #580) + host_key_checking (default off); surfaced via to_ansible_cfg into app.config[ANSIBLE] - executor.py: pure build_credentials() materializes creds into a 0600 temp dir (--private-key, --vault-password-file, become via -e @vars-file so the password never hits argv) cleaned up in finally; pure ansible_env() sets ANSIBLE_HOST_KEY_CHECKING. build_ansible_command stays param-only - settings/routes.py + ansible.html: admin-only Credentials section, masked-update (blank keeps current, explicit Clear checkbox), reload app config on save - tests: unit (build_credentials per cred + none; ansible_env toggle); integration vault round-trip (ansible-vault encrypt a vars file, run via executor with the vault password, assert it decrypted) Co-Authored-By: Claude Opus 4.8 (1M context) <noreply@anthropic.com>
Steward
A self-hosted network monitoring and infrastructure management hub for home servers. Steward gives you a single pane of glass over your hosts, services, and automation — with live-updating dashboards, alerting, and Ansible integration.
What It Does
- Ping monitoring — TCP/ICMP probes with live latency history and configurable thresholds
- DNS monitoring — resolution checks with optional expected-IP validation
- Ansible — browse playbooks, trigger runs, stream output live
- Alerting — threshold-based rules against any monitored metric, with email and webhook (Discord-compatible) notifications
- Plugins — extend with additional data sources; Traefik metrics included out of the box
- Dashboard widgets — all monitors and plugins contribute live-updating widgets
No JavaScript framework. No build step. No external workers or message brokers.
Quick Start — Docker
cp .env.example .env
# Set STEWARD_DATABASE_URL in .env
docker compose up -d
Open http://localhost:5000. On first run you'll be prompted to create the admin account.
Quick Start — Bare Metal
Requires Python 3.11+ and PostgreSQL.
python -m venv .venv && source .venv/bin/activate
pip install -e .
cp config.example.yaml config.yaml
# Edit config.yaml — set database.url at minimum
steward --host 0.0.0.0 --port 5000
ICMP ping requires CAP_NET_RAW or the setuid ping binary. TCP mode (the default) needs no elevated privileges.
Configuration
Only two things must be set to run the app:
| What | How |
|---|---|
| Database URL | STEWARD_DATABASE_URL env var or database.url in config.yaml |
| Secret key | Auto-generated on first run and saved to /data/secret.key |
Everything else — SMTP, webhooks, monitor intervals, Ansible sources, plugin settings — is configured through the web UI at /settings/.
Plugins
Drop a directory into plugins/ and enable it via the Settings UI. The Traefik plugin is included:
plugins/
└── traefik/ ← included; enable in Settings
See docs/plugins/ for a full plugin development guide.
Documentation
| Document | Contents |
|---|---|
docs/architecture.md |
How the app works: startup sequence, routing, scheduler, DB pattern |
docs/core/configuration.md |
Bootstrap config, DB-backed settings, all setting keys and defaults |
docs/core/monitors.md |
Ping and DNS monitors: probe logic, metrics emitted, data models |
docs/core/alerting.md |
Alert rules, state machine, notification channels, template variables |
docs/core/ansible.md |
Playbook sources, run lifecycle, SSE streaming |
docs/plugins/overview.md |
Plugin system: how loading works, plugin.yaml schema, required exports |
docs/plugins/writing-a-plugin.md |
Step-by-step plugin development guide |
docs/plugins/traefik.md |
Traefik plugin: config, metrics, alert rule examples |
docs/reference/code-map.md |
Where every key function, model, and route lives in the codebase |