How Hetscale works
Hetscale watches a node group behind your load balancer, adds a node when load rises, replaces one when it dies, and removes what is no longer needed. Every step has a rule that keeps it safe, and every action carries its reason.
- Autoscaling and self-healing for the Hetzner servers you already run
- No Kubernetes, no migration: your account, your deploy tool, your traffic path
- Your traffic never passes through Hetscale
- Works with Docker or cloud-init, Coolify, and any webhook or CI
- Try it read-only first: 14 days of Observe on a read-only Hetzner token, no card
What you get
- Every planAutoscalingAdds the nodes the load needs when CPU, requests or open connections stay high, removes one at a time when load stays low. Thresholds and warm-up are yours per group.
- Every planSelf-healingReplaces a node that stays unhealthy; the failed one never leaves before its replacement serves.
- Every planHealth gateNo node receives traffic before your load balancer’s own health check passes.
- Every planCost guardA cap on how many nodes a group may create in a window, plus a maximum node count. When it trips, nothing more is created and you are alerted.
- Every planLocation fallbackType sold out? Hetscale tries the other locations of the zone; as an opt-in it tries larger types until your type is back: up to three in your order, or the cheapest in stock under your price cap. Never weaker, never another zone.
- Every planDrain, pause, emergency stopOut of the load balancer first, a drain window you set, then a clean shutdown. Pause a group, or stop every create and delete in it.
- Every planFour modesObserve, Rehearsal, Propose, Live. Start read-only; moving to a safer mode takes effect immediately.
- Every planAction logEvery action carries its trigger, the metric values and the rule that fired.
- Every planAudit logEvery change by your people, their tokens and Hetscale’s writes to Hetzner, sealed into a hash chain within a minute. Every plan keeps a year; Team exports it.
- Pro and aboveScheduled scalingScale on a schedule you set, for the peaks you can predict.
- Pro and above, plannedPre-warm suggestionsWhen the same weekday ramp shows up in your history and autoscaling arrived late, Hetscale proposes a schedule with the minutes it would have covered and its price. One click to apply; letting Hetscale manage it is opt-in.
- Pro and aboveTarget trackingHold one metric at the value you pick, such as CPU at 60%, instead of fixed thresholds.
- Pro and above, plannedCustom metrics agentDecisions on RAM or latency that an optional agent on your servers reports.
- Pro and aboveSlack and Discord alertsEach alert batch of the mail, also in a Slack or Discord channel, from the level you choose.
Need a planned feature sooner? Write to support@hetscale.com with your case.
What differs between plansWhat you set up
A node group is the set of servers behind one Hetzner Load Balancer (a Cloudflare Load Balancing pool is planned) that run the same stateless application. You give it three things: a range (the fewest and the most nodes it may run), a release to boot new nodes from (a snapshot or an image digest) and an adapter (how a new node gets your application). The server you already run becomes the group's seed: it counts toward capacity, keeps its price and is never scaled in or replaced.
Hetscale's own setup is about 15 minutes (estimate). What your setup needs first, and how long it takes, is on the onboarding cases: Find your starting point.
The loop, step by step
- 01Monitorcpu 78% · 3 min
- 02Decide> 75% → +1 node
- 03Provisioncreate web-4
- 04Deploypinned release
- 05VerifyLB check 3×
- 06Routetarget added
- 07Healweb-2 kept
- 08Drainno new requests
- 09Destroy3 checks, delete
- 01Monitor
Reads CPU per node and the request and open-connection metrics from the load balancer through the Hetzner API, once a minute while your Hetzner project holds up to 25 nodes and less often per node above that, so polling never uses up your API budget.
Rule Missing, stale or rate-limited metrics stop decisions. A gap in data is never read as "a server is gone" and never leads to a scale-in.
- 02Decide
Compares the readings with the group’s policy. Defaults: scale out when CPU stays above 75% for 3 minutes, adding the nodes the load needs within the group’s rate cap and per-hour cost guard; scale in when it stays below 35% for 10 minutes, one node at a time, after a cooldown and only if the remaining nodes stay under the scale-out threshold. All of them are yours to change per group.
Rule Scale-in is always stricter than scale-out. A decision is checked against the group’s current release and template before it runs; if either changed in between, it is dropped and made again.
- 03Provision
Creates the server in your Hetzner project with the type and location you prefer. If that type is not available there, Hetscale tries the other locations of the same network zone; as an opt-in, it falls back to same-or-stronger types (the same architecture, at least the cores, memory and disk): up to three you list, in your order, or the cheapest in stock within a monthly price cap you set, and replaces each such server with your type once it is back in stock. Never a weaker type, never another zone. When the whole chain is exhausted the group is marked in capacity deficit and you are notified; the type Hetscale would recommend is shown, not applied.
Rule Every server it creates is labelled and named as Hetscale’s from the first second, and the intent to create is recorded before the call, so a retry never produces a duplicate.
- 04Deploy
Gets your application onto the node through the adapter you chose: a clone of your seed’s snapshot, also when Coolify deploys your seed, or a signed webhook to your CI or deploy tool. No agent, no SSH access; the one thing Hetscale sends with a new server is a fixed first-boot step that removes Coolify’s monitoring container where there is one.
Rule Always the release you pinned, never
:latest. The group screen shows the release new nodes boot from and how old it is, and warns before they boot from a stale snapshot. - 05Verify
Waits for your load balancer’s own health check to pass on the new node.
Rule No node receives traffic before the load balancer says it is healthy. A node that is not healthy after 15 minutes (default) is destroyed and you are alerted; three failures in a row pause the group instead of burning through servers. While healing waits out a fault every server shares, failures do not count.
- 06Route
Your load balancer sends the node its share of requests. Hetscale added it as a target when it booted, or with the webhook adapter once your pipeline reported it ready; the passed health check opened its traffic.
Rule Requests go from your load balancer to your servers, as they do today. Nothing passes through Hetscale, and nothing about the traffic path changes when Hetscale is unavailable.
- 07Heal
When a node stays unhealthy for 3 minutes and Hetzner does not report it rebooting or in maintenance, Hetscale starts one replacement beside it from the current release, waits for it to pass the health check and routes to it. Capacity is added before anything is removed.
Rule In a group with a minimum of 2 or more, a failed node Hetscale created, or a seed you promoted, leaves only after its replacement serves and the group’s “Keep a failed server” time has passed; its diagnostics are recorded, then it is drained and deleted. A failed node of a group with a minimum of 1, your seed server and any other server of yours are never deleted: they are kept out of traffic for you to look at. If the replacement fails its health check too, Hetscale stops after that one attempt and alerts you, because two failures in a row point at the release, not the server. The seed server is never replaced: if it dies, you are alerted and a node is started beside it. When every server of a group with a minimum of 2 or more fails at once, the cause is something they share, such as the load balancer or a database: Hetscale replaces none of them, alerts you once, and after 10 minutes starts one new server as a test.
- 08Drain
On scale-in the node is removed from the load balancer first, so it gets no new requests while existing ones finish; Hetzner keeps those connections alive for up to 5 minutes. After the drain window you set (default 60 seconds, up to 300) the node gets a clean shutdown signal.
Rule The node to remove is chosen so that Hetzner answers its delete call before its next billed hour begins, which is when Hetzner stops billing it; you do not pay an hour for a node that was leaving. The seed server is never chosen.
- 09Destroy
Deletes the node from your project.
Rule Three checks before every delete: the server is in Hetscale’s ledger as one it created or a seed you promoted, its labels say so, and its name says so. Any mismatch aborts the delete and raises a security alert. Every other server is listed, never shut down or deleted; a server you marked delete-protected in Hetzner is a hard stop.
Four modes. Start read-only, move up when the report convinces you.
The mode decides whether Hetscale may call the Hetzner API. It never changes how a decision is made, or how it is explained.
- [observe] web-2 unhealthy for 3 min
- [observe] would: create web-4 beside web-2
- [observe] would cost: +1 node-hour, billed by Hetzner
- [observe] no API write; token is read-only
The trial mode. While a project only observes, Hetscale holds a Hetzner token with read permission only, so it cannot create or delete anything even by mistake. For 14 days the group page lists every decision it would have taken, set against the day-0 report.
- [rehearsal] create web-4 from template
- [rehearsal] deploy via adapter → wait for LB health
- [rehearsal] web-4 active → drain → delete
- [rehearsal] passed; Live unlocked
A supervised rehearsal before Live: Hetscale creates one short-lived server from your template, deploys through your adapter, waits for the load balancer health check, drains it and deletes it while you watch; Hetzner bills at least one started hour. Success unlocks Live; failure produces a report and never leaves a node behind.
- [propose] create web-5 (cx33)
- [propose] reason: CPU 78% > 75% for 3 min
- [propose] waiting for approval…
- [propose] approved → executing
Each scaling action is proposed with its reason and waits for approval in the dashboard; a mail links you to it. Unapproved proposals expire, and healing acts on its own.
- [live] web-2 unhealthy for 3 min
- [live] create web-4 beside web-2
- [live] web-4 active → LB target
- [live] web-2 kept for diagnosis; 3 healthy
Hetscale creates, health-checks, attaches, drains and deletes nodes within the minimum and maximum you set. Moving back to a safer mode takes effect immediately.
What keeps you in control
- Ownership guardDeletes only servers it created or a seed you promoted: ledger, labels and name must all match.
- Health gateNo node receives traffic before your load balancer says it is healthy.
- Pinned releaseEvery new node boots the release you chose, never :latest. Shown on the group page.
- ProposeApprove each scaling action in the dashboard; unapproved proposals expire.
- RehearsalWatch one node created, checked, drained and deleted before going Live.
- Emergency stopPause a group, or stop every create and delete in it; moving to a safer mode is immediate.
- Action logEvery action carries its trigger, the metric values and the rule that fired.
- web-4draining
- web-3healthy
- web-4 · clean shutdown and deletea server it created
- web-3 · never touchednot in the ledger
When something goes wrong
| Situation | What happens | What never happens |
|---|---|---|
| Hetscale is down | Your servers keep running and your load balancer keeps routing; traffic never depended on Hetscale. No scaling or healing happens until it is back. On reconnect it re-reads the state of your project and continues. | Nothing is deleted on the way back. |
| The Hetzner API is rate-limited or failing | Decisions pause. Polling stops early enough to keep a reserve for the calls that create, drain and delete nodes. | A limit response is never read as a missing server. |
| A create fails | It is retried from its recorded intent; a sold-out type follows the fallback chain above. | A retry never produces a duplicate. |
| You want it to stop | Pause a group, or stop every create and delete in it, from the dashboard; moving to a safer mode takes effect immediately. Revoking the token in the Hetzner Console stops everything. | Nothing on your servers depends on Hetscale. |
After every healing, capacity shortfall or quarantine you get a one-page incident report: what was seen, what was decided, how long each step took. It is on the group's timeline, and the alert mail links to it.
What Hetscale never does
- Never routes, proxies or terminates your traffic
- Never holds an SSH key or runs a command on your servers
- Never shuts down or deletes a server it did not create, even behind the same load balancer, except a seed you promoted
- Never boots a node from
:latest - Never scales in without fresh metrics
- Never stores your Hetzner token in the clear: envelope encryption, and a read-only token while a project only observes
Works with what you have
- adapterSnapshotClones your seed server. Secrets stay inside your own snapshot in your own project.
- adapterWebhookA signed
node.createdevent your CI, deploy tool or shell script acts on. - adapterCoolifyCoolify keeps deploying to your seed; new nodes boot from its snapshot, and Coolify never sees them. No Coolify token. Per-server Coolify deploys are planned.
- trafficHetzner Cloud Load BalancerIts health check gates traffic; its targets are what Hetscale adds and removes.
- trafficCloudflare Load BalancingPlanned. In front of Hetzner servers; the pool’s health check will gate traffic the same way. Until it ships, a Hetzner load balancer behind the Cloudflare proxy is the supported setup.
Adapters ship in that order; no agent on your servers, no SSH access. Whatever the traffic setup, the health check that gates traffic is the load balancer's own. Each adapter's status is in the documentation.
What it costs to run
Your account, your bill, no per-server fee. The seed server you already own keeps its price; new nodes are billed hourly by Hetzner only while they run, and Hetscale's plan is a flat monthly price for the node capacity it covers: no meter, not a fee per server and not a share of your Hetzner spend. Every group shows what autoscaling has cost this month, computed from Hetzner list prices, and the worst case at max — and you can set a euro ceiling.
Estimate with your own numbers: Cost and capacity calculator. The plans are on Pricing.