The warden of your servers โ status, resources, cost/expiry and security of Linux hosts over SSH.
Project description
Vordr ๐บ
In Norse lore, the Vรถrรฐr is the guardian spirit that follows each person from birth to death, watching without rest. Here, Vordr stands guard over your servers.
Vordr is a CLI that watches your Linux hosts over SSH and answers, in one place, the questions that matter day to day:
- Are they up? โ state, uptime, load, RAM, disk and containers for every host.
- Will I be charged? โ how long you've hosted each one, when the server renews and when the domain expires, and how much you spend per month. The feature that prevents the surprise charge.
- Are they secure? โ failed logins, listening ports, fail2ban, pending updates and reboot-required.
No agents installed on the servers, no database, no secrets in the code: Vordr only
needs your ~/.ssh/config.
โโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโ
โ Vordr ยท server status โ
โโโโโโโโโโโโโฌโโโโโโโโโโโฌโโโโโโโโโโฌโโโโโโโฌโโโโโโฌโโโโโโโโฌโโโโโโโโโฌโโโโโโโโโโค
โ host โ state โ uptime โ load โ ram โ disk โ docker โ expires โ
โโโโโโโโโโโโโผโโโโโโโโโโโผโโโโโโโโโโผโโโโโโโผโโโโโโผโโโโโโโโผโโโโโโโโโผโโโโโโโโโโค
โ web โ โ online โ 2w 5d โ 0.28 โ 32% โ 22% โ 5/6 โ 53d โ
โ db โ โ online โ 4w 4d โ 0.04 โ 18% โ 62% โ 6/6 โ 6d โ โ
โโโโโโโโโโโโโดโโโโโโโโโโโดโโโโโโโโโโดโโโโโโโดโโโโโโดโโโโโโโโดโโโโโโโโโดโโโโโโโโโโ
Why it exists
Anyone running a few servers ends up collecting loose commands and repeated logins to answer simple questions. Vordr folds that into a single layer that:
- looks at all hosts at once, with comparable metrics colored by threshold (load per CPU, disk/RAM %);
- warns before a renewal charges again;
- gives a quick security audit without logging into each machine.
Vordr collects metrics via small sh scripts that emit KEY=value (stable and
testable) instead of parsing fragile colored output โ but it still offers a --raw
mode that reproduces the native output of a status_command of yours, when you set one.
Install
Requires Python 3.11+ and the ssh client configured with the hosts you want to watch.
pipx install vordr # recommended (isolated tool on PATH)
# or, for development:
pip install -e ".[dev]"
Quick start (just a token)
For cost and billing you don't need to configure anything: give a provider token and Vordr discovers your account's servers on its own.
vordr secret set hetzner # or: vordr secret set vultr
vordr cost # lists the account's servers, with cost and age
vordr billing # balance/credit and next charge
The config.toml is optional and only covers what the API can't know: a nice label,
the SSH alias (for status/resources/security) or a pinned price that differs
from the list price (promo/legacy). What you write in the config always wins over the API.
Configuration (optional)
Hosts are aliases from your ~/.ssh/config โ no IP, user or key is stored by Vordr.
Each host has two lifecycle blocks: [hosts.X.server] (the hosting) and
[hosts.X.domain] (the domain) โ both with all-optional fields, filled from the
API/RDAP when you leave them blank.
vordr init # wizard: imports servers from the API and maps SSH aliases
In a terminal, vordr init is a wizard: with a saved token, it lists the account's
servers, suggests the SSH alias for each (reading your ~/.ssh/config) and asks whether
there's a fixed price to pin โ generating the config without you writing TOML. In a
pipe/CI, or without a token, it writes a commented template.
If a server has no SSH alias (you leave it blank, or write ssh = ""), it becomes
billing-only: it shows in cost/billing, but status/resources/security
ignore it (with a warning), since there's no way to contact it.
[thresholds]
warn_days = 14
critical_days = 7
[hosts.web]
ssh = "web" # alias in ~/.ssh/config
label = "Web"
# status_command = "my-status" # optional: your script for `vordr status --raw`
[hosts.web.server] # the hosting
provider = "Hetzner"
since = "2024-03-01" # since when you've hosted (hosting age)
expires = "2026-08-15" # YYYY-MM-DD โ next server renewal
cost = 6.99
currency = "USD"
cycle = "monthly" # monthly | yearly
[hosts.web.domain] # the domain (optional)
name = "web.example.com"
registrar = "Cloudflare"
expires = "2027-03-01"
cost = 12.00
currency = "USD"
cycle = "yearly"
Vordr ships no hosts. Without a config and without a token, the commands just point
you to the next step (vordr secret set or vordr init). The SSH-based commands
(status, resources, security) need the aliases in the config; cost and billing
work with just the token.
Usage
vordr status # board of all hosts
vordr status web # a single host
vordr status --watch 5 # refresh every 5s (full screen)
vordr status --raw # host's native status_command output
vordr resources # CPU/load, memory and disk in detail
vordr security # audit: logins, failures, ports, fail2ban, updates
vordr cost # table: hosting, server/domain renewal, cost/mo
vordr cost web # detailed lifecycle panel for one host
vordr cost --offline # no network: uses only the config
vordr billing # balance/credit and next charge per provider
vordr check # triage: only what needs attention (for cron)
vordr check --notify # ...and push the alerts to Telegram / email / ntfy
vordr check --watch 6h # ...keep it on an interval (no system changes)
vordr setup # guided setup for alerts & notifications
vordr test # send a sample alert to your channels (verify the look)
vordr hosts # lists what's configured
vordr secret set hetzner # stores the API token (chmod 600, outside the repo)
vordr secret status # shows which providers have a token (masked)
All colors follow thresholds: green (ok), yellow (attention), red (critical) โ for disk/RAM, load per CPU and days until the charge.
cost automation (no typing dates)
cost fills in what you didn't provide โ and the config value always wins (handy
for promo/legacy prices):
- Domain: give just
namein[hosts.X.domain]and the expiry comes from RDAP (public, no credential), cached in~/.cache/vordr/rdap.json. - Server: with
provider = "Hetzner"or"Vultr"and a token configured, thesince(creation date) and the monthly cost come from the provider's API.
Supported providers: Hetzner (HCLOUD_TOKEN) and Vultr (VULTR_API_KEY).
Tokens never live in the repository: they're read from an environment variable or from
~/.config/vordr/secrets.toml (chmod 600, in .gitignore), with env taking precedence.
Configure with vordr secret set <provider>. Values coming from the network are tagged
with (API) / (RDAP).
โ ๏ธ The API price is the list price of the type/plan โ if your account has a promo/locked value, set
costin the config (it wins). The Vultr API uses an IP allowlist and the token is full-access (there's no read-only): guard it well.
Balance and next charge (vordr billing)
With a token configured, vordr billing answers when and from where the charge
comes โ each provider has a model:
- Prepaid (e.g. Vultr): shows credit, the cycle's pending usage and the
runway โ how many days the balance still covers (summing the account's server
costs) and the date it runs out. Useful when running on a bonus/credit: the card is
only charged once the balance hits zero. A summary of that line also appears in the
footer of
vordr cost. - Postpaid (e.g. Hetzner): the Cloud API doesn't expose a balance;
billingshows the next charge date (1st of the next month) and the estimated monthly cost.
Don't get charged by surprise (vordr check)
vordr check is the triage command โ it prints only what needs attention and exits
non-zero if anything does, so it's made for cron. It flags:
- a prepaid bonus/credit about to run out (and the card charges that follow),
- an upcoming charge or renewal, and an expiring domain,
- a host that's offline.
Set it up in one guided command โ type a value, press enter, done:
vordr setup # pick a channel, set thresholds, (optionally) a daily timer
vordr check # quiet when all is well; lists alerts + exit 1 otherwise
vordr check --notify # also push the alerts to your phone
vordr setup asks where alerts should go and writes only the [alerts]/[notify]
sections of your config (the rest is left untouched), then can send a test push.
vordr ยท check
โฒ Vultr ยท credit runs out in ~12d (2026-08-20) โ card charges begin
โฒ Hetzner ยท charge in 6d (โ EUR 4.99, 2026-07-01)
2 alert(s), 0 critical
Thresholds live in [alerts] (runway_days, default 14; charge_days, default 7).
Three notification channels ship โ pick what you already use, or several at once
(vordr setup adds a channel without dropping the others, and every configured channel
fires on each alert):
- Telegram โ delivery through an app you already have, no extra install. Create a bot
with @BotFather (
/newbot), thenvordr secret set telegram(the token is stored chmod 600, outside the repo).vordr setupauto-detects the chat id from a message you send the bot and writes[notify] telegram_chat. - Email (Gmail) โ for the inbox you already watch. Generate an
app password (needs 2FA), then
vordr secret set email; the address goes in[notify] email.vordr setupchecks the SMTP login before saving. - ntfy โ no account, just a topic; set
[notify] ntfy = "https://ntfy.sh/<topic>"(orVORDR_NTFY_URL). Needs the ntfy app (or a browser tab) subscribed to the topic.
A push reads at a glance โ a one-line summary, then a colored dot per item (๐ด critical, ๐ก attention, ๐ข recovered) mirroring the terminal's thresholds:
๐บ vordr ยท 1 critical ยท 1 alert ยท 1 recovered
๐ด db โ domain EXPIRED (2026-06-28)
๐ก Hetzner โ charge in 6d (โ EUR 4.99, 2026-07-01)
๐ข web โ back online
Run vordr test anytime to push a sample alert in this exact layout to every configured
channel โ handy right after vordr setup, or to confirm a channel still delivers.
Push only when it changes (no alarm fatigue)
On a timer, a standing alert โ say a charge seven days out โ would otherwise push on every
single run. --notify instead pushes only when something changes: when an alert is
new, or when it climbs to a more urgent tier (upcoming โ imminent โ due). A host that
recovers gets a one-shot โ <host> back online; alerts that simply clear drop out quietly.
The terminal still shows the full picture on every run โ only the push is deduplicated.
The small ledger lives in ~/.cache/vordr/notify-state.json. (A transient SSH hiccup is
re-probed before it's ever called offline, so a blip never wakes your phone.)
Scheduling โ your call, nothing installed for you
vordr check runs once and exits; vordr never touches your system scheduler. Pick what
suits you:
- Self-contained loop โ
vordr check --watch 6h --notifykeeps itself on an interval in the foreground (run it intmux, or as the user service below). No system changes. - Per-user systemd timer โ a ready-made, fully reversible unit lives in
examples/systemd/: copy it to~/.config/systemd/user/andsystemctl --user enable --now vordr-check.timer. It's yours to remove anytime. - Your own cron/launchd โ if you already run one, just add
vordr check --notify.
How it works
| Layer | File | Responsibility |
|---|---|---|
| SSH transport | src/vordr/ssh.py |
Runs remote commands (BatchMode, timeout). |
| Metric probe | src/vordr/probe.py |
sh scripts โ KEY=value โ dataclasses. |
| Configuration | src/vordr/config.py |
Reads the TOML; days/cost computation. |
| Domain expiry | src/vordr/rdap.py |
Public RDAP + on-disk cache (no credential). |
| Provider API | src/vordr/hetzner.py, src/vordr/vultr.py |
Read-only clients (since, price, balance). |
| Secrets | src/vordr/secrets.py |
Tokens outside the repo (env > chmod-600 file). |
| Alerts / push | src/vordr/notify.py |
vordr check push channels (Telegram/email/ntfy). |
| Formatting | src/vordr/format.py |
Pure functions (uptime, bytes, color thresholds). |
| CLI | src/vordr/cli.py |
Typer + Rich; orchestrates everything in parallel. |
Hosts are queried in parallel (ThreadPoolExecutor), so watching 2 or 10 servers
takes essentially the same time.
Secure by design
- Read-only: Vordr only runs read commands (
/proc,df,ss,last, โฆ). - No secrets in the repository: hosts are SSH aliases; the real
config.tomlstays out of version control (see.gitignore). - No interactive
sudo: privileged checks usesudo -n(non-interactive) and degrade gracefully when there's no permission โ they never block the terminal. BatchMode: if the key isn't available, it fails fast instead of prompting for a password.
Development
make dev # pip install -e ".[dev]"
make lint # ruff check .
make test # pytest -q
The tests never touch the network: the SSH layer is injected (monkeypatch) and the
parsing/formatting logic is tested against real samples of server output. A full sample
config lives in examples/config.example.toml; the
README hero is regenerated with python3 docs/make_hero.py.
License
MIT โ see LICENSE.
Project details
Release history Release notifications | RSS feed
Download files
Download the file for your platform. If you're not sure which to choose, learn more about installing packages.
Source Distribution
Built Distribution
Filter files by name, interpreter, ABI, and platform.
If you're not sure about the file name format, learn more about wheel file names.
Copy a direct link to the current filters
File details
Details for the file vordr-1.0.0.tar.gz.
File metadata
- Download URL: vordr-1.0.0.tar.gz
- Upload date:
- Size: 63.5 kB
- Tags: Source
- Uploaded using Trusted Publishing? Yes
- Uploaded via: twine/6.1.0 CPython/3.13.12
File hashes
| Algorithm | Hash digest | |
|---|---|---|
| SHA256 |
b717b7b19b80e83b954c369ea7ba50f4c6e892921a7aa75caeb38e98cc642aca
|
|
| MD5 |
83ed207f89ba964a138c411cac9505ec
|
|
| BLAKE2b-256 |
9e04d611aa6a83a34e2daaf226d593a87ed8c316c3ed5a40ab7bf56e0a73a59a
|
Provenance
The following attestation bundles were made for vordr-1.0.0.tar.gz:
Publisher:
publish.yml on gusta-ve/vordr
-
Statement:
-
Statement type:
https://in-toto.io/Statement/v1 -
Predicate type:
https://docs.pypi.org/attestations/publish/v1 -
Subject name:
vordr-1.0.0.tar.gz -
Subject digest:
b717b7b19b80e83b954c369ea7ba50f4c6e892921a7aa75caeb38e98cc642aca - Sigstore transparency entry: 2028134751
- Sigstore integration time:
-
Permalink:
gusta-ve/vordr@d331ddf9bdd37d63f9312726435e4fc2b755581f -
Branch / Tag:
refs/tags/v1.0.0 - Owner: https://github.com/gusta-ve
-
Access:
public
-
Token Issuer:
https://token.actions.githubusercontent.com -
Runner Environment:
github-hosted -
Publication workflow:
publish.yml@d331ddf9bdd37d63f9312726435e4fc2b755581f -
Trigger Event:
push
-
Statement type:
File details
Details for the file vordr-1.0.0-py3-none-any.whl.
File metadata
- Download URL: vordr-1.0.0-py3-none-any.whl
- Upload date:
- Size: 49.2 kB
- Tags: Python 3
- Uploaded using Trusted Publishing? Yes
- Uploaded via: twine/6.1.0 CPython/3.13.12
File hashes
| Algorithm | Hash digest | |
|---|---|---|
| SHA256 |
f8fc26653750f22dcb956bbb307f1673bec5ea95d8dbffe75b2a1f876d3870fa
|
|
| MD5 |
07733ecba61c1ebb51b45bd77bb665f8
|
|
| BLAKE2b-256 |
979ceb6180b9d352140e7e5896fb856beed12b94289fd71db044ee443c6708ec
|
Provenance
The following attestation bundles were made for vordr-1.0.0-py3-none-any.whl:
Publisher:
publish.yml on gusta-ve/vordr
-
Statement:
-
Statement type:
https://in-toto.io/Statement/v1 -
Predicate type:
https://docs.pypi.org/attestations/publish/v1 -
Subject name:
vordr-1.0.0-py3-none-any.whl -
Subject digest:
f8fc26653750f22dcb956bbb307f1673bec5ea95d8dbffe75b2a1f876d3870fa - Sigstore transparency entry: 2028134917
- Sigstore integration time:
-
Permalink:
gusta-ve/vordr@d331ddf9bdd37d63f9312726435e4fc2b755581f -
Branch / Tag:
refs/tags/v1.0.0 - Owner: https://github.com/gusta-ve
-
Access:
public
-
Token Issuer:
https://token.actions.githubusercontent.com -
Runner Environment:
github-hosted -
Publication workflow:
publish.yml@d331ddf9bdd37d63f9312726435e4fc2b755581f -
Trigger Event:
push
-
Statement type: