Proxxx
Records serial console sessions as asciinema cast v2 files and replays them with proxxx play-cast.
Exports the append-only audit log as JSON or CSV for ingestion into Elastic SIEM.
Provides full management of Proxmox VE clusters and Proxmox Backup Server: cluster-wide reads, guest and storage lifecycle operations, backup and restore, state export/diff/apply, audit logging, incident freeze, and MCP access.
Exports the append-only audit log as JSON or CSV for ingestion into Splunk SIEM.
Human-in-the-loop approval gate for destructive operations via Telegram, with policy-driven routing, deny-on-timeout, and HITL workflow support.
Who is this for?
Pick the row that matches you and jump straight to the right page.
If you are… | …you'll care about | Start here |
Homelab solo running 1-3 nodes | wizard, fast TUI, single binary, no daemons | |
Platform / SRE on 10-50 nodes with on-call | HITL Telegram gate, alert daemon, | |
DevOps scripting Proxmox in pipelines | typed exit codes, deterministic JSON, pre-flight risk gate, batch ops with | |
LLM / agent integrator wiring Claude/Cursor to a cluster | MCP server (stdio + Streamable HTTP), compile-time-fixed 25-tool registry, SHA-256 pinned for supply-chain audit | |
Security / compliance evaluating before deploy | typed errors, HITL replay protection, sigstore-signed releases, CycloneDX SBOM, gate on every commit | |
EU-regulated ops (NIS2 / ISO 27001 / GDPR) | append-only SQLite audit log with HMAC-SHA256 chain, | |
Contributor sending a PR | 8-stage commit gate (fmt + clippy + audit + cargo-deny + test+proptest + live cluster + mutation lifecycle), no-skip-flags policy |
Related MCP server: Proxmox MCP Server
What you get
One binary —
proxxx. CLI, TUI, MCP server, unified daemon (alerts + HITL + schedule) all in the same executable.Cluster-wide read in a second —
proxxx ls nodes,proxxx ls guests, fuzzy search across the whole cluster from/.--all-profilesfans the read across every configured cluster in parallel.GitOps for Proxmox —
proxxx state {export,diff,apply}produces a byte-stable TOML across ten state families (pools, ACL grants, storage definitions, backup jobs, cluster firewall, notification matchers, HA rules, HA resources, and PCI + USB device mappings — passthrough-as-code), diffs against live, converges via dispatched API calls. Pre-flight risk gates refuse Severe changes (non-empty pool delete, root-role ACL delete, shared-storage delete, HA-rule strict-flip, passthrough-mapping delete) unless--allow-risk;--interactiveadds per-Severe[y/N]stdin prompts. Thereconcilecontroller runs that loop continuously:reconcile run(CI-gateable drift check) andreconcile converge(push-mode apply, same safety gate), plus an opt-in unmannedauto_convergedaemon that self-heals drift on a timer — and never auto-applies a Severe change (it alerts for human review instead).Pipeline writes — start, stop, migrate, snapshot, clone, backup, patch, disk-move, with
--format jsonfor jq.migrate --streamshows live per-disk progress.Pre-flight risk gate — both per-guest (Locked/Running/LongUptime/TaggedProd/ActiveNetTraffic/HaManaged + 5 more) and state-change (PoolDeleteNonEmpty/AclDeleteRootRole/StorageDeleteShared/BackupJobDelete/NotificationMatcherDelete/HaRuleDelete/HaRuleStrictChange/HaResourceDelete/HaResourceStateChange/BulkChangeCount) — refuses destructive ops without explicit override.
HITL — Telegram-mediated human approval gate, deny-on-timeout (120 s), policy-driven by tag / vmid / wildcard.
Incident lockdown —
proxxx incident freeze --reason X --ttl 4hhalts every mutation cluster-wide (POST/PUT/DELETErefuse with exit 8);thawlifts it. Reads keep working for investigators.Console handoff + recording — SSH/serial/SPICE/noVNC, all from
proxxx <verb> <vmid>.proxxx serial --recordwrites asciinema cast v2;proxxx play-castreplays.Cross-cluster —
proxxx find <vmid>answers "which cluster owns this guest?" without manual profile-switching.Fleet view —
proxxx fleetaggregates every configured profile (clusters + standalone hosts, mixed) into one read-only TUI: per-cluster health summary + an aggregated guest table.↑↓select a cluster,Tabtoggle the guest pane (selected vs whole fleet),Enterdrill into a cluster's full TUI,qquit.Read-only profiles —
read_only = trueon a profile makes proxxx refuse every mutation on it client-side (reads still work); pair with aPVEAuditorPVE token for a server-enforced lock too. Observe production safely, write only on your test cluster.PBS browse + restore — REST browse plus
proxmox-backup-clientrestore withkill_on_dropsupervision.proxxx backup-verifydoes metadata-level integrity probing.Observability —
proxxx logs tail(cross-node journalctl fanout via SSH),proxxx heatmap(per-node API RTT),proxxx anomaly(z-score outliers),proxxx accounting --timeframe month(CPU-hours/GiB·h/net-GiB from per-guest RRD).Upgrade pre-flight —
proxxx upgrade-check --target 9.xscans cluster + config against bundled rules; exit code 1 on any block-severity finding (CI-gateable).Bundled error knowledge base —
proxxx explain <error-id>for every typed error proxxx can emit (15 entries; ships with the binary, no network needed).Cluster digest for LLMs —
proxxx describe --output llm-contextemits a token-compact prose+key:value paste-pronto for AI chats.MCP server — stdio JSON-RPC + HTTP/SSE for LLM agents, compile-time-fixed tool registry, surface SHA-256 pinned. Server-sent
notifications/cluster-eventon both transports (task lifecycle + freeze/thaw events). Security defaults: destructive tools are fail-closed — refused unless a matching[[policies]]entry routes them through HITL approval — andserve-httpbinds loopback-only, refusing a non-loopback bind unlessmcp_tokenis set.Verifiable releases — every tarball ships with three layers: SHA-256 sidecar, sigstore keyless cosign signature pinned to this exact workflow path (offline-verifiable; transparency-log inclusion proof embedded), and a CycloneDX SBOM generated from
Cargo.lock. Audit withcosign verify-blob+grype/trivy.
EU & compliance
proxxx is designed for operators who need auditability, data sovereignty, and supply-chain transparency — requirements increasingly mandated under NIS2, ISO 27001, and GDPR in the EU.
Requirement | How proxxx addresses it |
No telemetry | Zero outbound connections except to your configured PVE/PBS endpoints and, if you opt in, your own Telegram bot. No analytics, no crash-reporting, no version-check pings. |
Data sovereignty | All state — config, cache, audit log, HITL keys — lives on-prem, under paths you control ( |
Append-only audit log |
|
Cryptographic chain verification |
|
Export for SIEM |
|
Supply-chain | Every release ships: SHA-256 sidecar, sigstore keyless cosign signature (pinned to the exact workflow path, offline-verifiable, transparency-log proof embedded), and a CycloneDX SBOM from |
Self-diagnostic |
|
Secrets hygiene | All secret values live in |
Note: proxxx is a management tool, not a compliance product.
proxxx audit verifyprovides integrity assurance for the local mutation log; it does not replace a SIEM or a formal audit trail required by a certification body. Use it as one control layer in a broader NIS2 / ISO 27001 implementation.
Install
Pre-built binaries for macOS Apple Silicon, Linux x86_64-musl, and Linux aarch64-musl (Pi 4/5, Ampere, Graviton, Oracle Free Tier) are attached to each tagged release. All Linux artefacts are statically linked — no glibc, drops onto Alpine through RHEL.
Homebrew (macOS & Linux)
brew install fabriziosalmi/proxxx/proxxxThe fastest path on a workstation. For a Proxmox VE node (Debian) use the .deb below; for air-gapped installs or full supply-chain verification, download + verify the trio manually:
TARGET=x86_64-unknown-linux-musl # or aarch64-apple-darwin
VERSION=$(gh release view --repo fabriziosalmi/proxxx --json tagName -q .tagName | sed 's/^v//')
gh release download v${VERSION} --repo fabriziosalmi/proxxx \
--pattern "*-${TARGET}.tar.gz" \
--pattern "*-${TARGET}.tar.gz.sha256" \
--pattern "*-${TARGET}.tar.gz.cosign.bundle"
# 1. Checksum
shasum -a 256 -c proxxx-${VERSION}-${TARGET}.tar.gz.sha256
# 2. Sigstore keyless signature (offline; cert pinned to release.yml)
cosign verify-blob \
--bundle proxxx-${VERSION}-${TARGET}.tar.gz.cosign.bundle \
--certificate-identity-regexp 'https://github.com/fabriziosalmi/proxxx/.github/workflows/release.yml@.*' \
--certificate-oidc-issuer 'https://token.actions.githubusercontent.com' \
proxxx-${VERSION}-${TARGET}.tar.gz
# 3. (optional) Audit the CycloneDX SBOM
gh release download v${VERSION} --repo fabriziosalmi/proxxx \
--pattern "*.cdx.json" --pattern "*.cdx.json.sha256"
shasum -a 256 -c proxxx-${VERSION}.cdx.json.sha256
grype sbom:proxxx-${VERSION}.cdx.json # or trivy / cyclonedx-cli
tar xzf proxxx-${VERSION}-${TARGET}.tar.gz
./proxxx-${VERSION}-${TARGET}/proxxx --versionIf you only want the binary fast (no verification), skip steps 2–3 and run just shasum -a 256 -c … from the snippet above. Production deployments should run all three — see the Production checklist.
Or build from source (needs Rust 1.95+):
git clone https://github.com/fabriziosalmi/proxxx.git
cd proxxx && cargo build --release
./target/release/proxxx --versionThe Linux musl artifact is statically linked — runs on every distro from RHEL 6 to Alpine 3.x without GLIBC drama.
Debian / Ubuntu / Proxmox VE — .deb
Each release also ships a .deb for amd64 and arm64, signed with the same sigstore bundle. The binary is static-musl, so the package declares no runtime dependencies — drop it straight onto a Proxmox VE node (which is Debian):
VERSION=$(gh release view --repo fabriziosalmi/proxxx --json tagName -q .tagName | sed 's/^v//')
gh release download v${VERSION} --repo fabriziosalmi/proxxx \
--pattern "proxxx_${VERSION}-1_amd64.deb" # or _arm64.deb
sudo apt install ./proxxx_${VERSION}-1_amd64.deb # or: sudo dpkg -i proxxx_*.deb
proxxx --versionVerify its signature exactly like the tarball — cosign verify-blob --bundle proxxx_${VERSION}-1_amd64.deb.cosign.bundle … with the same --certificate-identity-regexp / --certificate-oidc-issuer as above.
Quick start
proxxx init --interactive # 5-step wizard: prompts for URL, auth, TLS, optional
# SSH + Telegram, validates each input against the
# live cluster before write. Recommended for first
# run — wrong field caught here, never lands in TOML.
proxxx init # non-interactive variant: writes a commented
# starter config.toml; refuses to overwrite — pass
# --force if you mean it. Edit url / user /
# token_id / token_secret manually after.
proxxx ls nodes # validates the connection.
proxxx # TUI (no args). Press ? for the keymap; the
# bottom-row footer shows contextual binds always.
proxxx --help # full subcommand list.
proxxx version --json # build + capability metadata.The starter config.toml carries inline comments for every secret-resolution path (CLI flag → env var → 0600 file → OS keychain). Optional sections — HITL via Telegram, SSH layer, PBS, alerts, policies — are commented out so the API-only operator doesn't have to delete anything.
Daily-driver TUI
Run with no arguments. Vim keys, fuzzy search across the cluster (/), command palette (:), quick-open palette (Ctrl+K). 18 views over the same Elm-pattern reducer:
|
|
|
|
|
|
|
|
|
|
|
|
Plus a read-only fleet view (proxxx fleet) that aggregates every configured profile into one screen — ↑↓ select cluster, Tab toggle guest pane, Enter drill into a cluster, q quit.
Multi-select + bulk ops with pre-flight risk preview. Operation queue with dry-run, diff preview, replay-as-script export (proxxx CLI / pvesh / curl / Ansible), and HITL approval gate (Telegram, policy-driven).
The terminal is restored on every exit path — happy, ? early-return, panic. RAII TerminalGuard plus a flight-recorder panic hook installed in main() before the runtime starts.
Pipeline-friendly CLI
# Read
proxxx ls guests --format json | jq '.[] | select(.status == "running") | .vmid'
proxxx ha preview --node pve1 # failover what-if
proxxx hw conflicts --node pve1 # PCI passthrough audit
proxxx perms root@pam --node pve1 # effective permissions# Write — every destructive op routes through the pre-flight risk gate
proxxx start 100 101 102
proxxx delete 100 --yes
proxxx migrate 100 pve2 --yes
proxxx snapshot create 100 --name pre-upgrade
proxxx disk move 100 --disk scsi0 --storage ceph-rbd --yes
proxxx patch apply --reboot=auto --dry-run# Console handoff
proxxx ssh 100 # interactive ssh into guest (system ssh +
# QGA / lxc-interfaces auto-discovery; falls
# back to [ssh.guests."100"] when explicit)
proxxx serial 100 --node pve1 # raw termproxy WebSocket
proxxx spice 100 --node pve1 # writes 0600 .vv, launches remote-viewer
proxxx novnc 100 --node pve1 # opens browser to web UI's noVNC# GitOps loop — export, diff, apply with safety on top
proxxx state export > state.toml # snapshot cluster state
git add state.toml && git commit -m snapshot # version it
$EDITOR state.toml # declare intent
proxxx state diff state.toml # preview drift, exit 2 if any
proxxx state apply state.toml --dry-run # rehearse, never mutates
proxxx state apply state.toml --prune # pre-flight refuses Severe (exit 6)
proxxx state apply state.toml --prune --interactive # per-Severe [y/N] prompt
# Continuous reconciliation — the GitOps controller (Layers 1–3)
proxxx reconcile run --source git@host:cluster.git # CI drift gate, exit 2 on drift
proxxx reconcile converge --source git@host:cluster.git --dry-run # rehearse the converge
proxxx reconcile converge --source git@host:cluster.git --prune # push-mode: converge prod
# Unmanned: set `auto_converge = true` under [profiles.X.reconcile] + run `proxxx daemon serve`# Cross-cluster fanout + cluster digest
proxxx find 100 # which profile owns VMID 100?
proxxx ls guests --all-profiles # every guest across every cluster
proxxx fleet # read-only TUI: ALL profiles in one screen
proxxx describe --output llm-context # paste at top of an LLM chat
proxxx accounting --group-by pool --timeframe month # CPU-hours / GiB·h / net-GiB
proxxx heatmap # per-node API RTT, color-bucketed
proxxx anomaly --threshold 3 # z-score outliers on CPU + mem%
proxxx logs tail --service pveproxy --since "1 hour ago" # cross-node journalctl# Incident lockdown + upgrade pre-flight
proxxx incident freeze --reason "rotating token" --ttl 4h # halt every mutation cluster-wide
proxxx incident status --output json
proxxx incident thaw --reason "rotation complete"
proxxx upgrade-check --target 9.x # exits 1 on any block-severity finding
proxxx explain freeze-refusal # bundled error knowledge base# Console handoff + session recording
proxxx ssh 100 # interactive ssh into guest (auto-discovery)
proxxx serial 100 --node pve1 --record # raw termproxy WebSocket + asciinema cast
proxxx play-cast ~/.../sessions/<ts>-100-serial.cast --speed 2
proxxx spice 100 --node pve1 # writes 0600 .vv, launches remote-viewer
proxxx novnc 100 --node pve1 # opens browser to web UI's noVNC# Long-running daemon — alerts + HITL + schedule under ONE process
proxxx daemon serve # all three with one SIGTERM
proxxx daemon serve --no-hitl # alerts + schedule only
proxxx schedule add --name nightly-snap --every 1d --cmd "vm snapshot 100 --yes"
# MCP for AI agents (stdio JSON-RPC, HTTP/SSE for streaming)
proxxx mcp serve # stdio + interleaved server-sent notifications
proxxx mcp serve-http --bind 0.0.0.0:8080 # HTTP/SSE transport
proxxx mcp tools --checksum # registry SHA-256 for audit pinningExit codes are stable contract — see docs/reference/exit-codes.md for the full table.
Configuration
Default location follows the directories project-dirs convention:
Platform | Path |
Linux |
|
macOS |
|
Secrets resolve in order: CLI flag → PROXXX_TOKEN_SECRET env → token_secret_file (0600 enforced) → inline TOML → OS keychain. Loaded values live in Zeroizing<String> and are wiped from the heap on Drop.
Optional section | Unlocks |
| HITL approvals + alert routing |
| Patching orchestrator, |
| Per-guest SSH overrides (optional — |
| PBS browse + restore |
| Alerting daemon — |
| HITL gating rules — match by tag / vmid / wildcard |
Per-profile, set read_only = true to refuse all mutations on that profile client-side (reads unaffected, exit 8) — pair with a PVEAuditor PVE token for a server-side lock. See the configuration guide.
Quality gate
Eight stages, run as both a pre-commit hook and the CI contract in .github/workflows/ci.yml.
Stage | What | Time |
0 | secret regression scan | <1 s |
1 |
| ~3 s |
2 |
| 10–60 s |
3 |
| 3–5 s |
4 |
| 2–4 s |
5 |
| 10–90 s |
6 |
| ~30 s |
7 |
| ~60 s |
End-to-end wall time against a reachable cluster: ~340–480 s.
git config core.hooksPath .githooks
chmod +x scripts/gate.sh .githooks/pre-commit .githooks/pre-push
cargo install cargo-audit --locked
cargo install cargo-deny --lockedThe clippy [lints.clippy] block in Cargo.toml denies unwrap_used, expect_used, panic, todo, await_holding_lock in production code.
Architecture
Pure Elm-pattern TUI over a typed REST client. The reducer is sync, total, and tested without a runtime.
crossterm key tokio::mpsc<DataMsg>
user ─────────────────► event::map_key ─► Action
│
▼
app::update(state, action)
│
┌─────────────┴────────────┐
▼ ▼
AppState mutation Option<SideEffect>
│
▼
enforce_preflight → check_hitl
(risk gate) (Telegram round-trip)
│
▼
ProxmoxGateway / PbsGateway / SshPoolModule | Responsibility |
Pure reducer. No I/O, no async. ~70 | |
| |
| |
GitOps loop — model + export + diff + apply + preflight, ten state families (pools, ACL, storage, backup-jobs, firewall-cluster, notifications, HA rules, HA resources, PCI/USB mappings), byte-stable TOML. | |
PBS REST browse + | |
| |
SQLite-backed time-travel cache, drives | |
11 risk variants with per-op weighting and | |
Real Telegram round-trip via | |
JSON-RPC server with stdio + Streamable HTTP transports. Compile-time-fixed tool registry (25 tools). Surface SHA-256 pinned via | |
|
Documentation
VitePress site —
docs/and the live build. Local preview:cd docs && npm install && npx vitepress dev.CHANGELOG.md— what shipped, with the SemVer contract for CLI / JSON / config / MCP registry surfaces.pre-commit/— four matrices distinguishing implemented from verified end-to-end:01-feature-coverage.md·02-error-handling.md·03-security-invariants.md·04-resiliency-and-chaos.md·ACCEPTED-RISKS.md(AR-1..AR-6 residual risks)ARCHITECTURE.md— one-page module map + data flow + reducer/side-effect bus + process model.THREAT_MODEL.md— attack surfaces, mitigations, accepted risks, verification ladder.SECURITY.md— vulnerability reporting policy + scope + hardening snapshot.CONTRIBUTING.md— onboarding, the gate, live-cluster verification format..cargo/audit.toml— supply-chain advisory ignore policy.deny.toml— cargo-deny policy: license whitelist + banned crates + source lock.
Live cluster harness
tests/live/ drives the release binary against a real PVE cluster — separate from the cargo integration tests in tests/ which use wiremock.
File | Tracked | Purpose |
✓ | 67 read-only probes covering the full CLI surface; logs to | |
✓ | 34 mutation probes with | |
| — | Generated by the harness |
Honest non-goals
Design boundaries — proxxx will not ship these.
No GUI. Proxmox already has a web UI; proxxx is for terminal users who want CLI / TUI / scripting parity.
No frame rendering for graphical SPICE or VNC. proxxx hands off to
remote-viewer/virt-viewer(SPICE) or the system browser (noVNC). It never holds pixel buffers.No re-implementation of Perl algorithms in Rust where the Perl on the node is the ground truth.
proxxx permsshells out topveum user permissionsover SSH and parses, since thepve-access-controlevaluator is canonical. The API-sideproxxx access permissionsis also available — same typed tree from/access/permissions, no SSH dependency — for the common case where the evaluator's full expansion isn't needed.No new dependencies for trivial things. Three-line per-platform
Command::newbeats pullingopenerfor a launcher.No multi-cluster writes from one TUI. The interactive per-cluster TUI is single-profile-per-process by architectural decision (switch with
--profile); every mutation targets exactly one cluster. The read-onlyproxxx fleetview does aggregate every configured profile into one pane — but it stays strictly read-only and drills into a single-profile TUI (Enter) to act. The boundary is writable aggregation, not aggregation itself.No Ceph cluster writes. Operators reach for the
cephCLI directly on the node where the kernel module is loaded; proxxx wraps Ceph reads (status, metadata, flags) but not destructive ops (osd add/down, mon create, pool prune).No SDN config writes. PVE SDN is opt-in cluster config that few clusters enable, and the wire shape changes between PVE versions. Skipped rather than ship a fragile surface.
No browser-only auth flows. U2F/WebAuthn registration and OIDC's redirect-callback dance both need a browser to drive them. proxxx exposes the API-driven primitives (token CRUD, password change, ACL editing) but stays out of
/access/openid/*and/access/tfa/u2f— there's no terminal UX for those that beats the web UI.No snapshot rollback as a destructive trigger. The snapshot-tree TUI shows a read-only rollback impact preview (what would be discarded + time delta); the actual rollback runs through
qm rollback/pct rollbackor the PVE web UI. Read-only inspector views never expose destructive entry points by design.
License
MIT. Copyright © 2026 Fabrizio Salmi. See LICENSE.
This server cannot be installed
Maintenance
Resources
Unclaimed servers have limited discoverability.
Looking for Admin?
If you are the server author, to access and configure the admin panel.
Related MCP Connectors
Run commands and read/write files on your servers over Termalin's keyless tunnels (hosted MCP).
Go MCP server for GitLab: 2 dynamic tools reach 1000+ REST/GraphQL actions. Free/CE, no paid tier.
Manage CloudPepper servers, Odoo instances, backups, and deployments over MCP.
Let AI operate servers without SSH. Choose actions, approve risky changes, and audit every step.
Related MCP Servers
- AlicenseAqualityAmaintenanceMinimal MCP server for Proxmox VE — 38 tools for nodes, VMs, LXC, storage, and snapshots. Read-only by default, single Docker image, multi-arch.382MIT
- AlicenseAqualityBmaintenanceMCP server for Proxmox VE and Proxmox Datacenter Manager, covering every API endpoint via six consolidated tools for list, describe, and call operations with a read-only safety gate.6311AGPL 3.0
- AlicenseNot gradedqualityAmaintenanceA PROXMOX implementation containing 152 tools covering QEMU VMs, LXC, unified guest power, storage admin, cluster/tasks, snapshots, backups (incl. scheduled jobs), migration, HA, firewall (incl. IPSet CIDRs), access control, replication, SDN (read), ACME (read), pools, and console tickets.1MIT
- FlicenseNot gradedqualityBmaintenanceManages Proxmox VE clusters through the official PVE API with 22 tools for cluster status, VMs/containers, storage, snapshots, and provisioning. Supports stdio or HTTP/StreamableHTTP transports with optional OAuth for Gemini and multi-server configurations.
Latest Blog Posts
- Who's Calling? MCP Hosts Are an Identity Blind Spot (And the Spec Knows It)By Om-Shree-0709 on .mcpAgent IdentityOAuth 2.1
- Your AI Chatbot Just Exposed Your CEO's Salary to an InternBy Om-Shree-0709 on .Agent IdentityMCP SecurityOAuth Delegation
- Why MCP Servers Need Execution Sandboxing (And Why Your Current Stack Isn't Enough)By Om-Shree-0709 on .Agentic AiPrompt InjectionWebAssembly
MCP directory API
We provide all the information about MCP servers via our MCP API.
curl -X GET 'https://glama.ai/api/mcp/v1/servers/fabriziosalmi/proxxx'
If you have feedback or need assistance with the MCP directory API, please join our Discord server