aptmatic ๐ค๐ฆ
Because SSHing into 40 servers one by one to run
apt-get upgradeis a cry for help.
A snappy terminal UI for wrangling apt across a fleet of Debian/Ubuntu hosts โ written in Rust, because I don't know how to code in OCaml.
โญโ aptmatic โโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโฎ
โ Hosts โDetail โ
โ โธ webservers โweb1.example.com โ
โ โ web1 [2] โuser: ubuntu port: 22 sudo: true โ
โ โ web2 โ โ
โ โธ databases โStatus: 2 upgrade(s) available (1 security) โ
โ โ ผ db1 โ โ
โ โ db2 โKernel โ
โ โRunning: 6.1.0-28-amd64 โ
โ โLatest: linux-image-6.1.0-32-amd64 โ reboot โ
โ โ โ
โ โUpgradable โ
โ โ[sec] curl (7.88.1-10 โ 7.88.1-10+deb12u8) โ
โ โ libcurl4 (7.88.1-10 โ 7.88.1-10+deb12u8) โ
โฐโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโฏ
r:update+refresh R:refresh all u:upgrade U:upgrade all
f:full-upgrade F:full-upgrade all s:sec-upgrade S:sec-upgrade all
a:autoremove A:autoremove all p:purge-rc c:config files b:reboot
t:task output z:zoom /:search q:quit
Features
- ๐ฅ๏ธ Multi-host dashboard โ see every host's status at a glance
- ๐ฅ Groups โ organise hosts and trigger actions on a whole group at once
- ๐ SSH native โ talks directly to each host over SSH, no agents or daemons required
- ๐ Live task output โ watch
apt-get upgradescroll by in real time - ๐ง Kernel tracking โ know which hosts are silently waiting for a reboot
- ๐ฆ Held/kept-back packages โ spot the stragglers and why they're stuck
- ๐ก๏ธ Security-update badge โ upgradable packages from a security suite are called out separately, with a key to upgrade just those
- ๐ Sidebar search โ
/to filter hosts/groups by name in a big fleet - ๐พ Cached last-known state โ the dashboard isn't blank on startup while it reconnects
- ๐ฆ Bounded connection concurrency โ "all hosts" actions queue instead of opening a connection per host at once
- ๐งน RC package purging โ one key to purge all those half-removed ghosts
- ๐ Pending config files โ upgrades never stop to ask about a changed conffile; the new version is counted per host and reviewed later, with a diff, on your schedule
- โฌ๏ธ Full-upgrade & autoremove โ
apt-get full-upgradeandapt-get autoremove --purge, on selected hosts or the whole fleet - ๐ Confirmed reboot โ type the hostname to confirm before a host goes down
- ๐ฑ๏ธ Draggable divider โ because you deserve to customise your own TUI
- ๐ฆ Written in Rust โ guaranteed* to have no bugs
* guarantee void where prohibited by logic
Installation
Or build from source:
# binary at ./target/release/aptmatic
Configuration
aptmatic looks for its config at ~/.config/aptmatic.toml by default. Pass -c /path/to/config.toml to override.
[]
= "ubuntu"
= 22
= true
[[]]
= "webservers"
[[]]
= "web1.example.com"
[[]]
= "web2.example.com"
= "admin" # override per-host
[[]]
= "databases"
[[]]
= "db1.example.com"
Keybindings
| Key | Action |
|---|---|
โ / k |
Move up |
โ / j |
Move down |
/ |
Search/filter the sidebar by hostname or group name |
r |
apt-get update + refresh on selected |
R |
apt-get update + refresh on all hosts |
u |
apt-get upgrade on selected |
U |
apt-get upgrade on all hosts |
f |
apt-get full-upgrade on selected |
F |
apt-get full-upgrade on all hosts |
s |
Upgrade security-only packages on selected |
S |
Upgrade security-only packages on all hosts |
a |
apt-get autoremove --purge on selected |
A |
apt-get autoremove --purge on all hosts |
p |
Purge RC packages on selected |
c |
Review pending config files on the selected host |
b |
Reboot the selected host (type the hostname to confirm) |
t / Enter |
View live task output |
z |
Zoom โ hide sidebar for clean copy/paste |
q / Esc |
Quit |
The sidebar divider is also mouse-draggable if you're feeling fancy.
Pending config files
Upgrades run with --force-confdef --force-confold, so dpkg never stops to ask what to do about a config file you've edited โ it keeps yours and drops the maintainer's version next to it as .dpkg-dist. Hosts carrying unresolved files show a [n cfg] badge in the sidebar; c opens a review pane listing them with a diff against the live file. Mark each file with a decision, then execute the whole batch in one go:
| Key | Action |
|---|---|
โ / โ |
Select a file |
PgUp / PgDn |
Scroll the diff |
d |
Mark: discard the new version, keeping your current config |
a |
Mark: install the new version, backing your current one up to .dpkg-old |
u / Space |
Unmark |
Enter |
Execute all marked decisions (asks for confirmation first) |
Esc |
Close without touching anything |
Marking is free โ nothing happens on the host until you confirm with Enter then y. Unmarked files are left pending for a later review, and a failure on one file doesn't stop the rest of the batch. Applying a config file does not restart anything โ restart the affected service yourself once you're happy with it.
While searching, type to filter, โ/โ to jump between matches, Enter/Esc to stop editing (the filter stays applied โ clear it by backspacing to empty).
Actions on a whole group or "all hosts" are queued through a small connection pool (8 at a time) rather than opening an SSH connection per host simultaneously.
Development
Why?
Managing a modest fleet of Linux boxes with apt should not require an orchestration platform, a PhD in Ansible, or accepting a cookie banner. aptmatic is a single binary, a TOML file, and a spare SSH key away from a good time.