Features
Everything a lookout needs. Nothing he doesn’t.
Gabier is deliberately small. Here is the full list of what it does, and a few things it refuses to do.
01 · Real time
Within a second of the login
Gabier streams the sshd journal (journalctl --follow) or tails a log
file across rotations. There is no polling interval to tune: a line is read the moment sshd writes
it, and the webhook POST — with retries — never blocks reading the next one.
09:03:14.114 sshd: Accepted publickey for root from 203.0.113.42 …
09:03:14.118 gabier: event accepted user=root ip=203.0.113.42
09:03:14.391 gabier: discord ok 273 ms [events]
accepted = true
failed = true
invalid_user = true
closed = false # doubles the volume for little value
[throttle]
window_secs = 300 # per source IP
burst = 1 # then count and summarise 02 · Anti-spam
A scan cannot drown the real login
This is the only genuinely hard part, and it is solved. Per source IP, the first
burst failures go out immediately; the rest are counted and summarised
in one message at the end of the window. Successful logins are never grouped — that is the event you
are watching for.
03 · Channels
Discord and Slack, by webhook
No bot to invite, no OAuth dance, no token with broad scopes. A webhook URL is all Gabier needs, and
it can post to both at once — if one is down, the other still gets through. Keep the secret out of
the config entirely with GABIER_DISCORD_WEBHOOK.
Discord
Rich embed, coloured by event. Custom username. Ping a user or a role, and allowed_mentions is locked down so a log line can never trigger an @everyone.
Slack
Coloured attachment with a plain-text fallback for push. Slack's own mention syntax: <@U…>, <!subteam^S…>, <!channel>.
Telegram · ntfy · email
Not written yet, but cheap to add: a payload() and a Sink variant. Retries, size limits and ping clamping already live in hook.rs.
[Service]
User=gabier
SupplementaryGroups=systemd-journal
ProtectSystem=strict
ProtectHome=yes
NoNewPrivileges=yes
CapabilityBoundingSet=
RestrictAddressFamilies=AF_INET AF_INET6 AF_UNIX
MemoryDenyWriteExecute=yes
SystemCallFilter=@system-service
MemoryMax=64M
TasksMax=32 04 · Hardened
Least privilege, out of the box
A tool that watches your logins should not be a new way in. The installer creates a dedicated account with no shell and no home; the unit gives it a read-only filesystem, no capabilities, no executable memory, a syscall allow-list and a 64 MB ceiling. It can read the journal and open outbound HTTPS. That is the whole attack surface.
05 · Footprint
One binary, a few megabytes
Rust and rustls, no OpenSSL, no runtime, roots embedded — so there is nothing to install on the VPS alongside it. Release builds are stripped with LTO. Idle, it sits on a journal pipe and costs nothing.
- Binary
- [X] MB
- Memory ceiling
- 64 MB
- Runtime deps
- 0
Where Gabier sits
Between the bash one-liner you never finished and the SIEM you do not want to run for one VPS.
| Shell script + curl | Gabier | Full monitoring stack | |
|---|---|---|---|
| Setup time | An evening, then forever | 2 minutes | A weekend |
| Log rotation, journald | Usually broken | Handled | Handled |
| Survives a port-22 scan | Floods the channel | Burst summaries | Yes, with tuning |
| Runs as root | Usually | No, dedicated account | Often, as an agent |
| Resources | Tiny | 64 MB ceiling | A dedicated host |
| Dashboards, history, search | No | No, on purpose | Yes |
| Good for | One box, one afternoon | Personal VPS, side projects, a handful of servers | Fleets and compliance |
What Gabier will not do
Block anyone
It watches and reports. Banning is fail2ban's job, and the two run well side by side.
Store history
Your journal already does. Gabier keeps no database and no state across restarts.
Phone home
The only outbound connections are your webhooks — plus ipwho.is, if you opt in to geolocation.
Ready to put Pince on watch?
Two minutes, one webhook.