| name | hetzner-cloud-management |
| description | Use when deploying, managing, or troubleshooting Hetzner Cloud infrastructure via hcloud CLI.
Triggers: "hetzner cloud", "hcloud", "hetzner server", "create server on hetzner",
"hetzner network", "hetzner firewall", "hetzner load balancer", "provision hetzner",
"deploy to hetzner", "hetzner volume", "hetzner floating ip", "hetzner snapshot".
Provides comprehensive workflows for server management, networking, storage, security,
and production-ready automation patterns with the official Hetzner Cloud CLI.
|
Hetzner Cloud Management
Comprehensive management of Hetzner Cloud infrastructure using the official hcloud CLI. Covers servers, networks, firewalls, load balancers, volumes, floating IPs, and automation workflows.
Quick Reference
| Task | Command | Notes |
|---|
| Create Server | hcloud server create --name <name> --type <type> --image <image> | Add --ssh-key, --network, --firewall for production |
| List Servers | hcloud server list | Use --output json for scripting |
| Server Control | hcloud server [poweron|shutdown|reboot|reset] <name> | reset is hard reset |
| SSH Access | hcloud server ssh <name> | Direct SSH connection |
| Create Snapshot | hcloud server create-image <name> --type snapshot | For backups before changes |
| Create Network | hcloud network create --name <name> --ip-range <cidr> | Private networking |
| Create Firewall | hcloud firewall create --name <name> --rules-file <file> | JSON format for rules |
| Create Load Balancer | hcloud load-balancer create --name <name> --type <type> | Add services and targets after |
| Context Switch | hcloud context use <context> | Multi-project management |
| JSON Output | hcloud <command> --output json | Pipe to jq for parsing |
Command Categories
The hcloud CLI is organized into these main resource types:
| Category | Purpose | Key Commands |
|---|
| server | Virtual machines | create, list, delete, poweron, shutdown, ssh, create-image |
| network | Private networks | create, add-subnet, add-route, expose-routes-to-vswitch |
| firewall | Security rules | create, add-rule, apply-to-resource, replace-rules |
| load-balancer | Traffic distribution | create, add-service, add-target, change-algorithm |
| volume | Block storage | create, attach, detach, resize |
| floating-ip | Static IPs | create, assign, unassign, set-rdns |
| ssh-key | SSH key management | create, list, delete |
| placement-group | Server distribution | create spread, create anti-affinity |
| primary-ip | IP management | create, assign, unassign |
| certificate | SSL/TLS certs | create, list, delete |
| datacenter | View datacenters | list, describe |
| location | View locations | list, describe |
| server-type | View server types | list, describe |
| image | OS images | list, describe, delete |
| context | Multi-project auth | create, list, use, active, delete |
Installation
Install hcloud CLI
brew install hcloud
sudo snap install hcloud
Verify Installation
hcloud version
Authentication
Workflow 1: Initial Setup with API Token
hcloud context create my-project
hcloud server list
hcloud context active
Workflow 2: Multiple Projects (Context Management)
hcloud context create production
hcloud context create staging
hcloud context list
hcloud context use production
hcloud server list
hcloud context use staging
hcloud server list
hcloud context active
Workflow 3: CI/CD Authentication (Environment Variable)
export HCLOUD_TOKEN="your-64-character-api-token"
hcloud server list
- name: Deploy to Hetzner
env:
HCLOUD_TOKEN: ${{ secrets.HETZNER_TOKEN }}
run: |
hcloud server create --name ci-server --type cpx11 --image ubuntu-24.04
Configuration File Location
Default: ~/.config/hcloud/cli.toml
active_context = "production"
[[contexts]]
name = "production"
token = "your-64-char-token"
[[contexts]]
name = "staging"
token = "another-64-char-token"
Server Management
Workflow 4: Create Basic Server
hcloud server create \
--name my-server \
--type cpx11 \
--image ubuntu-24.04 \
--location fsn1
Workflow 5: Create Production Server
hcloud ssh-key create \
--name deploy-key \
--public-key-from-file ~/.ssh/id_rsa.pub
hcloud network create --name app-network --ip-range 10.0.0.0/16
hcloud network add-subnet app-network \
--type cloud \
--network-zone eu-central \
--ip-range 10.0.1.0/24
cat > firewall-rules.json <<'EOF'
{
"rules": [
{
"direction": "in",
"protocol": "tcp",
"port": "22",
"source_ips": ["0.0.0.0/0", "::/0"],
"description": "SSH"
},
{
"direction": "in",
"protocol": "tcp",
"port": "80",
"source_ips": ["0.0.0.0/0", "::/0"],
"description": "HTTP"
},
{
"direction": "in",
"protocol": "tcp",
"port": "443",
"source_ips": ["0.0.0.0/0", "::/0"],
"description": "HTTPS"
}
]
}
EOF
hcloud firewall create --name web-firewall --rules-file firewall-rules.json
hcloud server create \
--name web-01 \
--type cpx21 \
--image ubuntu-24.04 \
--location fsn1 \
--ssh-key deploy-key \
--network app-network \
--firewall web-firewall \
--labels environment=production,service=web,team=platform \
--enable-backup \
--user-data-from-file cloud-init.yaml
hcloud server enable-protection web-01 --delete
hcloud server describe web-01
Workflow 6: Server Control Operations
hcloud server poweron my-server
hcloud server shutdown my-server
hcloud server reboot my-server
hcloud server reset my-server
hcloud server describe my-server --output json | jq -r '.status'
hcloud server enable-rescue my-server --ssh-key deploy-key
hcloud server reboot my-server
hcloud server disable-rescue my-server
hcloud server reboot my-server
hcloud server ssh my-server
hcloud server ssh my-server --user root
hcloud server describe my-server --output json | jq -r '.public_net.ipv4.ip'
Workflow 7: Snapshots and Backups
hcloud server create-image my-server \
--type snapshot \
--description "Before upgrade to v2.0" \
--labels version=1.9,backup_type=manual
hcloud server enable-backup my-server
hcloud server disable-backup my-server
hcloud image list --type snapshot
hcloud image list --type backup
hcloud image delete snapshot-123456
hcloud server create \
--name my-server-restored \
--image snapshot-123456 \
--type cpx21 \
--location fsn1
Workflow 8: Server Scaling and Resize
hcloud server-type list
hcloud server shutdown my-server
while [ "$(hcloud server describe my-server -o json | jq -r '.status')" != "off" ]; do
echo "Waiting for shutdown..."
sleep 2
done
hcloud server change-type my-server --upgrade-disk cpx31
hcloud server poweron my-server
Network Infrastructure
Workflow 9: Private Network Setup
hcloud network create \
--name app-network \
--ip-range 10.0.0.0/16 \
--labels environment=production
hcloud network add-subnet app-network \
--type cloud \
--network-zone eu-central \
--ip-range 10.0.1.0/24
hcloud network add-subnet app-network \
--type cloud \
--network-zone eu-central \
--ip-range 10.0.2.0/24
hcloud network add-route app-network \
--destination 192.168.0.0/16 \
--gateway 10.0.1.1
hcloud server attach-to-network my-server \
--network app-network \
--ip 10.0.1.10
hcloud server detach-from-network my-server --network app-network
hcloud network describe app-network
Workflow 10: Firewall Management
cat > app-firewall.json <<'EOF'
{
"rules": [
{
"direction": "in",
"protocol": "tcp",
"port": "22",
"source_ips": ["YOUR_IP/32"],
"description": "SSH from office"
},
{
"direction": "in",
"protocol": "tcp",
"port": "443",
"source_ips": ["0.0.0.0/0", "::/0"],
"description": "HTTPS"
},
{
"direction": "in",
"protocol": "icmp",
"source_ips": ["0.0.0.0/0", "::/0"],
"description": "Ping"
}
]
}
EOF
hcloud firewall create --name app-firewall --rules-file app-firewall.json
hcloud firewall apply-to-resource app-firewall \
--type server \
--server web-01
hcloud firewall apply-to-resource app-firewall \
--type label \
--label environment=production
hcloud firewall add-rule app-firewall \
--direction in \
--protocol tcp \
--port 8080 \
--source-ips 10.0.0.0/16 \
--description "Internal API"
hcloud firewall describe app-firewall
hcloud firewall delete-rule app-firewall --index 2
hcloud firewall replace-rules app-firewall --rules-file new-rules.json
hcloud firewall remove-from-resource app-firewall \
--type server \
--server web-01
hcloud firewall list
Workflow 11: Load Balancer Setup
hcloud load-balancer create \
--name app-lb \
--type lb11 \
--location fsn1 \
--labels service=frontend
hcloud load-balancer add-service app-lb \
--protocol http \
--listen-port 80 \
--destination-port 8080 \
--http-sticky-sessions
hcloud certificate create \
--name app-cert \
--type managed \
--domain example.com \
--domain www.example.com
hcloud load-balancer add-service app-lb \
--protocol https \
--listen-port 443 \
--destination-port 8080 \
--http-certificates app-cert \
--http-sticky-sessions \
--http-redirect-http
hcloud load-balancer update-service app-lb \
--listen-port 80 \
--health-check-protocol http \
--health-check-port 8080 \
--health-check-interval 15 \
--health-check-timeout 10 \
--health-check-retries 3 \
--health-check-http-path /health
hcloud load-balancer add-target app-lb --type server --server web-01
hcloud load-balancer add-target app-lb --type server --server web-02
hcloud load-balancer add-target app-lb \
--type label \
--label service=web
hcloud load-balancer change-algorithm app-lb --type round_robin
hcloud load-balancer metrics app-lb --type open_connections
hcloud load-balancer metrics app-lb --type requests_per_second
hcloud load-balancer enable-protection app-lb --delete
Storage Management
Workflow 12: Volume Management
hcloud volume create \
--name data-vol \
--size 50 \
--location fsn1 \
--format ext4 \
--labels service=database
hcloud volume attach data-vol --server db-01
hcloud server ssh db-01
sudo mkdir -p /mnt/data
sudo mount /dev/disk/by-id/scsi-0HC_Volume_* /mnt/data
hcloud volume detach data-vol
hcloud volume resize data-vol --size 100
hcloud volume enable-protection data-vol --delete
hcloud volume list
hcloud volume delete data-vol
Workflow 13: Floating IP Management
hcloud floating-ip create \
--type ipv4 \
--home-location fsn1 \
--description "Primary web IP" \
--labels service=web
hcloud floating-ip create \
--type ipv6 \
--home-location fsn1
hcloud floating-ip assign 1.2.3.4 --server web-01
hcloud server ssh web-01
sudo ip addr add 1.2.3.4/32 dev eth0
hcloud floating-ip set-rdns 1.2.3.4 --hostname web.example.com
hcloud floating-ip unassign 1.2.3.4
hcloud floating-ip enable-protection 1.2.3.4 --delete
hcloud floating-ip list
Automation Patterns
Workflow 14: Complete Infrastructure Provisioning
#!/bin/bash
set -euo pipefail
PROJECT="my-app"
LOCATION="fsn1"
NETWORK_CIDR="10.0.0.0/16"
SUBNET_CIDR="10.0.1.0/24"
echo "Creating network..."
hcloud network create --name "${PROJECT}-network" --ip-range "$NETWORK_CIDR"
hcloud network add-subnet "${PROJECT}-network" \
--type cloud \
--network-zone eu-central \
--ip-range "$SUBNET_CIDR"
echo "Creating firewall..."
cat > firewall.json <<'EOF'
{
"rules": [
{"direction": "in", "protocol": "tcp", "port": "22", "source_ips": ["0.0.0.0/0", "::/0"], "description": "SSH"},
{"direction": "in", "protocol": "tcp", "port": "80", "source_ips": ["0.0.0.0/0", "::/0"], "description": "HTTP"},
{"direction": "in", "protocol": "tcp", "port": "443", "source_ips": ["0.0.0.0/0", "::/0"], "description": "HTTPS"}
]
}
EOF
hcloud firewall create --name "${PROJECT}-firewall" --rules-file firewall.json
echo "Creating SSH key..."
hcloud ssh-key create --name "${PROJECT}-key" --public-key-from-file ~/.ssh/id_rsa.pub || true
echo "Creating web servers..."
for i in 1 2 3; do
hcloud server create \
--name "${PROJECT}-web-${i}" \
--type cpx21 \
--image ubuntu-24.04 \
--location "$LOCATION" \
--network "${PROJECT}-network" \
--firewall "${PROJECT}-firewall" \
--ssh-key "${PROJECT}-key" \
--labels "app=${PROJECT},role=web,index=${i}" \
--enable-backup &
done
wait
echo "Waiting for servers..."
for i in 1 2 3; do
while [ "$(hcloud server describe "${PROJECT}-web-${i}" -o json | jq -r '.status')" != "running" ]; do
sleep 2
done
echo "${PROJECT}-web-${i} is running"
done
echo "Creating load balancer..."
hcloud load-balancer create \
--name "${PROJECT}-lb" \
--type lb11 \
--location "$LOCATION"
hcloud load-balancer add-service "${PROJECT}-lb" \
--protocol http \
--listen-port 80 \
--destination-port 80 \
--health-check-protocol http \
--health-check-port 80 \
--health-check-http-path /health
hcloud load-balancer add-target "${PROJECT}-lb" \
--type label \
--label "role=web"
echo ""
echo "Infrastructure created:"
echo "======================"
hcloud server list --output columns=name,ipv4,status | grep "${PROJECT}"
echo ""
LB_IP=$(hcloud load-balancer describe "${PROJECT}-lb" -o json | jq -r '.public_net.ipv4.ip')
echo "Load Balancer IP: $LB_IP"
echo ""
echo "Test: curl http://$LB_IP"
Workflow 15: Server Monitoring and Health Checks
#!/bin/bash
SERVERS=$(hcloud server list -o json | jq -r '.[] | select(.labels.environment == "production") | .name')
for server in $SERVERS; do
STATUS=$(hcloud server describe "$server" -o json | jq -r '.status')
if [ "$STATUS" != "running" ]; then
echo "⚠️ $server is $STATUS"
else
echo "✅ $server is running"
fi
CPU=$(hcloud server metrics "$server" --type cpu --start=$(date -u -d '5 minutes ago' +%s) -o json | jq -r '.time_series.cpu.values[-1][1]')
echo " CPU: ${CPU}%"
if (( $(echo "$CPU > 90" | bc -l) )); then
echo " ⚠️ High CPU usage!"
fi
done
Workflow 16: Cleanup and Resource Management
#!/bin/bash
echo "Cleaning up temporary servers..."
hcloud server list -o json | jq -r '.[] | select(.labels.temp == "true") | select(.status == "off") | .name' | while read server; do
echo "Deleting $server..."
hcloud server delete "$server"
done
echo "Cleaning up unattached volumes..."
hcloud volume list -o json | jq -r '.[] | select(.server == null) | "\(.id) \(.created)"' | while read id created; do
AGE=$(( ($(date +%s) - $(date -d "$created" +%s)) / 86400 ))
if [ $AGE -gt 7 ]; then
echo "Deleting volume $id (${AGE} days old)..."
hcloud volume delete "$id"
fi
done
echo "Cleaning up old snapshots..."
hcloud image list --type snapshot -o json | \
jq -r 'sort_by(.created) | reverse | .[3:] | .[] | .id' | \
while read image_id; do
echo "Deleting snapshot $image_id..."
hcloud image delete "$image_id"
done
Workflow 17: Batch Operations with JSON
hcloud server list -o json | \
jq -r '.[] | select(.labels.role == "web") | select(.status == "running") | "\(.name): \(.public_net.ipv4.ip)"'
echo "[web_servers]"
hcloud server list -o json | \
jq -r '.[] | select(.labels.role == "web") | "\(.public_net.ipv4.ip) hostname=\(.name)"'
hcloud server list -o json | \
jq -r '.[] | select(.labels.environment == "dev") | .name' | \
xargs -I {} hcloud server shutdown {}
FIREWALL="prod-firewall"
hcloud server list -o json | \
jq -r '.[] | select(.labels.environment == "production") | .name' | \
while read server; do
hcloud firewall apply-to-resource "$FIREWALL" --type server --server "$server"
done
Best Practices
Resource Organization
--labels environment=production,service=api,team=platform,version=v2.0
hcloud server list --selector environment=production
hcloud server list --selector service=web
--name prod-web-01
--name server-123
hcloud server enable-protection prod-db-01 --delete --rebuild
hcloud volume enable-protection prod-data --delete
Security Hardening
{
"rules": [
{
"direction": "in",
"protocol": "tcp",
"port": "22",
"source_ips": ["YOUR_OFFICE_IP/32"],
"description": "SSH from office only"
}
]
}
hcloud server enable-backup prod-db-01
hcloud ssh-key create --name deploy-key --public-key-from-file ~/.ssh/id_rsa.pub
package_upgrade: true
packages:
- unattended-upgrades
Cost Optimization
hcloud server-type list
hcloud server shutdown dev-*
hcloud server create-image dev-server --type snapshot --description "Dev environment"
hcloud server delete dev-server
hcloud image list --type snapshot
hcloud image delete old-snapshot-id
hcloud placement-group create spread --name ha-group
High Availability Patterns
hcloud server create --name web-fsn1 --location fsn1
hcloud server create --name web-nbg1 --location nbg1
hcloud load-balancer add-service app-lb \
--health-check-protocol http \
--health-check-retries 3 \
--health-check-interval 15
hcloud floating-ip assign 1.2.3.4 --server primary
hcloud floating-ip assign 1.2.3.4 --server secondary
hcloud placement-group create spread --name web-spread
hcloud server create --placement-group web-spread
hcloud server enable-backup prod-server
Troubleshooting
Authentication Issues
hcloud context active
hcloud context list
hcloud server list
hcloud context delete my-project
hcloud context create my-project
cat ~/.config/hcloud/cli.toml
Server Creation Failures
hcloud location list
hcloud server-type list
hcloud datacenter list
hcloud server create --name test --type cpx11 --image ubuntu-24.04 --debug
Network Connectivity Issues
hcloud firewall describe my-firewall
hcloud server describe my-server -o json | jq '.private_net'
hcloud network describe my-network
hcloud server ssh my-server
ping -c 3 10.0.1.10
hcloud firewall list
hcloud server describe my-server -o json | jq '.firewall_ids'
Performance Issues
hcloud server metrics my-server --type cpu
hcloud server metrics my-server --type network
hcloud server metrics my-server --type disk
hcloud load-balancer metrics my-lb --type open_connections
hcloud load-balancer metrics my-lb --type requests_per_second
hcloud server-type describe cpx21
hcloud server shutdown my-server
hcloud server change-type my-server --upgrade-disk cpx31
hcloud server poweron my-server
Common Error Messages
| Error | Cause | Solution |
|---|
unable to authenticate | Invalid/expired token | Re-create context with valid token |
server not found | Wrong context or server name | Check hcloud context active |
insufficient resources | Location at capacity | Try different location |
limit_reached | Project limit exceeded | Contact support or upgrade |
protected | Resource has deletion protection | Disable protection first |
server_already_attached | Already in network | Detach first, then re-attach |
ip_not_available | IP already assigned | Unassign from other resource |
Output Formats for Scripting
hcloud server list --output json
hcloud server list -o json | jq '.[] | {name: .name, ip: .public_net.ipv4.ip}'
hcloud server describe my-server --output yaml
hcloud server list --output format='{{range .}}{{.Name}}: {{.PublicNet.IPv4.IP}}{{"\n"}}{{end}}'
hcloud server list --output noheader
hcloud server list --output columns=name,ipv4,status
hcloud server list -o noheader -o columns=name,ipv4 | while read name ip; do
echo "Server: $name -> $ip"
done
Advanced Use Cases
Placement Groups
hcloud placement-group create spread --name ha-web
hcloud server create --name web-01 --placement-group ha-web --type cpx21
hcloud server create --name web-02 --placement-group ha-web --type cpx21
Primary IPs
hcloud primary-ip create \
--type ipv4 \
--assignee-type server \
--datacenter fsn1-dc14 \
--name web-primary-ip
hcloud server create \
--name my-server \
--type cpx11 \
--image ubuntu-24.04 \
--primary-ipv4 web-primary-ip
User Data (Cloud-Init)
cat > cloud-init.yaml <<'EOF'
package_upgrade: true
packages:
- docker.io
- git
- curl
write_files:
- path: /etc/docker/daemon.json
content: |
{"log-driver": "json-file", "log-opts": {"max-size": "10m"}}
runcmd:
- systemctl enable docker
- systemctl start docker
- usermod -aG docker ubuntu
EOF
hcloud server create \
--name docker-server \
--type cpx21 \
--image ubuntu-24.04 \
--user-data-from-file cloud-init.yaml
DNS Integration (Experimental)
hcloud zone create --name example.com
hcloud zone add-record example.com --type A --name www --value 1.2.3.4
hcloud zone add-record example.com --type AAAA --name www --value 2001:db8::1
hcloud zone list
hcloud zone export example.com
Resources
Version Information
This skill is based on hcloud CLI v1.60.0 (January 2026).