agentsclimarketplace

Hetzner server provision

Skill punkaze/skills/plugin/skills/hetzner-server-provision

punkaze's Claude Code agent skills collection (plugin marketplace). Ships the bruno skill: author/generate/run Bruno .bru API collections.

Install
npx -y skills add punkaze/skills --skill hetzner-server-provision

Assembled from the repository path, not quoted from the project. Check it against their README if it does not work.

One thing to look at

  • 1 stars1 stars. Stars are a popularity signal and not a quality one, but at this level it is likely that nobody has read this closely except its author, and you would be relying on your own review.

What its author says it does

Copied from the file, not written here

Use this skill whenever the user wants to create, provision, or spin up a new Hetzner Cloud server. Triggers on phrases like "create a server on Hetzner", "spin up a Hetzner VPS", "set up a new Hetzner instance", "deploy to Hetzner", or any mention of Hetzner server creation. Also use when the user wants to migrate to a different Hetzner location or server type. Always invoke this skill before manually running Hetzner API calls — it handles all the edge cases automatically.

SKILL.md

7.1 KB, as published. Nobody here has run it

Hetzner Server Provision

Provision a production-ready Hetzner Cloud server end-to-end: choose type/location, create the firewall, boot the server, and install Docker + Nginx + Certbot. The mechanics live in scripts/; this file covers when to run each one and the judgment calls.

Announce at start: "I'm using the hetzner-server-provision skill to set up your Hetzner server."

Prerequisites

This skill uses Hetzner's official hcloud CLI (cleaner and more robust than raw API curl — it waits for the server natively and gives readable errors).

  • hcloud CLIcommand -v hcloud || brew install hcloud
  • API token — export it so every script picks it up:
    export HCLOUD_TOKEN="<your-hetzner-api-token>"
    
    (or hcloud context create <name> once, interactively). Ask the user for the token if it isn't set.

Step 0: Gather Requirements

Before provisioning, collect:

  • SSH public key — check ~/.ssh/*.pub, ask which to use if multiple found
  • Server purpose — dev or production? (affects size recommendation)
  • Location preference — or let the skill fall back across EU locations
  • Server name — e.g. my-app-dev

Step 1: Pick Type & Location

scripts/list-server-types.sh                 # all types, cheapest first
scripts/list-server-types.sh --location hel1 # filter to one location
scripts/list-server-types.sh --arch arm      # arm only (or: --arch x86)

Recommendation guide (specs only — prices drift, so read live figures from list-server-types.sh):

Use caseRecommendedSpecs
Dev server (budget)cx232vCPU / 4GB / 40GB, AMD64
Dev server (ARM)cax112vCPU / 4GB / 40GB, ARM64
Production smallcx334vCPU / 8GB / 80GB, AMD64

Architecture matters for deploys: an arm server (cax*) can only run arm64 images; an x86 server (cx*) runs amd64. Match the image you'll deploy later.

Not all types exist in all locations. cx* are EU-only (fsn1, nbg1, hel1). Singapore (sin) only has pricier cpx* types. list-server-types.sh shows exactly what's bookable where.

Step 2: Provision the Server

One script handles SSH key upload, firewall, server creation, and waiting — all idempotent, so it's safe to re-run.

scripts/provision.sh \
  --name my-app-dev \
  --type cx23 \
  --ssh-key-file ~/.ssh/id_ed25519.pub

It tries hel1 → nbg1 → fsn1 and automatically moves on if a location has no capacity. Pin one with --location hel1 if needed.

Firewall posture (secure by default): port 22 is opened only to your detected public IP, while 80/443/ICMP are public. Override with --ssh-source <CIDR[,CIDR]> (e.g. --ssh-source 0.0.0.0/0,::/0 to open SSH to the world — not recommended). Database/storage ports stay closed and are later bound to the Tailscale subnet by the tailscale-server-setup skill.

On success it prints a JSON line with the IP and ID, e.g.:

{"name":"my-app-dev","id":12345,"ip":"203.0.113.10","location":"hel1","type":"cx23","ssh_key":"id_ed25519","ssh_source":"203.0.113.5/32"}

Wait ~15s after this before the next step so sshd is fully up.

Step 3: Install Docker + Nginx + Certbot (and harden)

Copy the bootstrap script to the server and run it as root:

IP=203.0.113.10           # from Step 2 JSON
KEY=~/.ssh/id_ed25519

scp -o StrictHostKeyChecking=accept-new -i "$KEY" scripts/bootstrap-remote.sh root@"$IP":/tmp/
ssh -o StrictHostKeyChecking=accept-new -i "$KEY" root@"$IP" 'bash /tmp/bootstrap-remote.sh'

Uses accept-new (trust-on-first-use), not StrictHostKeyChecking=no — it pins the host key on first connect and refuses a silently-changed key afterward, which closes the MITM hole.

It installs Docker CE from the official repo (so docker compose works), plus Nginx and Certbot, then hardens the box: disables SSH password auth (key-only) and enables automatic security updates. The script runs sshd -t to validate the SSH config before reloading, so a typo can't lock you out, and prints the effective SSH settings at the end.

Step 4: Report

✅ Server provisioned successfully

| | |
|--|--|
| Server ID | <id> |
| Public IP | <ip> |
| Location | <location> |
| Type | <type> (xvCPU, xGB RAM) |
| Cost | €x.xx/mo |
| SSH | ssh -i <key-path> root@<ip> |

Next steps:
- Deploy your application (docker-compose-deploy skill)
- Set up domain + SSL (nginx-ssl-setup skill)
- Secure with Tailscale (tailscale-server-setup skill)

Security Posture

Defaults are chosen to fail closed:

  • Secrets stay out of the repo and argv. The Hetzner token is read only from HCLOUD_TOKEN (or an hcloud context) — never a flag, never echoed. Never commit it. provision.sh takes a public key path and refuses anything that isn't a .pub/valid OpenSSH public key, so a private key can't be uploaded by mistake.
  • SSH is locked to your IP at the firewall by default (--ssh-source to change), and the box is then made key-only (password auth off, root by key only).
  • Host keys are pinned on first connect (accept-new), not blindly trusted.
  • Automatic security updates are enabled on the server.
  • Input is validated (--name is restricted to [a-z0-9-]) and all scripts use set -euo pipefail.

Two things this skill intentionally does not do, by design: it leaves 80/443 public (web traffic needs them) and keeps a public SSH rule alive (you need SSH before Tailscale exists). Run the tailscale-server-setup skill next to drop public SSH entirely and reach the box over the tailnet.

Common Pitfalls

  • No capacity in a locationprovision.sh already falls back across EU locations; if all fail, try a different type or wait.
  • SSH timeout right after provision — wait ~15s more for sshd to start.
  • Locked out after your IP changed — SSH is pinned to the IP detected at provision time. If your IP rotates before Tailscale is up, re-run provision.sh (idempotent) or temporarily widen with --ssh-source; the firewall rule updates.
  • docker compose not found — only happens with apt install docker.io. bootstrap-remote.sh uses the official Docker repo and avoids this.
  • Architecture mismatch — deploying an amd64 image to a cax* (ARM) server (or vice-versa) fails to run. Pick the server arch to match your image in Step 1.
  • HCLOUD_TOKEN not set — every script exits early with a clear message; export the token (or set an hcloud context).

Keep looking

Skills are one crate of 328,083. Ordering is by how many stacks a row turns up in, so the top of any crate is what has actually been picked rather than what has the most stars.