Files
vps-tool-avni/README.md
Jagadeesh 8612b38bee first commit
Co-Authored-By: Claude Opus 4.8 <noreply@anthropic.com>
2026-06-24 20:36:08 +02:00

11 KiB
Raw Permalink Blame History

avni — a single-binary control center for your VPS

avni is a fast, dependency-light terminal dashboard (TUI) + CLI for operating a self-hosted Linux server: see your Docker apps, domains, bandwidth, SSH sessions and brute-force attackers at a glance — and act on them (start/stop services, ban/blacklist IPs, manage users) without leaving the terminal.

It shells out to the tools already on the box (docker, fail2ban-client, ipset, vnstat, who/last, getent, …) — no daemon, no database, no agent. One Rust binary, ~2% CPU, microsecond redraws.

Built for a small multi-app VPS behind Traefik. It auto-discovers the apps Traefik routes, so the dashboard never goes stale as you add or remove services.

┌ AVNI CLOUD · control center ─────────────────────────────────────────────────────────┐
│  1.Overview · 2.Services · 3.Domains · 4.Traffic · 5.Security · 6.SSH · 7.Users · 8.Set…│
└────────────────────────────────────────────────────────────────────────────────────────┘
┌ Applications (9/9 enabled) — s enable · x disable · R restart · l logs · ↵ details ─────┐
│    APP            STATE     SUBDOMAIN              PORT   HOST PORTS                      │
│ » ● gitea         enabled   git.example.com        3000   127.0.0.1:3000->3000           │
│   ● n8n           enabled   n8n.example.com        5678   127.0.0.1:5678->5678           │
│   ● uptime-kuma   enabled   uptime.example.com     3001   127.0.0.1:3001->3001           │
│   ○ analytics     disabled  stats.example.com      3000   -                              │
└──────────────────────────────────────────────────────────────────────────────────────────┘
  s enable   x disable   R restart   l logs   ↵ details    1-9/⇄ tabs   ↑↓ move   r refresh

Table of contents


Features

A tabbed dashboard (switch with 19, Tab, or ←/→):

Tab What it shows / does
Overview host, IP, uptime, load/memory/disk gauges, service & attacker summary, dual clock (server + your local time)
Services every Docker container with status + the domain Traefik routes to it; s/x/R start/stop/restart, l logs
Domains every Host() route → backend; Enter checks live HTTP status + TLS cert expiry
Traffic vnstat bandwidth bar chart, 24h / 7d / 30d windows (pins the real uplink interface)
Security a persistent IP registry of everyone who has touched the box (country, attempts, logins, status). Temp-ban (fail2ban), permanent firewall blacklist (ipset+iptables), and a whitelist that can never be banned
SSH live sessions (kick / kick+blacklist) + the effective sshd policy
Users list/create/delete Linux users, grant/revoke sudo, lock/unlock, set login password, and a full per-user activity view (system metadata only)
Settings delegate the tool to other admins (see access control)
Apps the user-facing apps Traefik routes — enable/disable, ports, subdomain, live HTTPS + cert details

Highlights:

  • Auto-discovery — apps and domains come straight from container labels; nothing to configure.
  • Persistent attacker registry with incremental log parsing (reads only newly-appended bytes of auth.log, survives rotation).
  • Optimistic UI — actions reflect instantly, then reconcile with the real system state.
  • Dual time — every timestamp shows a second timezone beside it (configured for IST in the source; see Build to change).
  • Scriptable — every view is also a one-shot CLI subcommand.

Requirements

  • Linux, run as root (or as a delegated avni-group member — it self-elevates via sudo).
  • A recent Rust toolchain (rustup stable; ratatui 0.26 needs a newer rustc than some distros ship).
  • Expected on the box (features degrade gracefully if missing): docker, fail2ban-client, ipset + iptables, vnstat, geoiplookup (geoip-bin), whois, plus coreutils (who, last, lastb, getent, passwd, chpasswd).

Install

git clone https://git.example.com/you/vps-tool-avni.git
cd vps-tool-avni
sudo bash install.sh

install.sh builds the release binary and installs it to /usr/local/bin/avni, installs the firewall helper to /usr/local/bin/avni-firewall.sh, creates the avni group, and writes a sudoers drop-in so delegated admins can launch it. Re-run it after pulling changes.

Then just:

avni            # full-screen dashboard
avni status     # one-shot CLI

Using the TUI

Global keys: 19 / Tab / ←→ switch tabs · ↑↓ (or j/k) move · r refresh · q quit.

Per-tab actions are always shown in the footer. The most useful:

  • Services / Appss start/enable · x stop/disable · R restart · l logs · Enter details
  • Security[ ] switch sub-tab · a add blacklist · A add whitelist · b ban · B blacklist selected · W whitelist selected · u undo · w whois · Enter IP intel
  • SSHk kick a session · K kick + blacklist its IP
  • UsersN new user · P set login/SSH password (masked) · G/g grant/revoke sudo · L/U lock/unlock · D delete (keeps /home) · Enter activity
  • Settingsg grant the tool · x revoke

Full reference: docs/guide.md.

CLI (scriptable)

Every subcommand prints the same data the TUI shows:

avni status                          # host + counts
avni services                        # all containers
avni apps                            # user-facing apps: state · subdomain · port
avni ips [attackers|banned|new|all]  # the IP registry
avni attackers [N]                   # top N attackers with country
avni ban <ip> | unban <ip>
avni blacklist [add <ip|cidr|domain>]
avni whitelist [add|del <ip>]
avni geo <ip> | ssh | users
avni adduser <user> [password]       # create account (-m home, bash)
avni passwd  <user> <password>       # set a user's Linux login / SSH password
avni sudo <user> | unsudo <user>     # grant / revoke sudo
avni deluser <user>                  # delete account, KEEP /home
avni activity <user>                 # logins, failed logins, sudo cmds, processes
avni access | grant <user> | revoke <user>   # tool delegation

Access control — who can run avni

The tool is root-only by default. To let a teammate use it:

  1. They must already be an admin (sudo)avni sudo <user> (Users tab G).
  2. Grant the tool — avni grant <user> (Settings tab g). This adds them to the avni group; the sudoers drop-in lets the binary auto-elevate via sudo when they run it.

Anyone not granted gets a polite "not authorised" message. Root can never be revoked. The single binary at /usr/local/bin/avni is a real root-owned file (mode 0755), so a delegated user can exec it but cannot modify it.

How it works

  • Background gather — a worker thread fans out the independent fetches (docker, auth-log registry, sessions, users, vnstat) across threads, so a full refresh ≈ the slowest single part (~2 s) instead of the sum. The UI never blocks; a loading splash shows on first start.
  • Incremental log parsing — stores a byte offset per log inode and reads only the new tail of auth.log on each refresh (not the whole multi-MB file).
  • Auto-discovery — services, domains and apps are parsed from docker ps + Traefik Host() labels in a single call. Nothing is hard-coded; add a container and it appears.
  • Traffic pins the default-route interface (a busy box can have dozens of docker veth/bridge interfaces; vnstat's interfaces[0] is often a zero-traffic bridge).

Data & file locations

Path Purpose
/usr/local/bin/avni the binary
/usr/local/bin/avni-firewall.sh blacklist/whitelist engine (ipset + iptables)
/var/lib/avni/ips.json persistent IP registry (+ per-log byte offsets)
/etc/avni/whitelist.txt, /etc/avni/blacklist.save firewall state
/etc/fail2ban/jail.d/avni-whitelist.conf auto-generated fail2ban ignoreip
/etc/sudoers.d/avni NOPASSWD drop-in for the avni group

Security notes

  • No secrets are stored in this repo or the binary. avni reads live system state at runtime; it never embeds passwords, IPs or hostnames. (The examples in the code are RFC 5737 documentation addresses.)
  • Whitelist your own IPs first. A firewall guard and fail2ban ignoreip then make it impossible to accidentally lock yourself out under a brute-force burst; an anti-lockout check also refuses to blacklist your current SSH client IP.
  • Docker-published ports bypass host UFW — the firewall engine adds rules to the DOCKER-USER chain too, so a blacklist actually blocks container-exposed ports.
  • The per-user activity view uses only system metadata (logins, sudo audit, ps) and never reads anyone's home directory or shell history — safe on a multi-tenant box.

Build from source

cargo build --release      # at the repo root → target/release/avni

Toolchain: rustup stable. Dependencies are just ratatui, crossterm, serde, serde_json (see Cargo.toml).

Changing the second timezone: the dual-clock offset is computed in ist_delta_min() in src/main.rs (currently targets IST, +05:30). Adjust the 330 (minutes) and the TZ=Asia/Kolkata strings to your zone.

Python fallback

avni.py is an earlier pure-Python (curses) implementation kept as a zero-build fallback. install.sh installs it as /usr/local/bin/avni-py. The Rust binary is the maintained one.

License

MIT © 2026 Jagadeesh (AVNI Cloud).