外网IP变更检测脚本
检测服务器外网IP是否发生变化,IP变更时自动发送告警,支持调用DDNS接口更新域名解析,适用于动态IP家庭宽带/小运营商场景
详细内容
#!/bin/bash
# ==========================================
# 外网IP变更检测脚本
# 用途:检测外网IP变化,变更时告警并更新DDNS
# 使用方法:加入crontab每5分钟执行一次
# ==========================================
# ========== 配置 ==========
IP_FILE="/tmp/current_public_ip.txt"
LOG_FILE="/var/log/ip_change_monitor.log"
ALERT_EMAIL=""
WECOM_WEBHOOK=""
# DDNS配置(支持阿里云DNS,留空则不更新)
DDNS_ENABLE=false
DDNS_PROVIDER="aliyun" # aliyun / cloudflare / dnspod
DDNS_DOMAIN="" # 要更新的域名,如 home.example.com
ALIYUN_ACCESS_KEY="" # 阿里云AccessKey
ALIYUN_SECRET_KEY="" # 阿里云SecretKey
# ==========================
mkdir -p "$(dirname "$LOG_FILE")"
log_msg() {
echo "[$(date '+%Y-%m-%d %H:%M:%S')] $1" | tee -a "$LOG_FILE"
}
send_alert() {
local title="$1"
local content="$2"
log_msg "【告警】$title: $content"
if [ -n "$ALERT_EMAIL" ]; then
echo -e "$content" | mail -s "【IP变更】$title" "$ALERT_EMAIL" 2>/dev/null
fi
if [ -n "$WECOM_WEBHOOK" ]; then
curl -s "$WECOM_WEBHOOK" -H "Content-Type: application/json" -d "{
"msgtype": "text",
"text": {"content": "【IP变更告警】$title\n$content\n主机: $(hostname)"}
}" >/dev/null 2>&1
fi
}
get_public_ip() {
# 多个源依次尝试,提高可靠性
local ip=""
local sources=(
"https://api.ipify.org"
"https://ifconfig.me"
"https://icanhazip.com"
"https://ipinfo.io/ip"
"http://members.3322.org/dyndns/getip"
)
for url in "${sources[@]}"; do
ip=$(curl -s --connect-timeout 5 --max-time 10 "$url" 2>/dev/null | grep -oE "([0-9]{1,3}\.){3}[0-9]{1,3}" | head -1)
if [ -n "$ip" ]; then
echo "$ip"
return 0
fi
done
return 1
}
update_aliyun_ddns() {
local new_ip="$1"
log_msg "正在更新阿里云DDNS: $DDNS_DOMAIN -> $new_ip"
# 阿里云DNS API调用(简化版,实际使用需签名)
# 这里提供一个基础框架,完整实现需要阿里云API签名
log_msg "阿里云DDNS更新需要完整API签名,请参考阿里云DNS API文档"
# 实际生产环境建议使用 aliddns 工具或现成的DDNS客户端
}
update_ddns() {
local new_ip="$1"
if [ "$DDNS_ENABLE" != true ]; then
return
fi
case "$DDNS_PROVIDER" in
aliyun)
update_aliyun_ddns "$new_ip"
;;
*)
log_msg "暂不支持的DDNS服务商: $DDNS_PROVIDER"
;;
esac
}
# 获取当前外网IP
CURRENT_IP=$(get_public_ip)
if [ -z "$CURRENT_IP" ]; then
log_msg "❌ 无法获取外网IP,请检查网络连接"
send_alert "无法获取外网IP" "所有IP查询源均失败,请检查服务器网络连接"
exit 1
fi
log_msg "当前外网IP: $CURRENT_IP"
# 读取上次记录的IP
if [ -f "$IP_FILE" ]; then
OLD_IP=$(cat "$IP_FILE")
else
OLD_IP=""
fi
# 对比IP是否变化
if [ "$CURRENT_IP" = "$OLD_IP" ]; then
log_msg "✅ 外网IP未变化"
exit 0
fi
# IP发生变化
if [ -z "$OLD_IP" ]; then
log_msg "📝 首次记录外网IP: $CURRENT_IP"
else
log_msg "⚠️ 外网IP发生变化!"
log_msg " 旧IP: $OLD_IP"
log_msg " 新IP: $CURRENT_IP"
send_alert "外网IP已变更" "外网IP发生变化!\n旧IP: $OLD_IP\n新IP: $CURRENT_IP\n变更时间: $(date '+%Y-%m-%d %H:%M:%S')\n\n如果使用了IP白名单或端口映射,请及时更新。"
# 更新DDNS
update_ddns "$CURRENT_IP"
fi
# 保存当前IP
echo "$CURRENT_IP" > "$IP_FILE"
log_msg "✅ 已保存新IP到 $IP_FILE"
适配环境
适配系统:CentOS 7+,Ubuntu 18.04+,Debian 10+
依赖环境:bash 4.0+
参数说明
[{"name": "ALERT_EMAIL", "label": "\u544a\u8b66\u90ae\u7bb1(\u53ef\u9009)", "default": ""}, {"name": "WECOM_WEBHOOK", "label": "\u4f01\u4e1a\u5fae\u4fe1Webhook(\u53ef\u9009)", "default": ""}, {"name": "DDNS_ENABLE", "label": "\u662f\u5426\u542f\u7528DDNS\u66f4\u65b0(true/false)", "default": "false"}, {"name": "DDNS_DOMAIN", "label": "DDNS\u57df\u540d(\u53ef\u9009)", "default": ""}]