Getting started

Architecture

Vortexa is a master/worker system. The master runs the web console, the API and the database; workers run a small Python agent that provisions and reports. Everything between them is mutually authenticated.

Control plane

master / worker · mTLS

Clients

BrowserHTTPS · secret path slug
Telegramstorefront & admin alerts
End-user clientVPN traffic — never via panel
requests

Master VPS

nginxTLS termination
autoscript-webweb console
autoscript-agentFastAPI + scheduler
autoscript-botTelegram bot
SQLitesource of truth
local-01built-in local node
mTLS RPC · panel → node
signed heartbeat every 15s · node → panel

Worker nodes

Node VPS #1

autoscript-nodexrayssh / dropbearssh-wsstunnelzivpnnginx

Node VPS #2

autoscript-nodexrayssh / dropbearssh-wsstunnelzivpnnginx
control plane
                      ┌───────────────────────── MASTER VPS ─────────────────────────┐
  browser ──HTTPS──▶ │  nginx  ──▶  web console (autoscript-web)                     │
                     │            └▶ FastAPI agent API (autoscript-agent) ──▶ SQLite │
  Telegram  ────────▶│  telegram bot (autoscript-bot)                                │
                     │  local node "local-01"  (always online while panel runs)      │
                     └──────────────┬──────────────────────────────┬─────────────────┘
                                    │ mTLS RPC (panel → node)      │ signed heartbeat (node → panel)
                     ┌──────────────▼──────────────┐  ┌────────────▼────────────────┐
                     │  NODE VPS (agent)           │  │  NODE VPS (agent)           │
                     │  xray · ssh/dropbear ·      │  │  ssh-ws · zivpn · nginx     │
                     │  stunnel · nginx            │  │                             │
                     └──────────────┬──────────────┘  └────────────┬────────────────┘
                                    │  VPN traffic                  │
  end user client ─────────────────▶┴───────────────────────────────┘
  • The master never runs the standalone node code from node/ — it auto-registers itself as local-01 and is considered online while the panel process is up.
  • Only remote worker boxes run the node agent, installed with the node one-liner.
  • End-user VPN traffic goes straight to the node it was provisioned on. The panel is a control plane, not a data path.

The installer deploys everything as systemd units. Knowing the unit names is most of troubleshooting.

On the master

UnitRole
autoscript-agentFastAPI API the web console talks to
autoscript-webWeb console server on a random internal port behind nginx
autoscript-botTelegram bot process
autoscript-ssh-wsSSH-over-WebSocket bridge
autoscript-stunnelTLS wrapper for SSH/stunnel port sets
autoscript-ip-limit.service / .timerPeriodic device (concurrent IP) enforcement
nginxTLS termination, panel vhost, / upgrade for SSH-WS

On each node

UnitRole
autoscript-nodeNode agent: handshake, heartbeat, mTLS RPC server
autoscript-node-ssh-wsSSH-over-WebSocket bridge on the node
autoscript-node-stunnelTLS wrapper for the node's SSH/stunnel port set
autoscript-node-logclean.service / .timerPeriodic log rotation and cleanup on the node
check the stack
systemctl status autoscript-agent autoscript-web autoscript-bot nginx
journalctl -u autoscript-agent -n 200 --no-pager

# on a node
systemctl status autoscript-node
journalctl -u autoscript-node -f
/opt/autoscript
Checked-out release: backend, node payload, built web bundle
/etc/autoscript/agent.env
Master environment: panel port, path slug, secrets (root-only)
/etc/autoscript/db.sqlite
Default database path (chosen at install)
/etc/autoscript/panel-credentials.txt
Generated panel URL + admin credentials, mode 600
/etc/default/autoscript-node
Node environment: NODE_ID, MASTER, AGENT_PORT
/usr/local/bin/autoscript
Admin CLI
/root/autoscript-backup-<timestamp>.tar.gz
Default location for panel backup archives
/var/log/autoscript-repair.log
Output of the automatic service-repair routine

Credentials are root-only

agent.env and panel-credentials.txt hold admin credentials and signing secrets. Never move them into a web-served directory or a git repo.

The installer resets ufw to deny-inbound and then opens exactly what the stack needs. Panel and local-node API ports are randomised so they never collide with the CDN-friendly VPN port sets.

Port setValuePurpose
TLS ports (default)443, 2053, 2083, 2087, 2096, 8443Cloudflare-proxyable TLS entrypoints for VMess/VLESS/Trojan
Plain ports (default)80, 8080, 8880, 2052, 2082, 2086, 2095Cloudflare-proxyable plaintext/WS entrypoints
Panel portrandomised at installHTTPS web console + API (autoscript set-port)
Local node API portrandomised at installmTLS RPC for the master’s own local-01 node
22/tcp22System SSH, always allowed

Node agent port is IP-locked

The node installer resolves the panel host from $MASTER and inserts a GRVPN_AGENT iptables/ip6tables chain that only accepts the panel’s IPv4/IPv6 addresses on the agent port. Changing the panel IP requires re-running the node’s firewall step.

Browser → panel

Nginx terminates TLS on the panel port and proxies to the internal web server and the FastAPI agent. The console lives under a secret path slug (autoscript set-path) so the panel is not discoverable at the domain root, and fail2ban is configured by default.

Node → panel (handshake + heartbeat)

A node bootstraps by POSTing to /api/public/node-handshake on the master with its node id, client-certificate fingerprint and agent port. After that it sends a signed keepalive every ~15 seconds carrying CPU, RAM and NIC snapshots. The panel marks a node offline when heartbeats stop arriving.

Panel → node (RPC)

For anything that changes node state — provisioning an account, reloading Xray, applying certs, syncing ZIVPN users, running a benchmark — the panel calls the node agent’s mTLS HTTPS server on the agent port. The certificate pinned at handshake time is the identity; a node whose fingerprint changes must be re-approved.

Updates

The panel cannot update itself from the web UI. Updates are performed on the VPS with autoscript update, which installs the latest published release of the official repository, runs migrations and restarts the stack.

  • SQLite on the master is the single source of truth for accounts, nodes, plans, invoices, wallets, settings and audit logs.
  • Nodes hold derived state only: Xray config, SSH system users, ZIVPN users.json, certs. Anything on a node can be rebuilt from the panel by re-syncing.
  • Counters are deltas. Node agents scrape cumulative traffic counters and report deltas, so a service restart or counter reset does not double-count or go negative.

Every master/node interaction goes through a small, fixed contract. Node → master calls land on public routes; master → node calls hit the agent's mTLS RPC server.

Node → master (public, signed)

EndpointPurpose
POST /api/public/node-handshakeFirst-boot enrolment; pins the node client certificate
POST /api/public/node-heartbeat15s keepalive with CPU, RAM and NIC telemetry
POST /api/public/node-webhookAsync events: strikes, cert renewal, job results
POST /api/public/node-ssh-usageSSH/dropbear session and traffic usage batches
GET /api/public/node-install/<token>One-time install script fetched by the node one-liner
GET /api/public/node-agent.tar.gzNode agent payload served to workers
GET /api/public/node-agent-versionVersion probe used by autoscript-node-update
POST /api/public/node-uninstallNode self-deregistration when uninstalled
GET /api/public/master-baselineBaseline config the node applies after enrolment
POST /api/public/master-user-usageAggregated per-user usage deltas

Master → node (mTLS + bearer)

EndpointPurpose
POST /rpc/users.applyFull or partial user set for Xray, SSH and ZIVPN
POST /rpc/config.applyPush hosts matrix, port sets and SNI overrides
POST /rpc/service.restartRestart xray / nginx / zivpn / the agent itself
GET /rpc/status · /rpc/ping · /rpc/node.healthReachability, status snapshot and health checks
POST /rpc/node.config · node.restart · node.rebuildRe-apply node config, restart or rebuild the node
POST /rpc/xray.install · xray.versionInstall or report the Xray core version
POST /rpc/cert.issueIssue or renew TLS certificates on the node
POST /rpc/firewall.apply · system.tuneFirewall chains and kernel/network tuning
POST /rpc/net.probe · net.speedtestLatency probes and bandwidth benchmarks
GET /rpc/logs · POST /rpc/logs.purgeFetch or trim node logs
POST /rpc/traffic.reset · vpn.haltReset counters, halt VPN services
POST /rpc/agent.update · agent.update_safe · agent.stop · GET /rpc/agent.versionNode agent lifecycle
GET /rpc/wsWebSocket channel for live streams (logs, stats)

Both factors are required

Every RPC needs a client certificate issued by the master's private CA and the Authorization: Bearer secret shown on the panel's Nodes page. Missing either one is rejected before the handler runs.

Besides the request path, the master runs scheduled work. Most “it fixed itself” behaviour comes from these.

WorkerWhereWhat it does
Scheduler loopinside autoscript-agentExpiry sweeps, renewals, plan/quota enforcement and queued jobs
Heartbeat cache refresherinside autoscript-agentKeeps the last-known node telemetry hot for the dashboard and map
autoscript-ip-limit.timermasterEnforces concurrent-device (IP) limits on a schedule
repair-servicesmaster CLIRestarts unhealthy units, logging to /var/log/autoscript-repair.log
autoscript-node-logclean.timernodeTrims node logs so small worker disks do not fill
autoscript-node-updatenode (via RPC)Pulls the matching node release when the panel triggers an update