When working with network configurations in Linux, it's crucial to distinguish between private and public IP addresses. Private IPs (like those shown by ifconfig
or hostname -i
) are used within local networks, while public IPs are what the internet sees.
Here are several reliable methods to fetch your public IP address in shell scripts:
# Using curl with common IP lookup services
curl ifconfig.me
curl icanhazip.com
curl ipinfo.io/ip
curl api.ipify.org
# Using wget alternative
wget -qO- ifconfig.me/ip
# DNS-based method (works without internet tools)
dig +short myip.opendns.com @resolver1.opendns.com
For production scripts, you should implement fallback mechanisms when one service is unavailable:
#!/bin/bash
get_public_ip() {
local services=(
"ifconfig.me"
"icanhazip.com"
"ipinfo.io/ip"
"api.ipify.org"
)
for service in "${services[@]}"; do
if ip=$(curl -s --connect-timeout 5 $service); then
echo "$ip"
return 0
fi
done
return 1
}
public_ip=$(get_public_ip)
if [[ -n "$public_ip" ]]; then
echo "Public IP: $public_ip"
else
echo "Failed to retrieve public IP" >&2
exit 1
fi
Consider these scenarios in your implementation:
- Network connectivity issues
- Rate limiting from IP services
- IPv6 vs IPv4 addresses
- Proxy or VPN configurations
For scripts that run frequently, you might want to cache the IP address:
#!/bin/bash
CACHE_FILE="/tmp/public_ip_cache"
CACHE_TIME=300 # 5 minutes in seconds
get_cached_ip() {
if [[ -f "$CACHE_FILE" ]]; then
local now=$(date +%s)
local modified=$(stat -c %Y "$CACHE_FILE")
if (( now - modified < CACHE_TIME )); then
cat "$CACHE_FILE"
return 0
fi
fi
return 1
}
if ! cached_ip=$(get_cached_ip); then
if new_ip=$(curl -s ifconfig.me); then
echo "$new_ip" > "$CACHE_FILE"
echo "$new_ip"
else
exit 1
fi
else
echo "$cached_ip"
fi
If you're on a cloud provider, you might have access to instance metadata:
# AWS EC2
curl http://169.254.169.254/latest/meta-data/public-ipv4
# Google Cloud
curl -H "Metadata-Flavor: Google" http://metadata.google.internal/computeMetadata/v1/instance/network-interfaces/0/access-configs/0/external-ip
# Azure
curl -H "Metadata: true" http://169.254.169.254/metadata/instance/network/interface/0/ipv4/ipAddress/0/publicIpAddress?api-version=2021-02-01&format=text
While ifconfig
and hostname -i
display local network interfaces, they don't reveal your public-facing IP address. This becomes crucial when:
- Configuring remote access solutions
- Setting up dynamic DNS
- Network troubleshooting
- Security auditing
Here are reliable methods to fetch your public IP from various external services:
Using cURL with Public API Services
# Most reliable option (supports both IPv4/IPv6)
curl -s https://api.ipify.org
# Alternative services
curl -s https://checkip.amazonaws.com
curl -s https://ifconfig.me/ip
curl -s https://icanhazip.com
DNS-Based Approach
# Using Google's DNS service
dig +short myip.opendns.com @resolver1.opendns.com
# Alternative using Cloudflare
dig +short txt ch whoami.cloudflare @1.1.1.1
Here's a production-ready script with error handling:
#!/bin/bash
# Function to get public IP with fallback options
get_public_ip() {
local services=(
"https://api.ipify.org"
"https://checkip.amazonaws.com"
"https://ifconfig.me/ip"
)
for service in "${services[@]}"; do
if ip=$(curl -s --connect-timeout 5 "$service"); then
if [[ "$ip" =~ ^[0-9]{1,3}\.[0-9]{1,3}\.[0-9]{1,3}\.[0-9]{1,3}$ ]]; then
echo "$ip"
return 0
fi
fi
done
# Fallback to DNS method
if command -v dig &> /dev/null; then
ip=$(dig +short myip.opendns.com @resolver1.opendns.com 2>/dev/null)
if [[ "$ip" ]]; then
echo "$ip"
return 0
fi
fi
echo "ERROR: Could not determine public IP" >&2
return 1
}
# Usage example
public_ip=$(get_public_ip) || exit 1
echo "Public IP: $public_ip"
For environments with strict firewall rules or proxy configurations:
# Using proxy configuration
https_proxy=http://your.proxy:port curl -s https://api.ipify.org
# With explicit timeout settings
curl -s --connect-timeout 10 --max-time 15 https://api.ipify.org
Some services return IPv6 addresses by default. For IPv4-only requests:
curl -4s https://api.ipify.org
For scripts that run frequently, implement caching to avoid rate limits:
#!/bin/bash
CACHE_FILE="/tmp/public_ip.cache"
CACHE_TIME=300 # 5 minutes in seconds
get_cached_ip() {
if [[ -f "$CACHE_FILE" ]]; then
local now=$(date +%s)
local modified=$(stat -c %Y "$CACHE_FILE")
if (( now - modified < CACHE_TIME )); then
cat "$CACHE_FILE"
return 0
fi
fi
return 1
}
if ! cached_ip=$(get_cached_ip); then
if new_ip=$(curl -s https://api.ipify.org); then
echo "$new_ip" > "$CACHE_FILE"
cached_ip="$new_ip"
else
echo "Failed to refresh IP cache" >&2
exit 1
fi
fi
echo "Current public IP: $cached_ip"