Timar

MIT · one container · no agents

Fleet care for machines that are usually off.

Timar wakes the machines in your homelab, updates them, reads their logs, and puts them back the way it found them. Nothing is installed on the machines it manages — it needs SSH, and Wake-on-LAN for the ones that sleep.

Run it Source on GitHub

v0.1.0amd64 + arm64Linux · OpenWrt · ProxmoxMIT licensed

Timar's dashboard listing six machines. Two are up, three are asleep and marked on-demand, one is down. Each on-demand row offers a wake or shutdown action; always-on rows show n/a. Below, a scheduled work panel shows a daily log sweep and a weekly update run with their last and next runs. The same dashboard in a light theme.
Three states, not two: asleep is a machine that is meant to be off, and it is not painted like a fault. A status page that shows both in red teaches you to ignore red.

The problem

A sleeping machine cannot phone home.

Homelab machines are mostly off. The GPU box runs when you need it, the hypervisor wakes for a job, the build server sits dark for a week. Every tool built for always-on fleets assumes an agent that reports in — which is the one thing a machine that is powered down cannot do. So the machines that go longest without a security update are exactly the ones nothing is watching.

Timar inverts it. Waking the host is step one of the job, and shutting it back down is the last. A machine that was off before the run is off after it.

What a run does

Wake, work, and put it back.

  1. Wake what is asleep A magic packet, or `qm start` on the hypervisor for a guest — a VM has no wake address of its own. From a different subnet, a relay sends the packet from a machine already on that segment.
  2. Update it with the command its platform actually has Debian's apt, Proxmox's dist-upgrade, your own command if you have one. OpenWrt is skipped by default on purpose: an unattended apk upgrade can fill the overlay or land a kernel-module mismatch, and the machine that breaks is the one carrying the session you would repair it from.
  3. Sweep the logs while it is up System log errors, disks past a threshold, stopped containers — and scheduled jobs on that machine that did not run today. Watching for absence is the point.
  4. Shut down whatever started off Guests first, then their hypervisor, in order. Anything that was already running is left running.

The reports outlive the notification. Every finished run is archived and readable in the UI, so a disk creeping upward or an update failing every Friday shows up as a series rather than a single snapshot. Telegram delivery is a copy, not the only place the findings exist.

Measured, not assumed

The failures here are the quiet kind.

A magic packet that never leaves the host. A disk check that exits non-zero and reports all-clear. A schedule that stops firing and writes no error anywhere. None of these announce themselves, so the decisions behind them were measured rather than reasoned about — and the measurements are written down in ARCHITECTURE.md.

0 → 1

Packets on the wire

Wake-on-LAN from a bridge network: the send succeeds, no error, and tcpdump on the LAN sees nothing. Host networking, same image, same button: one packet. That is why the compose file ships network_mode: host.

3.02s → 0.01s

Cold and cached probes

Most of the fleet is supposed to be unreachable, so a probe timeout is the normal case. Probes run in parallel behind a short TTL: the page costs one timeout, not one per sleeping machine.

126 MB

The whole thing

One Alpine image, running as a non-root fixed UID, for amd64 and arm64. A Raspberry Pi is a first-class host — it is what Timar is written on.

Platforms

Commands that exist on the machine you pointed at.

A check that cannot run on a platform says so, instead of quietly reporting all-clear. Every command was run against a real host of that platform before it was written down: busybox and coreutils disagree in ways that fail silently — one df flag GNU accepts and busybox rejects turned into a disk check that passed on every router it was pointed at.

PlatformSystem logDiskContainersUnattended updates
Linux (systemd)journalctlyesDockeryes
Proxmox VEjournalctlyesguests via qmyes
OpenWrtlogreadyesoff by default

Run it

One container, one volume.

$ curl -O https://raw.githubusercontent.com/orkun-soylu/timar/main/docker-compose.yml
$ docker compose up -d

Then open http://<host>:8080 and create the operator account. Nothing else answers until you do — the first screen is the only one served before an account exists. Everything an installation is lives in one directory (/data): config, credentials, state, reports and the SSH key. Backup and migration are cp -a.

Do not expose this to the internet. Timar holds an SSH key that reaches every machine it manages and can grant itself sudo on them. The login page is the only thing in front of your fleet. Keep it on a private network, or behind a reverse proxy you control.

Nothing to install on the fleet

SSH, and Wake-on-LAN for the machines that sleep. Timar generates its own keypair on first use, installs it with your password once, and pins each host key on first sight.

Optional, not required

A model to summarise sweeps (Anthropic, any OpenAI-compatible endpoint, or Ollama) and Telegram for delivery. Without either, waking, updating and the sweep all still work — you get the raw findings instead of a written assessment.