Skip to content

Latest commit

Β 

History

6 Commits

Folders and files

NameName
Last commit message
Last commit date
Β 
Β 
Β 
Β 
Β 
Β 
Β 
Β 
Β 
Β 
Β 
Β 
Β 
Β 
Β 
Β 

Repository files navigation

πŸ“‘ hetzner-server-radar

Out-of-stock radar for Hetzner Cloud β€” watch Β· match Β· email

Node TypeScript Resend Hetzner

Polls the Hetzner Cloud API for a given server type in a given location and emails you the moment it comes back in stock. A single-file Node script β€” point it at a CX/CCX/CAX type and a datacenter, run it, and walk away.



What it is

hetzner-server-radar is a small watcher for Hetzner Cloud capacity. Popular server types (especially the dedicated CCX line and the cheap CX/CAX types) routinely sell out in specific datacenters; this tool polls the public datacenter API on a fixed cadence and sends an email alert the moment your chosen type is available where you want it.

Defaults: CX33 (id 115) in Nuremberg (nbg1), checking every 5 minutes. Everything is configurable via .env. While a type stays available the tool stays quiet β€” it alerts on the transition into stock, then waits out a cooldown before it can fire again, so you get a heads-up rather than a flood.

Quick start

Requires Node 22 (see .nvmrc).

nvm use            # picks up .nvmrc
npm install
cp .env.example .env
# edit .env: fill in HCLOUD_TOKEN, RESEND_API_KEY, ALERT_EMAIL_TO
npm start
Script What it does
npm start run the radar (tsx src/index.ts)
npm run dev run with file-watch reload
npm run typecheck tsc --noEmit

Stop with Ctrl-C.

Configuration

All settings come from .env β€” copy .env.example and fill in the three required secrets.

Var Required Default Notes
HCLOUD_TOKEN yes β€” Hetzner Cloud API token; read scope is enough
RESEND_API_KEY yes β€” from https://resend.com
ALERT_EMAIL_TO yes β€” alert recipient
SERVER_TYPE_ID no 115 (CX33) Hetzner server type id
LOCATION_PREFIX no nbg1 (Nuremberg) matched against dc.name.startsWith(...)
CHECK_INTERVAL_SECONDS no 300 poll cadence in seconds
EMAIL_COOLDOWN_SECONDS no 3600 min seconds before a new alert can fire; suppresses flapping
HETZNER_PROJECT_ID no β€” when set, the "Buy now" link deep-links to that project's create-server page (find it in the console URL: https://console.hetzner.cloud/projects/<id>/...)

LOCATION_PREFIX options

Matched with dc.name.startsWith(...), so use a location name (or a specific datacenter name for finer scope). Verified against GET /v1/datacenters on 2026-05-10.

Prefix City Country Datacenter
nbg1 Nuremberg DE nbg1-dc3
fsn1 Falkenstein DE fsn1-dc14
hel1 Helsinki FI hel1-dc2
ash Ashburn, VA US ash-dc1
hil Hillsboro, OR US hil-dc1
sin Singapore SG sin-dc1

SERVER_TYPE_ID options

All active server types from GET /v1/server_types (verified 2026-05-10). Specs are cores / memory GB / disk GB.

ID Name Specs CPU Arch
22 cpx11 2 / 2 / 40 shared x86
23 cpx21 3 / 4 / 80 shared x86
24 cpx31 4 / 8 / 160 shared x86
25 cpx41 8 / 16 / 240 shared x86
26 cpx51 16 / 32 / 360 shared x86
45 cax11 2 / 4 / 40 shared arm
93 cax21 4 / 8 / 80 shared arm
94 cax31 8 / 16 / 160 shared arm
95 cax41 16 / 32 / 320 shared arm
96 ccx13 2 / 8 / 80 dedicated x86
97 ccx23 4 / 16 / 160 dedicated x86
98 ccx33 8 / 32 / 240 dedicated x86
99 ccx43 16 / 64 / 360 dedicated x86
100 ccx53 32 / 128 / 600 dedicated x86
101 ccx63 48 / 192 / 960 dedicated x86
108 cpx12 1 / 2 / 40 shared x86
109 cpx22 2 / 4 / 80 shared x86
110 cpx32 4 / 8 / 160 shared x86
111 cpx42 8 / 16 / 320 shared x86
112 cpx52 12 / 24 / 480 shared x86
113 cpx62 16 / 32 / 640 shared x86
114 cx23 2 / 4 / 40 shared x86
115 cx33 4 / 8 / 80 shared x86
116 cx43 8 / 16 / 160 shared x86
117 cx53 16 / 32 / 320 shared x86

93–95, 116, 117 are listed by the API but not in any datacenter's available list at the time of verification β€” pick one of these only if you're specifically waiting for it to come back in stock.

How it works

src/index.ts calls GET https://api.hetzner.cloud/v1/datacenters every CHECK_INTERVAL_SECONDS, keeps datacenters whose name starts with LOCATION_PREFIX, and checks whether their server_types.available list contains SERVER_TYPE_ID.

flowchart LR
  Timer["⏱️ poll loop"] --> DC["Hetzner /v1/datacenters"]
  DC --> Filter["filter by LOCATION_PREFIX\n+ SERVER_TYPE_ID available"]
  Filter -- "match (newly in stock)" --> Resend["Resend email alert"]
  Filter -- "no match / cooldown" --> Timer
  Resend --> Inbox["πŸ“¬ your inbox"]
Loading

On a transition into "available" it sends an alert email through Resend (subject + plaintext/HTML body, with an optional "Buy now" deep-link). It does not re-alert every cycle while the type stays in stock; once it drops out and comes back, a new alert can fire after EMAIL_COOLDOWN_SECONDS has elapsed.

Tech stack

Layer Tech
Runtime Node 22 (ESM), run via tsx
Language TypeScript 6 (strict, noEmit typecheck)
Data source Hetzner Cloud public API (/v1/datacenters, /v1/server_types, /v1/locations)
Email Resend
Config dotenv (.env)

Docs & decisions

This is a single-file utility β€” the full behavior lives in src/index.ts and the configuration reference above. There is no separate docs/ tree.

Not yet present in this repo: a LICENSE file, a CI workflow (.github/workflows/), and a docs/ directory. Add these if the project grows beyond a single script.

About

πŸ“‘ hetzner-server-radar β€” out-of-stock radar for Hetzner Cloud: get an email the moment your CX/CCX/CAX server type is available in your preferred datacenter.

Topics

Resources

Stars

1 star

Watchers

0 watching

Forks

Releases

Packages

Contributors

Languages