One hub on one machine, one small agent on every server — added with a single line — and an API your backend calls. It installs PHP, Nginx and databases, builds Kubernetes clusters and load balancers, deploys with rollback, watches, alerts and backs up.
gea-hub lives on one machine and is the only address your backend talks to. gea-agent is the part that goes on every server you want to manage — web, database, load balancer, Kubernetes node. You do not copy it there by hand: the hub hands it out.
# 1 · on the admin server, once
sudo DOMAIN=ops.shop.vn EMAIL=ops@shop.vn \
sh deploy/setup-hub.sh
# GEA_OPS_URL=https://ops.shop.vn
# GEA_OPS_APP=ops
# GEA_OPS_SECRET=… (shown once)
# 2 · your backend, for each server
POST /api/agents
{ "id": "web1", "profile": "full",
"labels": { "role": "web", "env": "prod" } }
# → install.one_line
# 3 · on that server, as root
curl -fsSL https://ops.shop.vn/install/3f9c…e1 | sudo sh
# gea-agent: web1 → https://ops.shop.vn
Profiles: full (may install and change), standard (deploys and services), monitor (reads only). The link holds the server's token, works once and dies after 24 hours. Ubuntu or Debian with systemd, amd64 or arm64.
Every agent reads its own server — Nginx sites, .env files, containers, databases, Kubernetes — and the hub joins them. Your backend draws this from GET /api/topology.
POST /api/agentsOne line to paste on the server; the agent installs itself and reports in.POST /api/blueprints/web.phpPHP-FPM, Nginx, the site, HTTPS — a plan of ops you can follow step by step, or preview with dry_run.GET /api/overviewEvery server: CPU, RAM, disks, services down, failing checks.GET /api/graph · /api/topologyDomains → load balancers → servers → apps → databases, with the connections actually seen between servers.GET /api/impactIf this server or database stops, which apps and domains go with it.GET /api/series · /api/capacity10-second points for 6 hours, minute points for 30 days; when a disk will be full.POST /api/agents/{id}/ops/{op}The agent checks allow / deny, runs it without a shell, reports progress, returns data — or a code and the fix.POST /api/ops/{op}The same op on a label (role=web) or a list, one batch to follow.release.deploy · compose.deploy · k8s.deployHealth checked; the previous version comes back by itself on failure.db.mysql.create · db.pg.user.createDatabases, accounts and grants; the password goes back to you once and is masked in the log.PUT /api/lbs/{name}Nginx + HTTPS written and tested; the pool follows servers going and coming.POST /api/blueprints/backup.scheduleNightly dumps and encrypted snapshots run on the server itself; an incident opens when a backup is late.PUT /api/notify/channels · /rulesservice.down, check.fail, agent.offline, disk over 85 % — to Telegram, Slack, Discord, e-mail or your webhook.diag.collect · log.search · GET /api/timelineThe state of the server, the log lines and what changed just before.GET /api/tasks · X-Gea-UserWho ran what, on which server, when and why.Kubernetes: install gea-agent on a machine with kubectl and a kubeconfig for the cluster (a bastion or one node). What it may do inside the cluster is the RBAC of that kubeconfig; a refusal comes back as os_permission with the binding to create.
Everything below is an op or an endpoint your backend calls — nobody logs in to a server.
PHP-FPM, Nginx, MySQL, PostgreSQL, MongoDB, Redis, Docker, Node.js, Python, Go — installed by an op, or a whole role by one blueprint: web.php, web.node, web.python, web.go, db.mysql, db.postgres, db.mongodb, cache.redis.
Domain → load balancer → server → site → app → which database, which Redis, which container, and who talks to whom. Found by itself; passwords never leave the server. Ask what breaks if one server goes down.
CPU, RAM, disks, inodes, I/O, network every 10 s; services up or down; site checks with certificate days left; errors counted in logs. 30 days of history, capacity trends, what changed and when.
Rules on events and on metrics send Telegram, Slack, Discord, e-mail or a signed webhook; an incident opens, is acknowledged, closes by itself when the value is back.
Plain servers: releases / shared / current with a health check and the previous release back on failure. Compose, Kubernetes and Helm the same way. Progress while it runs; a running op can be cancelled.
Containers, logs, stats, exec, images, volumes, networks, builds, registries, prune — and compose up / pull / logs / deploy.
Create a k3s cluster from empty servers (blueprint k8s.cluster), then nodes, drain, apply, diff, scale, autoscale, rollouts, ConfigMaps, Secrets, jobs, cert-manager, Helm releases.
Type the domains and the backends — IPs, host names or every server labelled role=web. HTTPS from Let's Encrypt; offline servers leave the pool and come back on their own.
Create databases, accounts and grants on MySQL and PostgreSQL, accounts on MongoDB; dumps and restores; slow queries and sizes. Nightly dumps and encrypted restic backups with real restore checks, on a schedule.
Nginx sites with HTTPS, PHP / Node / Python / Go apps as systemd services, Linux users, SSH and deploy keys, cron lines, scheduled jobs that keep running when the hub is away.
One op collects the state of a server at the bad moment; search logs, probe ports, read slow queries, Kafka lag and RabbitMQ queues; one timeline of events, deploys and changes.
Firewall, CrowdSec bans, certificates, SSH settings, failed logins, pending updates, Trivy and Lynis. Keys limited by role, op, server and IP; a second signature the hub itself cannot forge.
Ops that only read are always allowed. Ops that change things must be allowed in that server's own config — the backend alone can never widen them. The answer names the file, the line and the commands:
{
"ok": false,
"code": "not_allowed",
"error": "this server does not allow service.restart yet",
"fix": {
"file": "/etc/gea-ops/agent.json",
"key": "allow", "add": ["service.restart"],
"commands": [
"sudo nano /etc/gea-ops/agent.json",
"sudo systemctl restart gea-agent"
]
}
}
Same for a missing tool (with its install commands), a stopped Docker daemon, a path outside the allowed folders, cluster RBAC, a database login, a timeout.
$ops->saveLb('shop', [
'nodes' => ['lb1'],
'domains' => ['shop.vn', 'www.shop.vn'],
'backends' => [
'labels' => ['role' => 'web'],
'addrs' => ['10.0.0.30 backup'],
],
'tls' => true, 'email' => 'ops@shop.vn',
]);
The hub finds each server's address, writes the Nginx config, tests it before reloading, gets the certificate, and keeps the pool right as servers come and go.
349 ops in 33 groups, 195 of them change something and must be allowed on the server. Every op has a name, typed arguments, a timeout and a description; GET /api/catalog lists them, API.md documents them, and your backend can draw its forms from them.
gea-hub · gea-agentLinux amd64 and arm64, with checksums and the Go sourcedeploy/setup-hub.shthe hub in one commandREADME.mdinstall, upgrade, what was testedAPI.mdevery endpoint, key and op, with recipesopenapi.json · api.jsonthe same, for machines and AIphp/GeaOps.phpa ready client for PHP backendsPOST /api/agentsadd a server → the one-line installPOST /api/blueprints/{name}build a whole role: web, database, clusterPOST /api/agents/{id}/ops/{op}run any of the 349 opsPOST /api/plansseveral ops in order, results passed onGET /api/graph · /api/impactwhat exists, what depends on whatGET /api/overview · /api/serieslive numbers and history for chartsGET /api/events · /api/timelinewhat happened, plus a signed webhookPUT /api/notify/rules/{name}who is told about whatPUT /api/lbs/{name}create a load balancerPOST /api/keyslimited keys for each part of your systemGET /openapi.json · /api/catalogthe whole API, machine-readable75 endpoints in all. Every request is signed with HMAC; every answer is JSON; every error has a code and a fix.
Honest limits: the installers are for Ubuntu and Debian (no RHEL / CentOS yet); Kafka and RabbitMQ are read-only; there is no request tracing and no cloud-provider API or cost data; connections between servers are sampled every 5 minutes, not continuously; the hub runs on one machine — back up /var/lib/gea-hub.
From $59, lifetime. Free updates. Unlimited projects on your own server.