#!/usr/bin/env bash set -euo pipefail # Namecheap API CLI wrapper # Usage: ./namecheap.sh [options] NAMECHEAP_API_URL="https://api.namecheap.com/xml.response" CONFIG_FILE="$HOME/.namecheap-api" # Colors for output RED='\033[0;31m' GREEN='\033[0;32m' YELLOW='\033[1;33m' CYAN='\033[0;36m' NC='\033[0m' # No Color print_error() { echo -e "${RED}Error:${NC} $1" >&2; } print_success() { echo -e "${GREEN}✓${NC} $1"; } print_info() { echo -e "${CYAN}ℹ${NC} $1"; } print_warn() { echo -e "${YELLOW}⚠${NC} $1"; } # Load configuration load_config() { if [[ -f "$CONFIG_FILE" ]]; then # shellcheck source=/dev/null source "$CONFIG_FILE" fi } # Check if credentials are configured check_credentials() { load_config if [[ -z "${NAMECHEAP_API_USER:-}" || -z "${NAMECHEAP_API_KEY:-}" ]]; then print_error "Namecheap API credentials not configured." echo "" echo "Run './namecheap.sh setup' to configure your credentials." echo "" echo "You need:" echo " 1. Your Namecheap username" echo " 2. An API key from: https://ap.www.namecheap.com/settings/tools/apiaccess/" echo " 3. Your public IP whitelisted in the API settings" exit 1 fi } # Get public IP address get_public_ip() { curl -s https://api.ipify.org 2>/dev/null || curl -s https://ifconfig.me 2>/dev/null || echo "unknown" } # Make API request api_request() { local command="$1" shift local extra_params=("$@") check_credentials local client_ip client_ip=$(get_public_ip) local url="${NAMECHEAP_API_URL}?ApiUser=${NAMECHEAP_API_USER}&ApiKey=${NAMECHEAP_API_KEY}&UserName=${NAMECHEAP_API_USER}&Command=namecheap.${command}&ClientIp=${client_ip}" for param in "${extra_params[@]}"; do url="${url}&${param}" done local response response=$(curl -s "$url") # Check for errors in the response if echo "$response" | grep -q 'Status="ERROR"'; then local error_msg error_msg=$(echo "$response" | grep -oP '(?<=]*>\K[^<]+' 2>/dev/null || echo "$response" | sed -n 's/.*]*>\(.*\)<\/Err>.*/\1/p') print_error "API returned error: $error_msg" return 1 fi echo "$response" } # Parse domain into SLD and TLD parse_domain() { local domain="$1" local tld sld # Handle multi-part TLDs (e.g., co.uk, com.br) if echo "$domain" | grep -qE '\.(co|com|net|org|gov)\.[a-z]{2}$'; then tld=$(echo "$domain" | grep -oE '\.[^.]+\.[^.]+$' | sed 's/^\.//') sld=$(echo "$domain" | sed "s/\.${tld}$//") else tld="${domain##*.}" sld="${domain%.*}" fi echo "$sld" "$tld" } # Format XML DNS records as a table format_dns_records() { local xml="$1" # Extract host records echo "" printf "%-20s %-8s %-40s %-8s %-6s\n" "HOST" "TYPE" "ADDRESS" "TTL" "MXPREF" printf "%-20s %-8s %-40s %-8s %-6s\n" "----" "----" "-------" "---" "------" echo "$xml" | grep -oP '' | while read -r line; do local name type address ttl mxpref name=$(echo "$line" | grep -oP 'Name="\K[^"]+' || echo "") type=$(echo "$line" | grep -oP 'Type="\K[^"]+' || echo "") address=$(echo "$line" | grep -oP 'Address="\K[^"]+' || echo "") ttl=$(echo "$line" | grep -oP 'TTL="\K[^"]+' || echo "1800") mxpref=$(echo "$line" | grep -oP 'MXPref="\K[^"]+' || echo "-") printf "%-20s %-8s %-40s %-8s %-6s\n" "$name" "$type" "$address" "$ttl" "$mxpref" done echo "" } # Format domains list as a table format_domains_list() { local xml="$1" echo "" printf "%-30s %-12s %-12s %-10s\n" "DOMAIN" "EXPIRES" "LOCKED" "AUTO-RENEW" printf "%-30s %-12s %-12s %-10s\n" "------" "-------" "------" "----------" echo "$xml" | grep -oP '' | while read -r line; do local name expires locked autorenew name=$(echo "$line" | grep -oP 'Name="\K[^"]+' || echo "") expires=$(echo "$line" | grep -oP 'Expires="\K[^"]+' || echo "") locked=$(echo "$line" | grep -oP 'IsLocked="\K[^"]+' || echo "") autorenew=$(echo "$line" | grep -oP 'AutoRenew="\K[^"]+' || echo "") printf "%-30s %-12s %-12s %-10s\n" "$name" "$expires" "$locked" "$autorenew" done echo "" } # Commands cmd_setup() { echo "=== Namecheap API Setup ===" echo "" # Show public IP local public_ip public_ip=$(get_public_ip) print_info "Your public IP address is: ${CYAN}${public_ip}${NC}" echo "" echo "Make sure this IP is whitelisted at:" echo " https://ap.www.namecheap.com/settings/tools/apiaccess/" echo "" # Check existing config if [[ -f "$CONFIG_FILE" ]]; then load_config if [[ -n "${NAMECHEAP_API_USER:-}" ]]; then print_info "Existing configuration found for user: ${NAMECHEAP_API_USER}" echo "" # Test the connection echo "Testing API connection..." if api_request "domains.getList" "PageSize=1" > /dev/null 2>&1; then print_success "API connection successful!" else print_error "API connection failed. Please check your credentials and IP whitelist." fi return 0 fi fi # Prompt for credentials echo "Enter your Namecheap credentials:" echo "" read -rp " API Username: " api_user read -rsp " API Key: " api_key echo "" echo "" if [[ -z "$api_user" || -z "$api_key" ]]; then print_error "Both username and API key are required." exit 1 fi # Save configuration cat > "$CONFIG_FILE" << EOF NAMECHEAP_API_USER="${api_user}" NAMECHEAP_API_KEY="${api_key}" EOF chmod 600 "$CONFIG_FILE" print_success "Credentials saved to ${CONFIG_FILE}" echo "" # Test connection load_config echo "Testing API connection..." if api_request "domains.getList" "PageSize=1" > /dev/null 2>&1; then print_success "API connection successful!" else print_warn "API connection failed. Please verify:" echo " 1. API access is enabled (ON) at the Namecheap settings page" echo " 2. IP address ${public_ip} is whitelisted" echo " 3. Your API key is correct" fi } cmd_domains_list() { local list_type="ALL" local search_term="" local page="1" local page_size="20" while [[ $# -gt 0 ]]; do case "$1" in --type) list_type="$2"; shift 2 ;; --search) search_term="$2"; shift 2 ;; --page) page="$2"; shift 2 ;; --page-size) page_size="$2"; shift 2 ;; *) shift ;; esac done local params=("ListType=${list_type}" "Page=${page}" "PageSize=${page_size}") if [[ -n "$search_term" ]]; then params+=("SearchTerm=${search_term}") fi print_info "Fetching domain list..." local response response=$(api_request "domains.getList" "${params[@]}") format_domains_list "$response" } cmd_dns_get_hosts() { local domain="" while [[ $# -gt 0 ]]; do case "$1" in --domain) domain="$2"; shift 2 ;; *) shift ;; esac done if [[ -z "$domain" ]]; then print_error "Domain is required. Usage: ./namecheap.sh domains.dns.getHosts --domain example.com" exit 1 fi local sld tld read -r sld tld <<< "$(parse_domain "$domain")" print_info "Fetching DNS records for ${domain} (SLD=${sld}, TLD=${tld})..." local response response=$(api_request "domains.dns.getHosts" "SLD=${sld}" "TLD=${tld}") format_dns_records "$response" } cmd_dns_set_hosts() { local domain="" local hosts_file="" while [[ $# -gt 0 ]]; do case "$1" in --domain) domain="$2"; shift 2 ;; --hosts) hosts_file="$2"; shift 2 ;; *) shift ;; esac done if [[ -z "$domain" || -z "$hosts_file" ]]; then print_error "Both --domain and --hosts are required." echo "Usage: ./namecheap.sh domains.dns.setHosts --domain example.com --hosts hosts.json" exit 1 fi if [[ ! -f "$hosts_file" ]]; then print_error "Hosts file not found: ${hosts_file}" exit 1 fi local sld tld read -r sld tld <<< "$(parse_domain "$domain")" # Build host parameters from JSON file local params=("SLD=${sld}" "TLD=${tld}") local i=1 while IFS= read -r line; do local hostname recordtype address ttl mxpref hostname=$(echo "$line" | grep -oP '"HostName"\s*:\s*"\K[^"]+' || echo "") recordtype=$(echo "$line" | grep -oP '"RecordType"\s*:\s*"\K[^"]+' || echo "") address=$(echo "$line" | grep -oP '"Address"\s*:\s*"\K[^"]+' || echo "") ttl=$(echo "$line" | grep -oP '"TTL"\s*:\s*"\K[^"]+' || echo "1800") mxpref=$(echo "$line" | grep -oP '"MXPref"\s*:\s*"\K[^"]+' || echo "") if [[ -n "$hostname" && -n "$recordtype" && -n "$address" ]]; then params+=("HostName${i}=${hostname}") params+=("RecordType${i}=${recordtype}") params+=("Address${i}=${address}") params+=("TTL${i}=${ttl}") if [[ -n "$mxpref" ]]; then params+=("MXPref${i}=${mxpref}") fi ((i++)) fi done < <(python3 -c " import json, sys with open('${hosts_file}') as f: records = json.load(f) for r in records: print(json.dumps(r)) " 2>/dev/null || jq -c '.[]' "$hosts_file") if [[ $i -eq 1 ]]; then print_error "No valid host records found in ${hosts_file}" exit 1 fi print_info "Setting $((i-1)) DNS records for ${domain}..." local response response=$(api_request "domains.dns.setHosts" "${params[@]}") if echo "$response" | grep -q 'IsSuccess="true"'; then print_success "DNS records updated successfully for ${domain}!" else print_error "Failed to update DNS records." echo "$response" fi } cmd_dns_add_host() { local domain="" record_type="" name="" address="" ttl="1800" mxpref="" while [[ $# -gt 0 ]]; do case "$1" in --domain) domain="$2"; shift 2 ;; --type) record_type="$2"; shift 2 ;; --name) name="$2"; shift 2 ;; --address) address="$2"; shift 2 ;; --ttl) ttl="$2"; shift 2 ;; --mxpref) mxpref="$2"; shift 2 ;; *) shift ;; esac done if [[ -z "$domain" || -z "$record_type" || -z "$name" || -z "$address" ]]; then print_error "Missing required parameters." echo "Usage: ./namecheap.sh dns.addHost --domain example.com --type A --name \"@\" --address \"1.2.3.4\" [--ttl 1800] [--mxpref 10]" exit 1 fi local sld tld read -r sld tld <<< "$(parse_domain "$domain")" # Fetch existing records print_info "Fetching existing DNS records for ${domain}..." local response response=$(api_request "domains.dns.getHosts" "SLD=${sld}" "TLD=${tld}") # Build params with existing records + new one local params=("SLD=${sld}" "TLD=${tld}") local i=1 # Parse existing records while IFS= read -r line; do if [[ -z "$line" ]]; then continue; fi local h_name h_type h_address h_ttl h_mxpref h_name=$(echo "$line" | grep -oP 'Name="\K[^"]+' || echo "") h_type=$(echo "$line" | grep -oP 'Type="\K[^"]+' || echo "") h_address=$(echo "$line" | grep -oP 'Address="\K[^"]+' || echo "") h_ttl=$(echo "$line" | grep -oP 'TTL="\K[^"]+' || echo "1800") h_mxpref=$(echo "$line" | grep -oP 'MXPref="\K[^"]+' || echo "") if [[ -n "$h_name" && -n "$h_type" && -n "$h_address" ]]; then params+=("HostName${i}=${h_name}") params+=("RecordType${i}=${h_type}") params+=("Address${i}=${h_address}") params+=("TTL${i}=${h_ttl}") if [[ -n "$h_mxpref" && "$h_mxpref" != "0" ]]; then params+=("MXPref${i}=${h_mxpref}") fi ((i++)) fi done < <(echo "$response" | grep -oP '') # Add the new record params+=("HostName${i}=${name}") params+=("RecordType${i}=${record_type}") params+=("Address${i}=${address}") params+=("TTL${i}=${ttl}") if [[ -n "$mxpref" ]]; then params+=("MXPref${i}=${mxpref}") fi print_info "Adding ${record_type} record: ${name} -> ${address}" local set_response set_response=$(api_request "domains.dns.setHosts" "${params[@]}") if echo "$set_response" | grep -q 'IsSuccess="true"'; then print_success "DNS record added successfully!" else print_error "Failed to add DNS record." echo "$set_response" fi } cmd_dns_remove_host() { local domain="" record_type="" name="" address="" while [[ $# -gt 0 ]]; do case "$1" in --domain) domain="$2"; shift 2 ;; --type) record_type="$2"; shift 2 ;; --name) name="$2"; shift 2 ;; --address) address="$2"; shift 2 ;; *) shift ;; esac done if [[ -z "$domain" || -z "$record_type" || -z "$name" ]]; then print_error "Missing required parameters." echo "Usage: ./namecheap.sh dns.removeHost --domain example.com --type A --name \"@\" [--address \"1.2.3.4\"]" exit 1 fi local sld tld read -r sld tld <<< "$(parse_domain "$domain")" # Fetch existing records print_info "Fetching existing DNS records for ${domain}..." local response response=$(api_request "domains.dns.getHosts" "SLD=${sld}" "TLD=${tld}") # Build params excluding the record to remove local params=("SLD=${sld}" "TLD=${tld}") local i=1 local removed=false while IFS= read -r line; do if [[ -z "$line" ]]; then continue; fi local h_name h_type h_address h_ttl h_mxpref h_name=$(echo "$line" | grep -oP 'Name="\K[^"]+' || echo "") h_type=$(echo "$line" | grep -oP 'Type="\K[^"]+' || echo "") h_address=$(echo "$line" | grep -oP 'Address="\K[^"]+' || echo "") h_ttl=$(echo "$line" | grep -oP 'TTL="\K[^"]+' || echo "1800") h_mxpref=$(echo "$line" | grep -oP 'MXPref="\K[^"]+' || echo "") # Check if this is the record to remove if [[ "$h_name" == "$name" && "$h_type" == "$record_type" && "$removed" == "false" ]]; then if [[ -z "$address" || "$h_address" == "$address" ]]; then removed=true print_info "Removing record: ${h_name} ${h_type} ${h_address}" continue fi fi if [[ -n "$h_name" && -n "$h_type" && -n "$h_address" ]]; then params+=("HostName${i}=${h_name}") params+=("RecordType${i}=${h_type}") params+=("Address${i}=${h_address}") params+=("TTL${i}=${h_ttl}") if [[ -n "$h_mxpref" && "$h_mxpref" != "0" ]]; then params+=("MXPref${i}=${h_mxpref}") fi ((i++)) fi done < <(echo "$response" | grep -oP '') if [[ "$removed" == "false" ]]; then print_error "No matching record found to remove." exit 1 fi # If no records left, we still need at least one (Namecheap requirement) if [[ $i -eq 1 ]]; then print_error "Cannot remove the last DNS record. Namecheap requires at least one record." exit 1 fi print_info "Updating DNS records for ${domain}..." local set_response set_response=$(api_request "domains.dns.setHosts" "${params[@]}") if echo "$set_response" | grep -q 'IsSuccess="true"'; then print_success "DNS record removed successfully!" else print_error "Failed to remove DNS record." echo "$set_response" fi } cmd_public_ip() { local ip ip=$(get_public_ip) echo "$ip" } cmd_dns_get_list() { local domain="" while [[ $# -gt 0 ]]; do case "$1" in --domain) domain="$2"; shift 2 ;; *) shift ;; esac done if [[ -z "$domain" ]]; then print_error "Domain is required. Usage: ./namecheap.sh domains.dns.getList --domain example.com" exit 1 fi local sld tld read -r sld tld <<< "$(parse_domain "$domain")" print_info "Fetching nameservers for ${domain}..." local response response=$(api_request "domains.dns.getList" "SLD=${sld}" "TLD=${tld}") local using_our_dns using_our_dns=$(echo "$response" | grep -oP 'IsUsingOurDNS="\K[^"]+' || echo "unknown") echo "" print_info "Using Namecheap DNS: ${using_our_dns}" echo "" echo "Nameservers:" echo "$response" | grep -oP '\K[^<]+' | while read -r ns; do echo " - ${ns}" done echo "" } cmd_dns_set_default() { local domain="" while [[ $# -gt 0 ]]; do case "$1" in --domain) domain="$2"; shift 2 ;; *) shift ;; esac done if [[ -z "$domain" ]]; then print_error "Domain is required. Usage: ./namecheap.sh domains.dns.setDefault --domain example.com" exit 1 fi local sld tld read -r sld tld <<< "$(parse_domain "$domain")" print_info "Setting ${domain} to use Namecheap default DNS..." local response response=$(api_request "domains.dns.setDefault" "SLD=${sld}" "TLD=${tld}") if echo "$response" | grep -q 'Updated="true"'; then print_success "Domain ${domain} now uses Namecheap default DNS!" else print_error "Failed to set default DNS." echo "$response" fi } cmd_dns_set_custom() { local domain="" nameservers="" while [[ $# -gt 0 ]]; do case "$1" in --domain) domain="$2"; shift 2 ;; --nameservers) nameservers="$2"; shift 2 ;; *) shift ;; esac done if [[ -z "$domain" || -z "$nameservers" ]]; then print_error "Both --domain and --nameservers are required." echo "Usage: ./namecheap.sh domains.dns.setCustom --domain example.com --nameservers ns1.cloudflare.com,ns2.cloudflare.com" exit 1 fi local sld tld read -r sld tld <<< "$(parse_domain "$domain")" print_info "Setting ${domain} to use custom nameservers: ${nameservers}" local response response=$(api_request "domains.dns.setCustom" "SLD=${sld}" "TLD=${tld}" "Nameservers=${nameservers}") if echo "$response" | grep -q 'Updated="true"'; then print_success "Domain ${domain} now uses custom nameservers!" else print_error "Failed to set custom nameservers." echo "$response" fi } cmd_dns_get_email_forwarding() { local domain="" while [[ $# -gt 0 ]]; do case "$1" in --domain) domain="$2"; shift 2 ;; *) shift ;; esac done if [[ -z "$domain" ]]; then print_error "Domain is required. Usage: ./namecheap.sh domains.dns.getEmailForwarding --domain example.com" exit 1 fi print_info "Fetching email forwarding for ${domain}..." local response response=$(api_request "domains.dns.getEmailForwarding" "DomainName=${domain}") echo "" printf "%-20s %-40s\n" "MAILBOX" "FORWARDS TO" printf "%-20s %-40s\n" "-------" "-----------" echo "$response" | grep -oP '' | while read -r line; do local mailbox forward_to mailbox=$(echo "$line" | grep -oP 'mailbox="\K[^"]+' || echo "") forward_to=$(echo "$line" | grep -oP 'ForwardTo="\K[^"]+' || echo "") printf "%-20s %-40s\n" "${mailbox}@${domain}" "$forward_to" done echo "" } cmd_dns_set_email_forwarding() { local domain="" forwards_file="" while [[ $# -gt 0 ]]; do case "$1" in --domain) domain="$2"; shift 2 ;; --forwards) forwards_file="$2"; shift 2 ;; --mailbox) # Inline single forwarding rule local inline_mailbox="$2"; shift 2 ;; --forward-to) local inline_forward_to="$2"; shift 2 ;; *) shift ;; esac done if [[ -z "$domain" ]]; then print_error "Domain is required." echo "Usage: ./namecheap.sh domains.dns.setEmailForwarding --domain example.com --mailbox info --forward-to user@gmail.com" echo " or: ./namecheap.sh domains.dns.setEmailForwarding --domain example.com --forwards forwards.json" exit 1 fi local params=("DomainName=${domain}") if [[ -n "${inline_mailbox:-}" && -n "${inline_forward_to:-}" ]]; then # Single inline rule params+=("MailBox1=${inline_mailbox}" "ForwardTo1=${inline_forward_to}") elif [[ -n "$forwards_file" ]]; then if [[ ! -f "$forwards_file" ]]; then print_error "Forwards file not found: ${forwards_file}" exit 1 fi local i=1 while IFS= read -r line; do local mailbox forward_to mailbox=$(echo "$line" | grep -oP '"MailBox"\s*:\s*"\K[^"]+' || echo "") forward_to=$(echo "$line" | grep -oP '"ForwardTo"\s*:\s*"\K[^"]+' || echo "") if [[ -n "$mailbox" && -n "$forward_to" ]]; then params+=("MailBox${i}=${mailbox}" "ForwardTo${i}=${forward_to}") ((i++)) fi done < <(python3 -c " import json, sys with open('${forwards_file}') as f: rules = json.load(f) for r in rules: print(json.dumps(r)) " 2>/dev/null || jq -c '.[]' "$forwards_file") else print_error "Provide either --mailbox/--forward-to or --forwards " exit 1 fi print_info "Setting email forwarding for ${domain}..." local response response=$(api_request "domains.dns.setEmailForwarding" "${params[@]}") if echo "$response" | grep -q 'IsSuccess="true"'; then print_success "Email forwarding updated for ${domain}!" else print_error "Failed to set email forwarding." echo "$response" fi } cmd_ns_create() { local domain="" nameserver="" ip="" while [[ $# -gt 0 ]]; do case "$1" in --domain) domain="$2"; shift 2 ;; --nameserver) nameserver="$2"; shift 2 ;; --ip) ip="$2"; shift 2 ;; *) shift ;; esac done if [[ -z "$domain" || -z "$nameserver" || -z "$ip" ]]; then print_error "Missing required parameters." echo "Usage: ./namecheap.sh domains.ns.create --domain example.com --nameserver ns1.example.com --ip 1.2.3.4" exit 1 fi local sld tld read -r sld tld <<< "$(parse_domain "$domain")" print_info "Creating nameserver ${nameserver} -> ${ip}..." local response response=$(api_request "domains.ns.create" "SLD=${sld}" "TLD=${tld}" "Nameserver=${nameserver}" "IP=${ip}") if echo "$response" | grep -q 'IsSuccess="true"'; then print_success "Nameserver ${nameserver} created!" else print_error "Failed to create nameserver." echo "$response" fi } cmd_ns_delete() { local domain="" nameserver="" while [[ $# -gt 0 ]]; do case "$1" in --domain) domain="$2"; shift 2 ;; --nameserver) nameserver="$2"; shift 2 ;; *) shift ;; esac done if [[ -z "$domain" || -z "$nameserver" ]]; then print_error "Missing required parameters." echo "Usage: ./namecheap.sh domains.ns.delete --domain example.com --nameserver ns1.example.com" exit 1 fi local sld tld read -r sld tld <<< "$(parse_domain "$domain")" print_info "Deleting nameserver ${nameserver}..." local response response=$(api_request "domains.ns.delete" "SLD=${sld}" "TLD=${tld}" "Nameserver=${nameserver}") if echo "$response" | grep -q 'IsSuccess="true"'; then print_success "Nameserver ${nameserver} deleted!" else print_error "Failed to delete nameserver." echo "$response" fi } cmd_ns_get_info() { local domain="" nameserver="" while [[ $# -gt 0 ]]; do case "$1" in --domain) domain="$2"; shift 2 ;; --nameserver) nameserver="$2"; shift 2 ;; *) shift ;; esac done if [[ -z "$domain" || -z "$nameserver" ]]; then print_error "Missing required parameters." echo "Usage: ./namecheap.sh domains.ns.getInfo --domain example.com --nameserver ns1.example.com" exit 1 fi local sld tld read -r sld tld <<< "$(parse_domain "$domain")" print_info "Fetching info for nameserver ${nameserver}..." local response response=$(api_request "domains.ns.getInfo" "SLD=${sld}" "TLD=${tld}" "Nameserver=${nameserver}") local ns_ip ns_ip=$(echo "$response" | grep -oP 'IP="\K[^"]+' || echo "unknown") echo "" echo "Nameserver: ${nameserver}" echo "IP Address: ${ns_ip}" local statuses statuses=$(echo "$response" | grep -oP '\K[^<]+' | tr '\n' ', ' | sed 's/,$//') if [[ -n "$statuses" ]]; then echo "Status: ${statuses}" fi echo "" } cmd_ns_update() { local domain="" nameserver="" old_ip="" new_ip="" while [[ $# -gt 0 ]]; do case "$1" in --domain) domain="$2"; shift 2 ;; --nameserver) nameserver="$2"; shift 2 ;; --old-ip) old_ip="$2"; shift 2 ;; --ip) new_ip="$2"; shift 2 ;; *) shift ;; esac done if [[ -z "$domain" || -z "$nameserver" || -z "$old_ip" || -z "$new_ip" ]]; then print_error "Missing required parameters." echo "Usage: ./namecheap.sh domains.ns.update --domain example.com --nameserver ns1.example.com --old-ip 1.2.3.4 --ip 5.6.7.8" exit 1 fi local sld tld read -r sld tld <<< "$(parse_domain "$domain")" print_info "Updating nameserver ${nameserver}: ${old_ip} -> ${new_ip}..." local response response=$(api_request "domains.ns.update" "SLD=${sld}" "TLD=${tld}" "Nameserver=${nameserver}" "OldIP=${old_ip}" "IP=${new_ip}") if echo "$response" | grep -q 'IsSuccess="true"'; then print_success "Nameserver ${nameserver} updated to ${new_ip}!" else print_error "Failed to update nameserver." echo "$response" fi } # Help cmd_help() { echo "Namecheap DNS Management CLI" echo "" echo "Usage: ./namecheap.sh [options]" echo "" echo "Commands:" echo " setup Configure API credentials and test connection" echo " public-ip Show your public IP address" echo "" echo " domains.getList List your Namecheap domains" echo "" echo " domains.dns.getList Get nameservers for a domain" echo " domains.dns.getHosts Get DNS records for a domain" echo " domains.dns.setHosts Set all DNS records (from JSON file)" echo " domains.dns.setDefault Use Namecheap default DNS" echo " domains.dns.setCustom Use custom nameservers" echo " domains.dns.getEmailForwarding Get email forwarding rules" echo " domains.dns.setEmailForwarding Set email forwarding rules" echo "" echo " domains.ns.create Create a child nameserver (glue record)" echo " domains.ns.delete Delete a child nameserver" echo " domains.ns.getInfo Get nameserver info" echo " domains.ns.update Update nameserver IP" echo "" echo " dns.addHost Add a single DNS record (preserves existing)" echo " dns.removeHost Remove a single DNS record" echo "" echo "Options:" echo " --domain Domain name (e.g., example.com)" echo " --type Record type (A, AAAA, CNAME, MX, TXT, etc.)" echo " --name Host name (e.g., @, www, mail)" echo " --address Record value (IP or target)" echo " --ttl TTL in seconds (default: 1800)" echo " --mxpref MX preference (for MX records)" echo " --hosts JSON file with host records" echo " --nameservers Comma-separated nameservers" echo " --nameserver Nameserver hostname" echo " --ip
IP address for nameserver" echo " --old-ip
Current IP (for ns.update)" echo " --mailbox Email mailbox name" echo " --forward-to Forward destination email" echo " --forwards JSON file with forwarding rules" echo " --search Search term for domain list" echo " --page Page number for domain list" echo " --page-size Page size for domain list (10-100)" echo "" echo "Examples:" echo " ./namecheap.sh setup" echo " ./namecheap.sh domains.getList" echo " ./namecheap.sh domains.dns.getHosts --domain example.com" echo " ./namecheap.sh dns.addHost --domain example.com --type A --name www --address 1.2.3.4" echo " ./namecheap.sh dns.removeHost --domain example.com --type A --name www" echo " ./namecheap.sh domains.dns.setCustom --domain example.com --nameservers ns1.cloudflare.com,ns2.cloudflare.com" echo " ./namecheap.sh domains.dns.setEmailForwarding --domain example.com --mailbox info --forward-to user@gmail.com" echo " ./namecheap.sh domains.ns.create --domain example.com --nameserver ns1.example.com --ip 1.2.3.4" } # Main dispatch main() { local command="${1:-help}" shift || true case "$command" in setup) cmd_setup "$@" ;; public-ip) cmd_public_ip "$@" ;; domains.getList) cmd_domains_list "$@" ;; domains.dns.getList) cmd_dns_get_list "$@" ;; domains.dns.getHosts) cmd_dns_get_hosts "$@" ;; domains.dns.setHosts) cmd_dns_set_hosts "$@" ;; domains.dns.setDefault) cmd_dns_set_default "$@" ;; domains.dns.setCustom) cmd_dns_set_custom "$@" ;; domains.dns.getEmailForwarding) cmd_dns_get_email_forwarding "$@" ;; domains.dns.setEmailForwarding) cmd_dns_set_email_forwarding "$@" ;; domains.ns.create) cmd_ns_create "$@" ;; domains.ns.delete) cmd_ns_delete "$@" ;; domains.ns.getInfo) cmd_ns_get_info "$@" ;; domains.ns.update) cmd_ns_update "$@" ;; dns.addHost) cmd_dns_add_host "$@" ;; dns.removeHost) cmd_dns_remove_host "$@" ;; help|--help|-h) cmd_help ;; *) print_error "Unknown command: ${command}" echo "" cmd_help exit 1 ;; esac } main "$@"