Created
November 7, 2025 14:40
-
-
Save VincentBean/8ba565047cd21ebbeaa3303280f4fb72 to your computer and use it in GitHub Desktop.
A script to find cheaper Hetzner servers compared to what you have
This file contains hidden or bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
| #!/bin/bash | |
| # | |
| # Hetzner Cloud Server Info & Cost Optimizer | |
| # | |
| # Description: | |
| # Fetches all servers from your Hetzner Cloud account and analyzes their pricing. | |
| # For each server, it identifies cheaper server types with equal or better specs. | |
| # Results are exported to a tab-separated file (servers.txt) with cost savings. | |
| # | |
| # Setup: | |
| # 1. Create a .env file in the same directory with your Hetzner API token: | |
| # HETZNER_API_TOKEN=your_token_here | |
| # 2. Ensure jq and curl are installed | |
| # 3. Make the script executable: chmod +x get_server_info.sh | |
| # | |
| # Usage: | |
| # ./get_server_info.sh | |
| # | |
| # Output file (servers.txt) contains columns: | |
| # - Server name, type, IP, cores, RAM, disk, current price | |
| # - Cheaper alternative type, price, and potential savings (if available) | |
| # | |
| if [ -f ".env" ]; then | |
| source .env | |
| else | |
| echo "Error: .env file not found" | |
| exit 1 | |
| fi | |
| if [ -z "$HETZNER_API_TOKEN" ]; then | |
| echo "Error: HETZNER_API_TOKEN not set in .env file" | |
| exit 1 | |
| fi | |
| OUTPUT_FILE="servers.txt" | |
| > "$OUTPUT_FILE" | |
| echo "Fetching servers from Hetzner Cloud API..." | |
| echo "Fetching available server types..." | |
| server_types_response=$(curl -s -H "Authorization: Bearer $HETZNER_API_TOKEN" "https://api.hetzner.cloud/v1/server_types") | |
| all_servers="" | |
| for page in 1 2 3; do # very basic pagination, adjust as needed | |
| echo "Fetching servers page $page..." | |
| api_response=$(curl -s -H "Authorization: Bearer $HETZNER_API_TOKEN" "https://api.hetzner.cloud/v1/servers?page=$page&per_page=50") | |
| if [ $? -ne 0 ]; then | |
| echo "Error: Failed to fetch servers from Hetzner API (page $page)" | |
| exit 1 | |
| fi | |
| if [ -z "$all_servers" ]; then | |
| all_servers="$api_response" | |
| else | |
| all_servers=$(echo "$all_servers" | jq --argjson new "$api_response" '.servers += $new.servers') | |
| fi | |
| done | |
| echo "$all_servers" | jq -r '.servers[] | | |
| [ | |
| .name, | |
| .server_type.name, | |
| .public_net.ipv4.ip, | |
| (.server_type.cores | tostring), | |
| (.server_type.memory | tostring), | |
| (.server_type.disk | tostring), | |
| (.server_type.prices[0].price_monthly.gross) | |
| ] | @tsv' | while IFS=$'\t' read -r name server_type ip cores ram_gb disk price; do | |
| disk_gb="$disk" | |
| price_formatted=$(printf "%.2f" "$price" | sed 's/\./,/') | |
| cheaper_option=$(echo "$server_types_response" | jq -r --arg cores "$cores" --arg ram "$ram_gb" --arg disk "$disk" --arg current_price "$price" ' | |
| [.server_types[] | | |
| select( | |
| (.cores >= ($cores | tonumber)) and | |
| (.memory >= ($ram | tonumber)) and | |
| (.disk >= ($disk | tonumber)) and | |
| (.prices[0].price_monthly.gross | tonumber) < ($current_price | tonumber) | |
| ) | | |
| {name: .name, price: (.prices[0].price_monthly.gross | tonumber)}] | | |
| sort_by(.price) | | |
| .[0] // empty | | |
| [.name, (.price | tostring)] | | |
| @tsv | |
| ') | |
| if [ -n "$cheaper_option" ]; then | |
| cheaper_type=$(echo "$cheaper_option" | cut -f1) | |
| cheaper_price=$(echo "$cheaper_option" | cut -f2) | |
| cheaper_price_formatted=$(printf "%.2f" "$cheaper_price" | sed 's/\./,/') | |
| savings=$(echo "$price - $cheaper_price" | bc) | |
| savings_formatted=$(printf "%.2f" "$savings" | sed 's/\./,/') | |
| echo "Processing: $name ($server_type) - Cheaper option available: $cheaper_type" | |
| printf "%s\t%s\t%s\t%s\t%sGB\t%sGB\t%s\t%s\t%s\t%s\n" "$name" "$server_type" "$ip" "$cores" "$ram_gb" "$disk_gb" "$price_formatted" "$cheaper_type" "$cheaper_price_formatted" "$savings_formatted" >> "$OUTPUT_FILE" | |
| else | |
| echo "Processing: $name ($server_type) - Best price" | |
| printf "%s\t%s\t%s\t%s\t%sGB\t%sGB\t%s\t-\t-\t-\n" "$name" "$server_type" "$ip" "$cores" "$ram_gb" "$disk_gb" "$price_formatted" >> "$OUTPUT_FILE" | |
| fi | |
| done | |
| echo "" | |
| echo "Done! Results written to $OUTPUT_FILE" |
Sign up for free
to join this conversation on GitHub.
Already have an account?
Sign in to comment