GitHub Actions or GitLab CI deploys over SSH

The second-largest segment on Hetzner deploys with a CI job over SSH. The webhook adapter keeps that job: Hetscale tells it where the new server is, the job deploys, the load balancer decides when the node may serve.

Prerequisite work
deploy to the IP Hetscale sends
Time to set up
1–2 h
Adapter
Webhook
Fit
8/10

Prerequisites, time and fit are the ADR-0028 row for this case. Hetscale's own setup is about 15 minutes in every case; the rest is work on your side.

Steps

  1. 01
    Receive node.created

    Hetscale sends a signed node.created event with the node id, its IPs, the group and the current release when a server is booted and reachable. Deliveries are idempotent by node id, so a duplicate is safe.

  2. 02
    Run your deploy against that IP

    Trigger the workflow you already have (for GitHub Actions, a workflow_dispatch recipe) with the IP as input. Your SSH key stays in your CI; Hetscale never holds it.

  3. 03
    Optionally report ready or failed

    A ready callback speeds the decision up and a failed callback stops it at once, but traffic opens only when the load balancer health check passes; the callback is never the source of truth.

  4. 04
    Rebuild host lists from the inventory API

    GET /groups/{id}/nodes returns the current nodes with phase, IPs and release. Use it instead of a hand-kept host list.

  5. 05
    Hold a deploy lock during your own rollouts

    POST /groups/{id}/lock with a TTL pauses scaling while your pipeline rolls the fleet; the lock expires on its own if the pipeline dies.

  6. 06
    Observe, rehearse, go Live

    Read-only trial first; then one Rehearsal, which exercises the webhook end to end; then Live with minimum 2.

FAQ for this case

What if my pipeline never reports back?

The load balancer decides anyway. A node that is not healthy within the deadline (default 15 minutes) is destroyed and logged with the load balancer’s reason; three consecutive failures pause the group.

We have no load balancer yet.

Then this is the “CI/SSH deploy, no LB” row of the fit table: add the Hetzner load balancer first (TLS to it, DNS to it) and teach the pipeline the IP. Two to three hours, fit 6.

See what Hetscale would have done with your real data — connect read-only, get your report in minutes.

Connect read-only