diff options
Diffstat (limited to 'vps')
-rw-r--r-- | vps/.env | 5 | ||||
-rwxr-xr-x | vps/check-hardened.sh | 37 | ||||
-rwxr-xr-x | vps/check_rdns_retry.sh | 27 | ||||
-rwxr-xr-x | vps/functions/destroy_vps_by_label.sh | 28 | ||||
-rwxr-xr-x | vps/functions/disable_backups_by_label.sh | 23 | ||||
-rw-r--r-- | vps/functions/disable_ip.sh | 18 | ||||
-rwxr-xr-x | vps/functions/enable_backups_by_label.sh | 23 | ||||
-rwxr-xr-x | vps/functions/list_all_vps.sh | 9 | ||||
-rwxr-xr-x | vps/functions/provision.sh | 135 | ||||
-rwxr-xr-x | vps/functions/reboot_vps.sh | 7 | ||||
-rwxr-xr-x | vps/functions/resize_vps.sh | 27 | ||||
-rwxr-xr-x | vps/functions/safe_create_dataset.sh | 12 | ||||
-rwxr-xr-x | vps/functions/status_vps.sh | 8 | ||||
-rwxr-xr-x | vps/functions/usage.sh | 22 | ||||
-rwxr-xr-x | vps/functions/verify_ptr.sh | 29 | ||||
-rwxr-xr-x | vps/genesis_squeaky.sh | 44 | ||||
-rwxr-xr-x | vps/genesisctl.sh | 104 |
17 files changed, 558 insertions, 0 deletions
diff --git a/vps/.env b/vps/.env new file mode 100644 index 0000000..1be49f0 --- /dev/null +++ b/vps/.env @@ -0,0 +1,5 @@ +LINODE_API_TOKEN=8140523e8d64f16f490b70096b04d221a44236eda552b0caa35fe9be35442f6d +# Cloudflare API +CF_API_TOKEN="PrUbZD1bj0ky1T32waiis2hp91e4Az1ZiCule9Ys" +CF_ZONE_ID="c9b0c727c2c55594f62d38227133e3ac" +CF_DOMAIN="failzero.net" diff --git a/vps/check-hardened.sh b/vps/check-hardened.sh new file mode 100755 index 0000000..cdaeef8 --- /dev/null +++ b/vps/check-hardened.sh @@ -0,0 +1,37 @@ +#!/usr/bin/env bash +# check-hardened.sh - Scan all known Genesis VPSes for hardening status +# Requirements: ssh access to all VPSes by label or IP + +LOG_BASE="/home/doc/vpslogs" +MARKER_FILE="/var/log/genesis-hardened.ok" + +if [ ! -d "$LOG_BASE" ]; then + echo "ā Log directory $LOG_BASE does not exist. Are you running this on Krang?" + exit 1 +fi + +cd "$LOG_BASE" || exit 1 + +echo "š Scanning for hardened Genesis VPSes..." +echo + +for LOG in *.log; do + VPS_LABEL="${LOG%.log}" + LAST_KNOWN_IP=$(grep -Eo '\([0-9]+\.[0-9]+\.[0-9]+\.[0-9]+\)' "$LOG" | tail -1 | tr -d '()') + + if [ -z "$LAST_KNOWN_IP" ]; then + echo "ā ļø $VPS_LABEL: No IP found in log. Skipping." + continue + fi + + echo -n "š§ $VPS_LABEL ($LAST_KNOWN_IP): " + + ssh -o ConnectTimeout=5 -o StrictHostKeyChecking=no root@"$LAST_KNOWN_IP" "test -f $MARKER_FILE" >/dev/null 2>&1 + + if [ $? -eq 0 ]; then + echo "ā
Hardened" + else + echo "ā Not marked as hardened" + fi + +done diff --git a/vps/check_rdns_retry.sh b/vps/check_rdns_retry.sh new file mode 100755 index 0000000..b11208b --- /dev/null +++ b/vps/check_rdns_retry.sh @@ -0,0 +1,27 @@ +#!/bin/bash +set -e +[ -f ".env" ] && source .env +LOGFILE="/home/doc/vpslogs/pending_rdns.log" +TMPFILE="/tmp/rdns_retry.log" + +touch "$TMPFILE" + +while IFS="|" read -r LINODE_ID IP LABEL; do + CURRENT_RDNS=$(dig -x "$IP" +short) + EXPECTED_RDNS="$LABEL.failzero.net." + + if [[ "$CURRENT_RDNS" == "$EXPECTED_RDNS" ]]; then + echo "ā
$IP already has correct rDNS ($CURRENT_RDNS)" + else + echo "ā³ rDNS not set correctly for $LABEL ($IP). Retrying..." + RESPONSE=$(curl -s -X PUT "https://api.linode.com/v4/linode/instances/$LINODE_ID/ips/$IP" \ + -H "Authorization: Bearer $LINODE_API_TOKEN" \ + -H "Content-Type: application/json" \ + -d '{"rdns": "'"$LABEL.failzero.net"'"}') + echo "š Retry result for $IP: $RESPONSE" + fi + + echo "$LINODE_ID|$IP|$LABEL" >> "$TMPFILE" +done < "$LOGFILE" + +mv "$TMPFILE" "$LOGFILE" diff --git a/vps/functions/destroy_vps_by_label.sh b/vps/functions/destroy_vps_by_label.sh new file mode 100755 index 0000000..09d807e --- /dev/null +++ b/vps/functions/destroy_vps_by_label.sh @@ -0,0 +1,28 @@ +destroy_vps_by_label() { + LABEL="$1" + echo "Looking for VPS with label '$LABEL'..." + LINODE_ID=$(curl -s -H "Authorization: Bearer $LINODE_API_TOKEN" \ + https://api.linode.com/v4/linode/instances | \ + jq -r --arg LABEL "$LABEL" '.data[] | select(.label == $LABEL) | .id') + + if [ -z "$LINODE_ID" ]; then + echo "Error: No Linode found with label '$LABEL'" + exit 1 + fi + + read -rp "Are you sure you want to destroy VPS '$LABEL' (ID: $LINODE_ID)? [y/N] " confirm + if [[ "$confirm" =~ ^[Yy]$ ]]; then + echo "Destroying Linode with ID $LINODE_ID (label: $LABEL)..." + HTTP_STATUS=$(curl -s -o /dev/null -w "%{http_code}" -X DELETE \ + https://api.linode.com/v4/linode/instances/$LINODE_ID \ + -H "Authorization: Bearer $LINODE_API_TOKEN") + + if [[ "$HTTP_STATUS" == "204" ]]; then + echo "ā
Linode $LABEL (ID $LINODE_ID) has been destroyed." + else + echo "ā Failed to destroy VPS. HTTP status: $HTTP_STATUS" + fi + else + echo "Cancelled. VPS '$LABEL' not destroyed." + fi +} diff --git a/vps/functions/disable_backups_by_label.sh b/vps/functions/disable_backups_by_label.sh new file mode 100755 index 0000000..417bdb8 --- /dev/null +++ b/vps/functions/disable_backups_by_label.sh @@ -0,0 +1,23 @@ +disable_backups_by_label() { + LABEL="$1" + LINODE_ID=$(curl -s -H "Authorization: Bearer $LINODE_API_TOKEN" \ + https://api.linode.com/v4/linode/instances | \ + jq -r --arg LABEL "$LABEL" '.data[] | select(.label == $LABEL) | .id') + + if [ -z "$LINODE_ID" ]; then + echo "ā No Linode found with label '$LABEL'" + exit 1 + fi + + echo "Disabling backups for Linode '$LABEL' (ID: $LINODE_ID)..." + + HTTP_STATUS=$(curl -s -o /dev/null -w "%{http_code}" -X POST \ + https://api.linode.com/v4/linode/instances/$LINODE_ID/backups/disable \ + -H "Authorization: Bearer $LINODE_API_TOKEN") + + if [[ "$HTTP_STATUS" == "200" ]]; then + echo "ā
Backups disabled for Linode $LABEL." + else + echo "ā Failed to disable backups (HTTP $HTTP_STATUS)" + fi +} diff --git a/vps/functions/disable_ip.sh b/vps/functions/disable_ip.sh new file mode 100644 index 0000000..0021b74 --- /dev/null +++ b/vps/functions/disable_ip.sh @@ -0,0 +1,18 @@ +disable_ip() { + local ip="$1" + + if [[ -z "$ip" ]]; then + echo "[!] No IP specified." + exit 1 + fi + + echo "[*] Disabling access to VPS with IP: $ip" + + # Block all traffic to/from that IP via iptables + iptables -A INPUT -s "$ip" -j DROP + iptables -A OUTPUT -d "$ip" -j DROP + + echo "$ip - disabled on $(date)" >> /var/log/genesis-disabled.log + + echo "[ā] $ip has been blocked and logged." +} diff --git a/vps/functions/enable_backups_by_label.sh b/vps/functions/enable_backups_by_label.sh new file mode 100755 index 0000000..08fb31d --- /dev/null +++ b/vps/functions/enable_backups_by_label.sh @@ -0,0 +1,23 @@ +enable_backups_by_label() { + LABEL="$1" + LINODE_ID=$(curl -s -H "Authorization: Bearer $LINODE_API_TOKEN" \ + https://api.linode.com/v4/linode/instances | \ + jq -r --arg LABEL "$LABEL" '.data[] | select(.label == $LABEL) | .id') + + if [ -z "$LINODE_ID" ]; then + echo "ā No Linode found with label '$LABEL'" + exit 1 + fi + + echo "Enabling backups for Linode '$LABEL' (ID: $LINODE_ID)..." + + HTTP_STATUS=$(curl -s -o /dev/null -w "%{http_code}" -X POST \ + https://api.linode.com/v4/linode/instances/$LINODE_ID/backups/enable \ + -H "Authorization: Bearer $LINODE_API_TOKEN") + + if [[ "$HTTP_STATUS" == "200" ]]; then + echo "ā
Backups enabled for Linode $LABEL." + else + echo "ā Failed to enable backups (HTTP $HTTP_STATUS)" + fi +} diff --git a/vps/functions/list_all_vps.sh b/vps/functions/list_all_vps.sh new file mode 100755 index 0000000..8ce99eb --- /dev/null +++ b/vps/functions/list_all_vps.sh @@ -0,0 +1,9 @@ +list_all_vps() { + curl -s -H "Authorization: Bearer $LINODE_API_TOKEN" \ + https://api.linode.com/v4/linode/instances | \ + jq -r ' + .data[] | [.label, .id, .region, .type, .ipv4[0], .status] | + @tsv' | column -t -s $'\t' | \ + awk 'BEGIN { print "LABEL ID REGION TYPE IP STATUS" } + { printf "%-11s %-10s %-10s %-16s %-15s %s\n", $1, $2, $3, $4, $5, $6 }' +} diff --git a/vps/functions/provision.sh b/vps/functions/provision.sh new file mode 100755 index 0000000..f6e9d39 --- /dev/null +++ b/vps/functions/provision.sh @@ -0,0 +1,135 @@ +provision_vps() { + LABEL="$1" + REGION="$2" + TYPE="$3" + IMAGE="$4" + ROOT_PASS="${5:-$(openssl rand -base64 16)}" + + if [[ "$LINODE_API_TOKEN" == "REPLACE_WITH_YOUR_LINODE_API_TOKEN" ]]; then + echo "ā Error: You must set your LINODE_API_TOKEN at the top of this script." + exit 1 + fi + + CLOUD_INIT=$(cat <<EOF +#cloud-config +hostname: genesis-vps +manage_etc_hosts: true +write_files: + - path: /usr/local/bin/genesis_squeaky.sh + permissions: '0755' + content: | + #!/bin/bash + set -e + GEN_HOSTNAME="genesis-vps-$(head /dev/urandom | tr -dc A-Za-z0-9 | head -c 6)" + LOGDIR="/home/doc/vpslogs" + LOGFILE="$LOGDIR/$GEN_HOSTNAME.log" + IP_ADDR=$(hostname -I | awk '{print $1}') + + iptables -A OUTPUT -p icmp --icmp-type time-exceeded -j DROP + iptables -A INPUT -p udp --dport 33434:33534 -j DROP + iptables -A INPUT -p tcp --dport 33434:33534 -j DROP + + hostnamectl set-hostname "$GEN_HOSTNAME" + sed -i "s/^127.0.1.1.*/127.0.1.1 $GEN_HOSTNAME/" /etc/hosts + + systemctl stop linode-cloudinit 2>/dev/null || true + systemctl disable linode-cloudinit 2>/dev/null || true + touch /etc/cloud/cloud-init.disabled + rm -rf /etc/cloud /var/lib/cloud /var/log/cloud-init.log + + rm -f /etc/motd /etc/update-motd.d/linode + rm -rf /usr/share/linode* + rm -f /etc/apt/sources.list.d/linode.list + apt remove --purge -y linode-cli linode-config 2>/dev/null || true + + echo "[genesisctl] Attempting to log to Krang via webhook..." >> /var/log/genesis-harden.log + curl -s -X POST -H "Content-Type: application/json" \ + -d "{\"host\": \"$GEN_HOSTNAME\", \"ip\": \"$IP_ADDR\", \"timestamp\": \"$(date)\"}" \ + http://krang.core.sshjunkie.com:8080/genesislog >> /var/log/genesis-harden.log 2>&1 || echo "[genesisctl] Krang webhook logging failed" >> /var/log/genesis-harden.log + + touch /var/log/genesis-hardened.ok + +runcmd: + - [ bash, /usr/local/bin/genesis_squeaky.sh ] +EOF +) + + USER_DATA=$(echo "$CLOUD_INIT" | base64 -w 0) + + echo "Provisioning VPS '$LABEL' in $REGION with type $TYPE and image $IMAGE..." + TMP_FILE=$(mktemp) + JSON_PAYLOAD=$(cat <<EOF +{ + "label": "$LABEL", + "region": "$REGION", + "type": "$TYPE", + "image": "$IMAGE", + "authorized_users": [], + "root_pass": "$ROOT_PASS", + "booted": true, + "metadata": { + "user_data": "$USER_DATA" + } +} +EOF +) + + HTTP_STATUS=$(curl -s -o "$TMP_FILE" -w "%{http_code}" -X POST https://api.linode.com/v4/linode/instances \ + -H "Content-Type: application/json" \ + -H "Authorization: Bearer $LINODE_API_TOKEN" \ + -d "$JSON_PAYLOAD") + + echo -e "\n--- HTTP STATUS: $HTTP_STATUS ---" + echo "--- RAW RESPONSE: ---" + cat "$TMP_FILE" + + if [[ "$HTTP_STATUS" != "200" && "$HTTP_STATUS" != "201" ]]; then + echo -e "\nā Failed to provision VPS (HTTP $HTTP_STATUS)" + jq . "$TMP_FILE" + exit 1 + fi + + echo -e "\nā
VPS provisioned:" + IP=$(jq -r '.ipv4[0]' "$TMP_FILE") + LINODE_ID=$(jq -r '.id' "$TMP_FILE") + echo "Label: $LABEL" + echo "IP Address: $IP" + echo "Root Password: $ROOT_PASS" + + # Add DNS record to Cloudflare + echo "š” Adding A record for $LABEL.$CF_DOMAIN ā $IP..." + echo "[DEBUG] CF_API_TOKEN=$CF_API_TOKEN" + curl -s -X POST "https://api.cloudflare.com/client/v4/zones/$CF_ZONE_ID/dns_records" \ + -H "Authorization: Bearer $CF_API_TOKEN" \ + -H "Content-Type: application/json" \ + --data-binary @<(cat <<JSON +{ + "type": "A", + "name": "$LABEL.$CF_DOMAIN", + "content": "$IP", + "ttl": 120, + "proxied": false +} +JSON +) | jq '.success, .errors, .messages' + + echo "ā³ Waiting indefinitely for DNS to propagate before setting rDNS..." +i=1 +while true; do + CURRENT_IP=$(dig +short "$LABEL.$CF_DOMAIN") + if [[ "$CURRENT_IP" == "$IP" ]]; then + echo "ā
A record resolved. Setting rDNS..." + curl -s -X PUT "https://api.linode.com/v4/linode/instances/$LINODE_ID/ips/$IP" \ + -H "Authorization: Bearer $LINODE_API_TOKEN" \ + -H "Content-Type: application/json" \ + -d '{"rdns": "'"$LABEL.$CF_DOMAIN"'"}' + break + fi + echo "ā³ Attempt $i: DNS not ready. Waiting 15s..." + sleep 15 + ((i++)) +done + + + echo "$LINODE_ID|$IP|$LABEL" >> /home/doc/vpslogs/pending_rdns.log +} diff --git a/vps/functions/reboot_vps.sh b/vps/functions/reboot_vps.sh new file mode 100755 index 0000000..2741b9c --- /dev/null +++ b/vps/functions/reboot_vps.sh @@ -0,0 +1,7 @@ +reboot_vps() { + LINODE_ID="$1" + echo "Rebooting Linode VPS ID $LINODE_ID..." + + curl -s -X POST https://api.linode.com/v4/linode/instances/$LINODE_ID/reboot \ + -H "Authorization: Bearer $LINODE_API_TOKEN" | jq +} diff --git a/vps/functions/resize_vps.sh b/vps/functions/resize_vps.sh new file mode 100755 index 0000000..c06ea91 --- /dev/null +++ b/vps/functions/resize_vps.sh @@ -0,0 +1,27 @@ +resize_vps() { + LABEL="$1" + NEW_TYPE="$2" + + LINODE_ID=$(curl -s -H "Authorization: Bearer $LINODE_API_TOKEN" \ + https://api.linode.com/v4/linode/instances | \ + jq -r --arg LABEL "$LABEL" '.data[] | select(.label == $LABEL) | .id') + + if [ -z "$LINODE_ID" ]; then + echo "ā No Linode found with label '$LABEL'" + exit 1 + fi + + echo "Resizing Linode '$LABEL' to type '$NEW_TYPE'..." + + HTTP_STATUS=$(curl -s -o /dev/null -w "%{http_code}" -X POST \ + -H "Content-Type: application/json" \ + -H "Authorization: Bearer $LINODE_API_TOKEN" \ + -d '{"type": "'"$NEW_TYPE"'"}' \ + https://api.linode.com/v4/linode/instances/$LINODE_ID/resize) + + if [[ "$HTTP_STATUS" == "200" ]]; then + echo "ā
Linode $LABEL resized to $NEW_TYPE." + else + echo "ā Failed to resize VPS. HTTP status: $HTTP_STATUS" + fi +} diff --git a/vps/functions/safe_create_dataset.sh b/vps/functions/safe_create_dataset.sh new file mode 100755 index 0000000..1960e55 --- /dev/null +++ b/vps/functions/safe_create_dataset.sh @@ -0,0 +1,12 @@ +safe_create_dataset() { + FULLPATH="$1" + + # Remove any trailing slash + FULLPATH="${FULLPATH%/}" + + POOL="${FULLPATH%%/*}" + DATASET="${FULLPATH#*/}" + + echo "š° Connecting to Shredder to safely create '${POOL}/${DATASET}'..." + ssh shredder "/usr/local/bin/genesis-safe-zfs.sh $POOL $DATASET" +} diff --git a/vps/functions/status_vps.sh b/vps/functions/status_vps.sh new file mode 100755 index 0000000..91996e9 --- /dev/null +++ b/vps/functions/status_vps.sh @@ -0,0 +1,8 @@ +status_vps() { + LABEL="$1" + curl -s -H "Authorization: Bearer $LINODE_API_TOKEN" \ + https://api.linode.com/v4/linode/instances | \ + jq -r --arg LABEL "$LABEL" ' + .data[] | select(.label == $LABEL) | + "Label: \(.label)\nID: \(.id)\nRegion: \(.region)\nType: \(.type)\nStatus: \(.status)\nIP: \(.ipv4[0])\nCreated: \(.created)"' +} diff --git a/vps/functions/usage.sh b/vps/functions/usage.sh new file mode 100755 index 0000000..25861b8 --- /dev/null +++ b/vps/functions/usage.sh @@ -0,0 +1,22 @@ +#!/bin/bash + +function usage() { + echo "Usage: genesisctl [command]" + echo "Commands:" + echo " watch-abuse Start abuse monitoring via IPTables" +} + +function watch_abuse() { + echo "[*] Launching abuse watch via screen..." + screen -dmS abusewatch /usr/local/bin/genesisctl-watch-abuse.sh + echo "[ā] Abuse watch running in detached screen session 'abusewatch'" +} + +case "$1" in + watch-abuse) + watch_abuse + ;; + *) + usage + ;; +esac diff --git a/vps/functions/verify_ptr.sh b/vps/functions/verify_ptr.sh new file mode 100755 index 0000000..8ce2f6c --- /dev/null +++ b/vps/functions/verify_ptr.sh @@ -0,0 +1,29 @@ +verify_ptr() { + LABEL="$1" + IP=$(curl -s -H "Authorization: Bearer $LINODE_API_TOKEN" https://api.linode.com/v4/linode/instances \ + | jq -r --arg LABEL "$LABEL" '.data[] | select(.label == $LABEL) | .ipv4[0]') + LINODE_ID=$(curl -s -H "Authorization: Bearer $LINODE_API_TOKEN" https://api.linode.com/v4/linode/instances \ + | jq -r --arg LABEL "$LABEL" '.data[] | select(.label == $LABEL) | .id') + + if [[ -z "$IP" || -z "$LINODE_ID" ]]; then + echo "ā Could not retrieve IP or Linode ID for label '$LABEL'" + return 1 + fi + + echo "Re-attempting rDNS update for $LABEL ($IP)..." + PTR_NAME="${LABEL}.doinkle.pro" + RDNS_PAYLOAD=$(cat <<EOF +{ + "rdns": "$PTR_NAME" +} +EOF +) + + RESPONSE=$(curl -s -w "\nHTTP Status: %{http_code}\n" -X PUT \ + -H "Authorization: Bearer $LINODE_API_TOKEN" \ + -H "Content-Type: application/json" \ + -d "$RDNS_PAYLOAD" \ + "https://api.linode.com/v4/linode/instances/$LINODE_ID/ips/$IP") + + echo "$RESPONSE" +} diff --git a/vps/genesis_squeaky.sh b/vps/genesis_squeaky.sh new file mode 100755 index 0000000..431227b --- /dev/null +++ b/vps/genesis_squeaky.sh @@ -0,0 +1,44 @@ +#!/bin/bash +set -e + +# === CONFIG === +GEN_HOSTNAME="genesis-vps-$RANDOM" +TG_API_URL="https://api.telegram.org/bot<OPTIONAL-BOT>/sendMessage" +TG_CHAT_ID="<OPTIONAL-ID>" + +# === STEP 1: Obfuscate Traceroute (ICMP & UDP/TCP Ports) === +echo "[*] Obfuscating traceroute and TTL paths..." +iptables -A OUTPUT -p icmp --icmp-type time-exceeded -j DROP +iptables -A INPUT -p udp --dport 33434:33534 -j DROP +iptables -A INPUT -p tcp --dport 33434:33534 -j DROP +echo "[+] Firewall rules added." + +# === STEP 2: Set a Neutral Hostname === +echo "[*] Setting hostname to $GEN_HOSTNAME" +hostnamectl set-hostname "$GEN_HOSTNAME" +sed -i "s/^127.0.1.1.*/127.0.1.1 $GEN_HOSTNAME/" /etc/hosts +echo "[+] Hostname set." + +# === STEP 3: Remove Linode Metadata Access === +echo "[*] Disabling Linode metadata agent (if present)..." +systemctl stop linode-cloudinit 2>/dev/null || true +systemctl disable linode-cloudinit 2>/dev/null || true +touch /etc/cloud/cloud-init.disabled +rm -rf /etc/cloud /var/lib/cloud /var/log/cloud-init.log +echo "[+] Cloud-init neutered." + +# === STEP 4: Scrub Linode Stuff === +echo "[*] Scrubbing Linode fingerprints..." +rm -f /etc/motd /etc/update-motd.d/linode +rm -rf /usr/share/linode* +rm -f /etc/apt/sources.list.d/linode.list +apt remove --purge -y linode-cli linode-config 2>/dev/null || true +yum remove -y linode-cli linode-config 2>/dev/null || true +echo "[+] Linode packages and branding removed." + +# === STEP 5: Optional Telegram Notice === +# Uncomment if you want to alert yourself when a VPS is hardened +# curl -s -X POST "$TG_API_URL" -d chat_id="$TG_CHAT_ID" -d text="Genesis VPS hardened: $GEN_HOSTNAME is stealth-ready." > /dev/null + +# === STEP 6: Final Touch === +echo "[ā
] Genesis VPS hardened. You are now off-the-grid and good to go." diff --git a/vps/genesisctl.sh b/vps/genesisctl.sh new file mode 100755 index 0000000..21fdf7d --- /dev/null +++ b/vps/genesisctl.sh @@ -0,0 +1,104 @@ +#!/usr/bin/env bash +# genesisctl - Genesis VPS Provisioning and Reboot CLI +# Usage: +# genesisctl provision <label> <region> <type> <image> [root_pass] +# genesisctl reboot <linode-id> +# genesisctl list regions|types|images +# genesisctl ultra <label> [root_pass] +# genesisctl safe <label> [root_pass] +# genesisctl micro <label> [root_pass] +# genesisctl mastodon <label> [root_pass] +# genesisctl destroy <label> + +LINODE_API_TOKEN="f8b1552bf1f2f791e16fed0c1474d56014330de1c33810527523e44a7389cb6f" + +# Package presets +PACKAGE_ULTRA_REGION="us-east" +PACKAGE_ULTRA_TYPE="g6-dedicated-4" +PACKAGE_ULTRA_IMAGE="linode/ubuntu22.04" + +PACKAGE_SAFE_REGION="us-east" +PACKAGE_SAFE_TYPE="g6-standard-2" +PACKAGE_SAFE_IMAGE="linode/ubuntu22.04" + +PACKAGE_MICRO_REGION="us-east" +PACKAGE_MICRO_TYPE="g6-nanode-1" +PACKAGE_MICRO_IMAGE="linode/ubuntu22.04" + +PACKAGE_MASTODON_REGION="us-east" +PACKAGE_MASTODON_TYPE="g6-standard-4" +PACKAGE_MASTODON_IMAGE="linode/ubuntu22.04" + +for f in functions/*.sh; do source "$f"; done + +# Helper for DNS pre-propagation check (used after provisioning) +await_dns_propagation() { + HOSTNAME="$1" + EXPECTED_IP="$2" + + echo "ā³ Waiting for DNS A record to propagate for $HOSTNAME to $EXPECTED_IP..." + for i in {1..10}; do + ACTUAL_IP=$(dig +short "$HOSTNAME") + if [[ "$ACTUAL_IP" == "$EXPECTED_IP" ]]; then + echo "ā
DNS A record found: $HOSTNAME ā $EXPECTED_IP" + return 0 + fi + echo "...still waiting ($i/10)..." + sleep 10 + done + echo "ā DNS A record for $HOSTNAME did not propagate in time. Skipping rDNS setup." + return 1 +} + +case "$1" in + provision) + provision_vps "$2" "$3" "$4" "$5" "$6" + ;; + reboot) + reboot_vps "$2" + ;; + destroy) + destroy_vps_by_label "$2" + ;; + safe) + provision_vps "$2" "$PACKAGE_SAFE_REGION" "$PACKAGE_SAFE_TYPE" "$PACKAGE_SAFE_IMAGE" "$3" + ;; + ultra) + provision_vps "$2" "$PACKAGE_ULTRA_REGION" "$PACKAGE_ULTRA_TYPE" "$PACKAGE_ULTRA_IMAGE" "$3" + ;; + micro) + provision_vps "$2" "$PACKAGE_MICRO_REGION" "$PACKAGE_MICRO_TYPE" "$PACKAGE_MICRO_IMAGE" "$3" + ;; + mastodon) + provision_vps "$2" "$PACKAGE_MASTODON_REGION" "$PACKAGE_MASTODON_TYPE" "$PACKAGE_MASTODON_IMAGE" "$3" + ;; + backup) + enable_backups_by_label "$2" + ;; + disable-backup) + disable_backups_by_label "$2" + ;; + status) + status_vps "$2" + ;; + listvps) + list_all_vps + ;; + disable) + disable_ip "$2" + ;; + resize) + resize_vps "$2" "$3" + ;; + safe-create) + safe_create_dataset "$2" "$3" + ;; + verify_ptr) + verify_ptr "$2" + ;; + *) + echo "Usage: $0 <command> [...]" + echo "Available commands: provision, reboot, destroy, safe, ultra, micro, mastodon" + exit 1 + ;; +esac |