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

202 lines
11 KiB
Markdown
Raw Permalink Blame History

This file contains ambiguous Unicode characters

This file contains Unicode characters that might be confused with other characters. If you think that this is intentional, you can safely ignore this warning. Use the Escape button to reveal them.

# 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](https://traefik.io/). 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](#features)
- [Requirements](#requirements)
- [Install](#install)
- [Using the TUI](#using-the-tui)
- [CLI](#cli-scriptable)
- [Access control — who can run `avni`](#access-control--who-can-run-avni)
- [How it works](#how-it-works)
- [Data & file locations](#data--file-locations)
- [Security notes](#security-notes)
- [Build from source](#build-from-source)
- [Python fallback](#python-fallback)
- [License](#license)
---
## Features
A tabbed dashboard (switch with `1``9`, `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](#access-control--who-can-run-avni)) |
| **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](#build-from-source) 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
```bash
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:
```bash
avni # full-screen dashboard
avni status # one-shot CLI
```
## Using the TUI
Global keys: `1``9` / `Tab` / `←→` switch tabs · `↑↓` (or `j`/`k`) move · `r` refresh · `q` quit.
Per-tab actions are always shown in the footer. The most useful:
- **Services / Apps** — `s` 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
- **SSH** — `k` kick a session · `K` kick + blacklist its IP
- **Users** — `N` new user · `P` set login/SSH password (masked) · `G`/`g` grant/revoke sudo · `L`/`U` lock/unlock · `D` delete (keeps `/home`) · `Enter` activity
- **Settings** — `g` grant the tool · `x` revoke
Full reference: **[docs/guide.md](docs/guide.md)**.
## CLI (scriptable)
Every subcommand prints the same data the TUI shows:
```bash
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](https://datatracker.ietf.org/doc/html/rfc5737) 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
```bash
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](LICENSE) © 2026 Jagadeesh (AVNI Cloud).