A Realm Watch project
Heimdall
Fleet security from one small hub.
A self-hosted inventory of your Linux servers. Heimdall records what each one runs, checks it against public vulnerability and end-of-life data, and shows what needs updating, where, and how urgently.
The watchman of the gods sees everything across all nine realms, and touches nothing.
Security first
Heimdall’s database lists every weak spot in every server you manage, which makes the tool itself a target. It’s built so that a fully compromised hub gives an attacker that list and nothing else.
- The hub is a sink, not a controller. Servers push to it. It never connects to a server, holds no SSH keys and has no way to run anything remotely, not even as an option.
- It never serves code. The collector is installed from a signed release, never from the hub, so a compromised hub can’t distribute malware.
- Ingest is write-only. A host’s token can append reports for that host and nothing else. The collector ignores everything the hub sends back except the status code.
- The UI is private. The UI and ingest listen on separate ports. Only ingest faces your servers; the UI sits behind a VPN or tailnet.
- Small and auditable. The hub is one Go binary with five direct dependencies. The collector is a shell script you can read in five minutes.
| If an attacker gets… | They can… | They cannot… |
|---|---|---|
| The hub | Read the inventory and findings | Log into or run code on any server |
| One server and its token | Send fake reports for that host | Read anything, or touch other hosts |
| A user account | See the orgs that account is granted | See other orgs, or create users or tokens |
| The network path | Nothing useful; it’s all TLS | Read or alter reports in transit |
| A feed provider | Return bad advisory data | Learn your hostnames or addresses |
Features
What Heimdall does
Inventory
OS, kernel, packages (dpkg, rpm, apk, pacman), pending and security updates, reboot status, runtimes, services and Docker containers, with history so you can see what changed.
Vulnerabilities and end of life
Package versions matched against OSV.dev, CISA KEV flags, optional EPSS scores, and end-of-life dates for operating systems and runtimes. Only package and version tuples leave the hub.
Sites and Laravel
Every nginx and Apache site, the PHP-FPM version serving it, its Laravel version and every Composer package, with findings per site. It never reads .env or runs app code.
Anomaly signals
Tripwires in the data it already has. Silent hosts, replayed reports, packages changed outside a patch plan, a kernel change without a reboot, a collector that changed unexpectedly.
Logins and privileged access
Opt-in watches for sudo, su and root SSH sessions and for failed SSH logins, with every address named as a person, a deploy service, your own servers or nobody known.
Attack surface
Every public hostname followed to its DNS record, the host it reaches, the site there and that site's open findings, worst first. Cloudflare data is optional and read-only.
Patch plans
Per-host update lists sorted by KEV, severity and EPSS, commands you copy and run yourself, and plans that batch hosts and confirm the fix on the next check-in.
API and MCP
A REST API and an MCP server, so an AI assistant can ask which hosts are exposed. A threat list of attacker addresses that firewalls can pull.
How it works
Getting it running
Install the hub
One Go binary and one SQLite file on a small VM. install-hub.sh sets it up as a sandboxed systemd service, with the UI kept on your tailnet.
Add your servers
Add a host in the UI for a one-line install command, or create an enrollment key to add many servers at once. Each server gets its own write-only token.
Let the collector report
A short POSIX shell script, installed from a signed release and run as an unprivileged user, reports hourly and soon after packages change.
Documentation
Read more
Status: Pre-1.0. Everything below is built; the last steps before 1.0 are an independent security review and a run on real fleets.


