Hetzner Server Management
Create and manage Hetzner Cloud servers using the hcloud CLI.
Prerequisites
- •
hcloudCLI installed (via mise:hcloud = "latest") - •Authenticated:
hcloud context create <name>with API token from https://console.hetzner.cloud
Quick Reference
Create a server
# Prefer ARM (best value) hcloud server create \ --name dev \ --type cax21 \ --image ubuntu-24.04 \ --location nbg1 \ --ssh-key connorads \ --ssh-key connor@penguin # x86 fallback hcloud server create \ --name dev \ --type cpx21 \ --image ubuntu-24.04 \ --location nbg1 \ --ssh-key connorads \ --ssh-key connor@penguin # IPv6-only (saves ~$0.60/month on IPv4) hcloud server create \ --name dev \ --type cax21 \ --image ubuntu-24.04 \ --location nbg1 \ --ssh-key connorads \ --ssh-key connor@penguin \ --without-ipv4
With user-data (auto-run install script)
# Use heredoc - process substitution <(echo '...') escapes the shebang incorrectly hcloud server create \ --name dev \ --type cax21 \ --image ubuntu-24.04 \ --location nbg1 \ --ssh-key connorads \ --ssh-key connor@penguin \ --user-data-from-file - <<'EOF' #!/bin/bash curl -fsSL https://raw.githubusercontent.com/connorads/dotfiles/master/install.sh | bash EOF
The dotfiles installation takes ~5 minutes. To monitor progress:
# Quick status check ssh connor@$(hcloud server ip dev) "cloud-init status" # View recent installation logs ssh connor@$(hcloud server ip dev) "sudo journalctl -u cloud-final -n 50 --no-pager" # Follow installation in real-time ssh connor@$(hcloud server ip dev) "sudo journalctl -u cloud-final -f" # Check if tools are installed ssh connor@$(hcloud server ip dev) "which zsh mise && echo \$SHELL"
With swap (recommended for production)
Ubuntu cloud images don't include swap by default. Add swap via cloud-init at creation:
# Create server with 16GB swap (1:1 ratio for 16GB RAM server) hcloud server create \ --name dev \ --type cax33 \ --image ubuntu-24.04 \ --location nbg1 \ --ssh-key connorads \ --ssh-key connor@penguin \ --user-data-from-file - <<'EOF' #cloud-config swap: filename: /swapfile size: 16G maxsize: 16G EOF
Recommended swap sizes:
- •4GB RAM → 4-8GB swap
- •8GB RAM → 8GB swap
- •16GB+ RAM → 16GB swap (1:1 ratio)
Add swap to existing server:
# Create 16GB swap file ssh connor@$(hcloud server ip dev) "sudo fallocate -l 16G /swapfile && \ sudo chmod 600 /swapfile && \ sudo mkswap /swapfile && \ sudo swapon /swapfile && \ echo '/swapfile none swap sw 0 0' | sudo tee -a /etc/fstab" # Verify swap is active ssh connor@$(hcloud server ip dev) "free -h"
Common commands
# List servers hcloud server list # Get server IP hcloud server ip dev # SSH to server ssh connor@$(hcloud server ip dev) # Delete server hcloud server delete dev # Power operations hcloud server poweroff dev hcloud server poweron dev hcloud server reboot dev # Rebuild (reinstall OS, keeps IP) hcloud server rebuild dev --image ubuntu-24.04
Server types (commonly used)
Prices in USD for EU regions (US regions ~20% higher):
| Type | Arch | vCPU | RAM | Disk | ~USD/mo |
|---|---|---|---|---|---|
| cax11 | ARM | 2 | 4GB | 40GB | $4.50 |
| cax21 | ARM | 4 | 8GB | 80GB | $8 |
| cax31 | ARM | 8 | 16GB | 160GB | $16 |
| cpx21 | x86 | 3 | 4GB | 80GB | $9 |
| cpx31 | x86 | 4 | 8GB | 160GB | $18 |
Full list: hcloud server-type list
Locations
| ID | City | Country |
|---|---|---|
| fsn1 | Falkenstein | DE |
| nbg1 | Nuremberg | DE |
| hel1 | Helsinki | FI |
| ash | Ashburn | US |
| hil | Hillsboro | US |
| sin | Singapore | SG |
SSH keys
# List keys hcloud ssh-key list # Add a key hcloud ssh-key create --name mykey --public-key-from-file ~/.ssh/id_ed25519.pub
Images
# List system images hcloud image list --type system # ARM images hcloud image list --type system --architecture arm
Cloning GitHub repos (SSH agent forwarding)
Use the <name>-agent SSH host (which has agent forwarding enabled) to clone private repos without copying keys to the server. If you hit host key errors, add GitHub's host key first.
# First time only: add GitHub's host key ssh dev "ssh-keyscan github.com >> ~/.ssh/known_hosts 2>/dev/null" # Confirm forwarded agent is visible ssh dev-agent "ssh-add -l" # Clone with agent forwarding (use -agent suffix) ssh dev-agent "mkdir -p ~/git && cd ~/git && git clone git@github.com:you/repo.git" # Clone specific branch ssh dev-agent "mkdir -p ~/git && cd ~/git && git clone git@github.com:you/repo.git && cd repo && git checkout branch-name" # Push/pull with agent forwarding ssh dev-agent "cd repo && git push"
For interactive sessions (e.g., lazygit):
ssh dev-agent # Then on server: git clone/push/pull works with forwarded agent
Post-creation setup
After creating a server, always clear any old host keys for that IP (Hetzner reuses IPs):
ssh-keygen -R $(hcloud server ip dev) 2>/dev/null ssh-keyscan $(hcloud server ip dev) >> ~/.ssh/known_hosts 2>/dev/null
Then add/update ~/.ssh/config with two profiles:
# Hetzner <name> - no agent forwarding (safe for AI agents)
Host <name>
HostName <ip-address>
User connor
ForwardAgent no
# Hetzner <name> - with agent forwarding (for git push/pull)
Host <name>-agent
HostName <ip-address>
User connor
ForwardAgent yes
- •Get IP:
hcloud server ip <name> - •If entry exists, update the HostName in both profiles
- •Default profile (
<name>) has no agent forwarding - safer for AI agents - •Use
<name>-agentwhen you need to push/pull to GitHub - •This enables VS Code Remote-SSH to show the server in the dropdown
Notes
- •ARM (cax*) servers are best value for dev work
- •IPv6-only saves money but requires Tailscale/cloudflared for access from IPv4 networks
- •User-data runs as root on first boot
- •The dotfiles install.sh handles creating user
connor, installing Nix, home-manager, and mise tools