Skip to content

Instantly share code, notes, and snippets.

@gsj1377
Last active September 27, 2025 00:03
Show Gist options
  • Select an option

  • Save gsj1377/29be655f01246a9b1810c3492193e543 to your computer and use it in GitHub Desktop.

Select an option

Save gsj1377/29be655f01246a9b1810c3492193e543 to your computer and use it in GitHub Desktop.
Offcloud IP Management Script
#!/bin/bash
# Offcloud IP Management Script
#
# This script automates adding the current public IP to your Offcloud account.
# It requires curl and jq to be installed.
# --- Configuration ---
# IMPORTANT: Hardcoding credentials is not secure.
# Consider using environment variables or a secrets management tool.
EMAIL="<offcloud-email>"
PASSWORD="<offcloud-password>"
BASE_URL="https://offcloud.com"
COOKIE_JAR="/tmp/offcloud_cookies.txt"
HOST="" # hostname-linked-to-home-dynamic-ip
IPS="" # example IPS="1.1.1.1;8.8.8.8"
# --- Helper Functions ---
# Function to print messages
log() {
echo -e "[$(date +'%Y-%m-%d %H:%M:%S')] $1" >&2
}
# Function to validate an IP address
is_valid_ip() {
local ip=$1
local stat=1
if [[ $ip =~ ^[0-9]{1,3}\.[0-9]{1,3}\.[0-9]{1,3}\.[0-9]{1,3}$ ]]; then
OIFS=$IFS
IFS='.'
ip=($ip)
IFS=$OIFS
[[ ${ip[0]} -le 255 && ${ip[1]} -le 255 && ${ip[2]} -le 255 && ${ip[3]} -le 255 ]]
stat=$?
fi
return $stat
}
# Function to get the current public IP
get_current_ip() {
local IP
IP=$(curl -s https://api.ipify.org)
if [ -z "$IP" ]; then
log "❌ Failed to get IP from ipify.org, trying httpbin.org..."
IP=$(curl -s https://httpbin.org/ip | jq -r '.origin')
fi
if [ -z "$IP" ]; then
log "❌ Could not determine public IP address."
return 1
fi
echo "$IP"
}
# Function to get the IP of a given host
get_host_ip() {
local HOSTNAME=$1
local IP
IP=$(dig +short "$HOSTNAME" 2>/dev/null || true)
if [ -z "$IP" ]; then
log "⚠️ Could not resolve IP for $HOSTNAME."
fi
echo "$IP"
}
# Function to log in to Offcloud
login() {
LOGIN_URL="$BASE_URL/api/login"
LOGIN_PAYLOAD=$(cat <<EOF
{
"username": "$EMAIL",
"password": "$PASSWORD"
}
EOF
)
HTTP_RESPONSE=$(curl -s -w "\n%{http_code}" \
-X POST "$LOGIN_URL" \
-H "Content-Type: application/json;charset=utf-8" \
-c "$COOKIE_JAR" \
--data "$LOGIN_PAYLOAD")
HTTP_BODY=$(echo "$HTTP_RESPONSE" | sed '$d')
HTTP_STATUS=$(echo "$HTTP_RESPONSE" | tail -n 1)
if [ "$HTTP_STATUS" -ne 200 ]; then
log "❌ Login failed with status code $HTTP_STATUS."
log " Response: $HTTP_BODY"
exit 1
fi
USER_ID=$(echo "$HTTP_BODY" | jq -r '.userId')
if [ "$USER_ID" != "null" ] && [ -n "$USER_ID" ]; then
log "βœ… Login successful. User ID: $USER_ID"
else
ERROR_MSG=$(echo "$HTTP_BODY" | jq -r '.error // "Unknown error"')
log "❌ Login failed: $ERROR_MSG"
exit 1
fi
}
# Function to get currently registered IPs
get_registered_ips() {
IPS_URL="$BASE_URL/account/registered-ips"
HTTP_RESPONSE=$(curl -s -w "\n%{http_code}" \
-X POST "$IPS_URL" \
-H "Content-Type: application/json;charset=utf-8" \
-b "$COOKIE_JAR")
HTTP_BODY=$(echo "$HTTP_RESPONSE" | sed '$d')
HTTP_STATUS=$(echo "$HTTP_RESPONSE" | tail -n 1)
if [ "$HTTP_STATUS" -ne 200 ]; then
log "❌ Failed to get registered IPs. Status: $HTTP_STATUS"
log " Response: $HTTP_BODY"
REGISTERED_IPS=""
return 1
fi
local ips=$(echo "$HTTP_BODY" | jq -r '.data[].ip')
local valid_ips=()
for ip in $ips; do
if is_valid_ip "$ip"; then
valid_ips+=("$ip")
else
log "⚠️ Found invalid IP in registered list: $ip"
fi
done
REGISTERED_IPS=("${valid_ips[@]}")
log "βœ… Found registered IPs: \n$(printf "%s\n" "${REGISTERED_IPS[@]}")"
}
# Function to add an IP address
add_ip() {
local IP_TO_ADD=$1
log "πŸ”„ Adding IP address $IP_TO_ADD..."
ADD_IP_URL="$BASE_URL/account/ip/add"
ADD_PAYLOAD=$(cat <<EOF
{
"ip": "$IP_TO_ADD"
}
EOF
)
HTTP_RESPONSE=$(curl -s -w "\n%{http_code}" \
-X POST "$ADD_IP_URL" \
-H "Content-Type: application/json;charset=utf-8" \
-b "$COOKIE_JAR" \
--data "$ADD_PAYLOAD")
HTTP_BODY=$(echo "$HTTP_RESPONSE" | sed '$d')
HTTP_STATUS=$(echo "$HTTP_RESPONSE" | tail -n 1)
if [ "$HTTP_STATUS" -eq 200 ]; then
log "βœ… Server accepted request to add IP: $IP_TO_ADD"
else
log "❌ Failed to add IP address. Status: $HTTP_STATUS"
log " Response: $HTTP_BODY"
return 1
fi
}
# Function to remove an IP address
remove_ip() {
local IP_TO_REMOVE=$1
log "πŸ”„ Removing IP address $IP_TO_REMOVE..."
REMOVE_IP_URL="$BASE_URL/account/ip/remove"
REMOVE_PAYLOAD=$(cat <<EOF
{
"ip": "$IP_TO_REMOVE"
}
EOF
)
HTTP_RESPONSE=$(curl -s -w "\n%{http_code}" \
-X POST "$REMOVE_IP_URL" \
-H "Content-Type: application/json;charset=utf-8" \
-b "$COOKIE_JAR" \
--data "$REMOVE_PAYLOAD")
HTTP_BODY=$(echo "$HTTP_RESPONSE" | sed '$d')
HTTP_STATUS=$(echo "$HTTP_RESPONSE" | tail -n 1)
if [ "$HTTP_STATUS" -eq 200 ]; then
log "βœ… Server accepted request to remove IP: $IP_TO_REMOVE"
else
log "❌ Failed to remove IP address. Status: $HTTP_STATUS"
log " Response: $HTTP_BODY"
return 1
fi
}
# Function to remove all IPs except the ones we want to manage
remove_other_ips() {
log "🧹 Removing all other IP addresses..."
for IP_TO_CHECK in "${REGISTERED_IPS[@]}"; do
if ! is_valid_ip "$IP_TO_CHECK"; then
log "⚠️ Skipping invalid IP in registered list: $IP_TO_CHECK"
continue
fi
SHOULD_KEEP=false
for IP_TO_KEEP in "${IPS_TO_MANAGE[@]}"; do
if [ "$IP_TO_CHECK" == "$IP_TO_KEEP" ]; then
SHOULD_KEEP=true
break
fi
done
if [ "$SHOULD_KEEP" == "false" ]; then
remove_ip "$IP_TO_CHECK"
fi
done
}
# --- Main Script ---
# Clean up cookie jar on exit
trap 'rm -f "$COOKIE_JAR"' EXIT
main() {
log "🌐 Offcloud IP Manager"
log "=============================="
# 1. Login to Offcloud
login
# 2. Get registered IPs
get_registered_ips
# 3. Define list of IPs to manage
declare -a IPS_TO_MANAGE
# Add current public IP
CURRENT_IP=$(get_current_ip)
if [ -n "$CURRENT_IP" ]; then
log "βœ… Public IP is: $CURRENT_IP"
IPS_TO_MANAGE+=("$CURRENT_IP")
else
log "⚠️ Could not get current public IP. Skipping."
fi
# Add IP for the specified host
HOST_IP=$(get_host_ip "$HOST")
if [ -n "$HOST_IP" ]; then
log "βœ… IP for $HOST is: $HOST_IP"
IPS_TO_MANAGE+=("$HOST_IP")
else
log "⚠️ Could not get IP for $HOST. Skipping."
fi
# Add static IPs from IPS variable
if [ -n "$IPS" ]; then
log "ℹ️ Processing static IPs from configuration..."
for IP in $(echo $IPS | tr ";" " "); do
if is_valid_ip "$IP"; then
log "βœ… Adding static IP: $IP"
IPS_TO_MANAGE+=("$IP")
else
log "⚠️ Invalid static IP found: $IP. Skipping."
fi
done
fi
# Remove duplicate IPs
IPS_TO_MANAGE=($(printf "%s\n" "${IPS_TO_MANAGE[@]}" | sort -u))
if [ ${#IPS_TO_MANAGE[@]} -eq 0 ]; then
log "❌ No valid IPs to manage. Exiting."
exit 1
fi
log "ℹ️ IPs to manage: ${IPS_TO_MANAGE[*]}"
# 4. Add any missing IPs
for IP_TO_CHECK in "${IPS_TO_MANAGE[@]}"; do
if [[ " ${REGISTERED_IPS[*]} " =~ " ${IP_TO_CHECK} " ]]; then
log "βœ… IP address $IP_TO_CHECK is already registered."
else
log "ℹ️ IP address $IP_TO_CHECK is not registered. Adding it..."
add_ip "$IP_TO_CHECK"
fi
done
# 5. Verify that all required IPs are now registered
log "πŸ” Verifying all IPs after additions..."
sleep 5 # Give the server a moment to process the changes
get_registered_ips # Refresh the list of registered IPs
VERIFICATION_FAILED=false
for IP_TO_VERIFY in "${IPS_TO_MANAGE[@]}"; do
if [[ " ${REGISTERED_IPS[*]} " =~ " ${IP_TO_VERIFY} " ]]; then
log "βœ… Verification successful for IP: $IP_TO_VERIFY"
else
log "❌ Verification failed for IP: $IP_TO_VERIFY"
VERIFICATION_FAILED=true
fi
done
if $VERIFICATION_FAILED; then
log "❌ One or more IPs could not be verified."
log " Current registered IPs: $REGISTERED_IPS"
exit 1
else
log "πŸŽ‰ All required IPs are successfully registered."
fi
# 6. Remove any other IPs
remove_other_ips
get_registered_ips # Refresh the list of registered IPs
}
main
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment