Files
s-hy2/scripts/post-deploy-check.sh
sindricn 5e57b7f357 修复
2025-10-01 17:35:36 +08:00

749 lines
21 KiB
Bash

#!/bin/bash
# Hysteria2 部署后检查模块
# 确保节点部署完成后各项功能正常
# 适度的错误处理
set -uo pipefail
# 加载公共库
# SCRIPT_DIR 由主脚本定义,此处已移除以避免覆盖
if [[ -f "$(dirname "${BASH_SOURCE[0]}")/common.sh" ]]; then
source "$(dirname "${BASH_SOURCE[0]}")/common.sh"
else
echo "错误: 无法加载公共库" >&2
exit 1
fi
# 加载防火墙管理模块
if [[ -f "$(dirname "${BASH_SOURCE[0]}")/firewall-manager.sh" ]]; then
source "$(dirname "${BASH_SOURCE[0]}")/firewall-manager.sh"
fi
# 配置路径 (防止重复定义)
if [[ -z "${HYSTERIA_CONFIG:-}" ]]; then
readonly HYSTERIA_CONFIG="/etc/hysteria/config.yaml"
fi
if [[ -z "${HYSTERIA_SERVICE:-}" ]]; then
readonly HYSTERIA_SERVICE="hysteria-server"
fi
if [[ -z "${CHECK_TIMEOUT:-}" ]]; then
readonly CHECK_TIMEOUT=10
fi
# 全面部署检查
comprehensive_deploy_check() {
log_info "开始全面部署检查"
echo -e "${CYAN}=== Hysteria2 全面部署检查 ===${NC}"
echo ""
local total_checks=8
local passed_checks=0
local failed_checks=()
# 检查 1: 二进制文件
echo -e "${BLUE}[1/$total_checks] 检查 Hysteria2 二进制文件${NC}"
if check_hysteria_binary; then
echo "✅ Hysteria2 二进制文件正常"
((passed_checks++))
else
echo "❌ Hysteria2 二进制文件异常"
failed_checks+=("二进制文件")
fi
echo ""
# 检查 2: 配置文件
echo -e "${BLUE}[2/$total_checks] 检查配置文件${NC}"
if check_config_file; then
echo "✅ 配置文件正常"
((passed_checks++))
else
echo "❌ 配置文件异常"
failed_checks+=("配置文件")
fi
echo ""
# 检查 3: 证书配置
echo -e "${BLUE}[3/$total_checks] 检查证书配置${NC}"
if check_certificate_config; then
echo "✅ 证书配置正常"
((passed_checks++))
else
echo "❌ 证书配置异常"
failed_checks+=("证书配置")
fi
echo ""
# 检查 4: 系统服务
echo -e "${BLUE}[4/$total_checks] 检查系统服务${NC}"
if check_system_service; then
echo "✅ 系统服务正常"
((passed_checks++))
else
echo "❌ 系统服务异常"
failed_checks+=("系统服务")
fi
echo ""
# 检查 5: 端口监听
echo -e "${BLUE}[5/$total_checks] 检查端口监听${NC}"
if check_port_listening; then
echo "✅ 端口监听正常"
((passed_checks++))
else
echo "❌ 端口监听异常"
failed_checks+=("端口监听")
fi
echo ""
# 检查 6: 防火墙规则
echo -e "${BLUE}[6/$total_checks] 检查防火墙规则${NC}"
if check_firewall_rules; then
echo "✅ 防火墙规则正常"
((passed_checks++))
else
echo "❌ 防火墙规则异常"
failed_checks+=("防火墙规则")
fi
echo ""
# 检查 7: 网络连通性
echo -e "${BLUE}[7/$total_checks] 检查网络连通性${NC}"
if check_network_connectivity; then
echo "✅ 网络连通性正常"
((passed_checks++))
else
echo "❌ 网络连通性异常"
failed_checks+=("网络连通性")
fi
echo ""
# 检查 8: 性能状态
echo -e "${BLUE}[8/$total_checks] 检查性能状态${NC}"
if check_performance_status; then
echo "✅ 性能状态正常"
((passed_checks++))
else
echo "❌ 性能状态异常"
failed_checks+=("性能状态")
fi
echo ""
# 生成检查报告
generate_check_report "$passed_checks" "$total_checks" "${failed_checks[@]}"
return $((total_checks - passed_checks))
}
# 检查 Hysteria2 二进制文件
check_hysteria_binary() {
# 检查命令是否存在
if ! command -v hysteria >/dev/null 2>&1; then
echo " ❌ hysteria 命令不存在"
return 1
fi
# 检查版本信息
local version
version=$(hysteria version 2>/dev/null | head -1 || echo "")
if [[ -n "$version" ]]; then
echo " 📦 版本: $version"
else
echo " ⚠️ 无法获取版本信息"
fi
# 检查可执行权限
local hysteria_path
hysteria_path=$(which hysteria)
if [[ -x "$hysteria_path" ]]; then
echo " ✅ 可执行权限正常"
else
echo " ❌ 可执行权限异常"
return 1
fi
return 0
}
# 检查配置文件
check_config_file() {
# 检查文件是否存在
if [[ ! -f "$HYSTERIA_CONFIG" ]]; then
echo " ❌ 配置文件不存在: $HYSTERIA_CONFIG"
return 1
fi
# 检查文件权限
if [[ ! -r "$HYSTERIA_CONFIG" ]]; then
echo " ❌ 配置文件不可读"
return 1
fi
# 检查配置语法
if hysteria config check "$HYSTERIA_CONFIG" >/dev/null 2>&1; then
echo " ✅ 配置语法正确"
else
echo " ❌ 配置语法错误"
hysteria config check "$HYSTERIA_CONFIG" 2>&1 | head -3 | sed 's/^/ /'
return 1
fi
# 检查关键配置项
check_config_items
return 0
}
# 检查配置关键项
check_config_items() {
local config_file="$HYSTERIA_CONFIG"
# 检查监听地址
if grep -q "^listen:" "$config_file"; then
local listen_addr
listen_addr=$(grep "^listen:" "$config_file" | awk '{print $2}' | tr -d '"')
echo " 📡 监听地址: $listen_addr"
else
echo " ⚠️ 未找到监听地址配置"
fi
# 检查认证配置
if grep -q "^auth:" "$config_file"; then
echo " 🔐 认证配置: 已配置"
else
echo " ⚠️ 未找到认证配置"
fi
# 检查 TLS/证书配置
if grep -q "^tls:" "$config_file" || grep -q "^acme:" "$config_file"; then
echo " 🔒 TLS配置: 已配置"
else
echo " ⚠️ 未找到 TLS 配置"
fi
# 检查混淆配置
if grep -q "obfs:" "$config_file"; then
echo " 🎭 混淆配置: 已配置"
else
echo " ℹ️ 未配置混淆(可选)"
fi
}
# 检查证书配置
check_certificate_config() {
local config_file="$HYSTERIA_CONFIG"
# 检查 TLS 配置类型
if grep -q "^acme:" "$config_file"; then
echo " 🔒 使用 ACME 自动证书"
return check_acme_certificate
elif grep -q "^tls:" "$config_file"; then
echo " 🔒 使用自定义证书"
return check_custom_certificate
else
echo " ❌ 未找到 TLS 配置"
return 1
fi
}
# 检查 ACME 证书
check_acme_certificate() {
local domains
domains=$(grep -A 10 "^acme:" "$HYSTERIA_CONFIG" | grep -E "^\s*-\s" | awk '{print $2}' | tr -d '"')
if [[ -n "$domains" ]]; then
echo " 📋 ACME 域名:"
echo "$domains" | sed 's/^/ - /'
# 检查证书目录
local acme_dir
acme_dir=$(grep -A 20 "^acme:" "$HYSTERIA_CONFIG" | grep "dir:" | awk '{print $2}' | tr -d '"' || echo "/etc/hysteria/acme")
if [[ -d "$acme_dir" ]]; then
local cert_count
cert_count=$(find "$acme_dir" -name "*.crt" 2>/dev/null | wc -l)
echo " 📁 证书目录: $acme_dir ($cert_count 个证书文件)"
else
echo " ⚠️ 证书目录不存在: $acme_dir"
fi
else
echo " ❌ 未找到 ACME 域名配置"
return 1
fi
return 0
}
# 检查自定义证书
check_custom_certificate() {
local cert_file key_file
cert_file=$(grep -A 5 "^tls:" "$HYSTERIA_CONFIG" | grep "cert:" | awk '{print $2}' | tr -d '"')
key_file=$(grep -A 5 "^tls:" "$HYSTERIA_CONFIG" | grep "key:" | awk '{print $2}' | tr -d '"')
if [[ -n "$cert_file" ]] && [[ -n "$key_file" ]]; then
echo " 📄 证书文件: $cert_file"
echo " 🔑 私钥文件: $key_file"
# 检查文件是否存在
if [[ -f "$cert_file" ]] && [[ -f "$key_file" ]]; then
echo " ✅ 证书文件存在"
# 检查证书有效性
if openssl x509 -in "$cert_file" -text -noout >/dev/null 2>&1; then
echo " ✅ 证书格式正确"
# 检查证书过期时间
local expiry_date
expiry_date=$(openssl x509 -in "$cert_file" -enddate -noout | cut -d= -f2)
echo " 📅 证书过期时间: $expiry_date"
else
echo " ❌ 证书格式错误"
return 1
fi
else
echo " ❌ 证书文件不存在"
return 1
fi
else
echo " ❌ 未找到证书文件配置"
return 1
fi
return 0
}
# 检查系统服务
check_system_service() {
# 检查服务是否存在
if ! systemctl list-unit-files | grep -q "$HYSTERIA_SERVICE"; then
echo " ❌ 系统服务不存在: $HYSTERIA_SERVICE"
return 1
fi
# 检查服务状态
if systemctl is-active --quiet "$HYSTERIA_SERVICE"; then
echo " ✅ 服务运行中"
else
echo " ❌ 服务未运行"
echo " 📄 服务状态:"
systemctl status "$HYSTERIA_SERVICE" --no-pager -l | head -5 | sed 's/^/ /'
return 1
fi
# 检查开机自启
if systemctl is-enabled --quiet "$HYSTERIA_SERVICE"; then
echo " ✅ 开机自启已启用"
else
echo " ⚠️ 开机自启未启用"
fi
# 检查服务启动时间
local start_time
start_time=$(systemctl show "$HYSTERIA_SERVICE" --property=ActiveEnterTimestamp --value 2>/dev/null || echo "未知")
echo " ⏰ 启动时间: $start_time"
return 0
}
# 检查端口监听
check_port_listening() {
local hysteria_port
hysteria_port=$(grep -E "^\s*listen:" "$HYSTERIA_CONFIG" | awk -F':' '{print $NF}' | tr -d ' ' | head -1)
if [[ -z "$hysteria_port" ]]; then
hysteria_port="443" # 默认端口
fi
echo " 🔌 检查端口: $hysteria_port"
# 检查端口监听状态
if ss -tulpn | grep ":$hysteria_port " >/dev/null; then
echo " ✅ 端口正在监听"
# 显示监听详情
local listen_info
listen_info=$(ss -tulpn | grep ":$hysteria_port " | head -1)
echo " 📊 监听详情: $listen_info"
else
echo " ❌ 端口未监听"
echo " 💡 可能原因:"
echo " - 服务未启动"
echo " - 端口配置错误"
echo " - 端口被其他程序占用"
return 1
fi
# 检查端口占用情况
local port_process
port_process=$(ss -tulpn | grep ":$hysteria_port " | grep -o 'pid=[0-9]*' | cut -d= -f2 | head -1)
if [[ -n "$port_process" ]]; then
local process_info
process_info=$(ps -p "$port_process" -o comm= 2>/dev/null || echo "未知进程")
echo " 🔍 占用进程: $process_info (PID: $port_process)"
fi
return 0
}
# 检查防火墙规则
check_firewall_rules() {
# 获取端口
local hysteria_port
hysteria_port=$(grep -E "^\s*listen:" "$HYSTERIA_CONFIG" | awk -F':' '{print $NF}' | tr -d ' ' | head -1)
hysteria_port=${hysteria_port:-443}
echo " 🔥 检查防火墙端口: $hysteria_port"
# 检测防火墙类型
local fw_type=""
if systemctl is-active --quiet firewalld 2>/dev/null; then
fw_type="firewalld"
elif command -v ufw >/dev/null 2>&1 && ufw status | grep -q "Status: active"; then
fw_type="ufw"
elif command -v iptables >/dev/null 2>&1; then
fw_type="iptables"
elif command -v nft >/dev/null 2>&1; then
fw_type="nftables"
fi
if [[ -z "$fw_type" ]]; then
echo " ⚠️ 未检测到活动的防火墙"
return 0 # 没有防火墙不算错误
fi
echo " 🛡️ 防火墙类型: $fw_type"
# 根据防火墙类型检查规则
case "$fw_type" in
"firewalld")
if firewall-cmd --query-port="$hysteria_port/tcp" >/dev/null 2>&1 && \
firewall-cmd --query-port="$hysteria_port/udp" >/dev/null 2>&1; then
echo " ✅ 防火墙规则正确"
return 0
else
echo " ❌ 防火墙规则缺失"
return 1
fi
;;
"ufw")
if ufw status | grep "$hysteria_port" >/dev/null; then
echo " ✅ 防火墙规则正确"
return 0
else
echo " ❌ 防火墙规则缺失"
return 1
fi
;;
"iptables")
if iptables -L INPUT -n | grep "dpt:$hysteria_port" >/dev/null; then
echo " ✅ 防火墙规则正确"
return 0
else
echo " ❌ 防火墙规则缺失"
return 1
fi
;;
*)
echo " ⚠️ 无法自动检查此防火墙类型的规则"
return 0 # 不确定的情况不算错误
;;
esac
}
# 检查网络连通性
check_network_connectivity() {
echo " 🌐 检查网络连通性"
# 检查本地网络接口
local active_interfaces
active_interfaces=$(ip link show up | grep -E "^[0-9]+:" | grep -v "lo:" | wc -l)
echo " 📡 活动网络接口: $active_interfaces"
# 检查外部 IP
local external_ip
external_ip=$(timeout 5 curl -s ifconfig.me 2>/dev/null || echo "获取失败")
echo " 🌍 外部 IP: $external_ip"
# 检查 DNS 解析
if timeout 5 nslookup google.com >/dev/null 2>&1; then
echo " ✅ DNS 解析正常"
else
echo " ❌ DNS 解析异常"
return 1
fi
# 检查外部连通性
local test_hosts=("8.8.8.8" "1.1.1.1" "google.com")
local reachable=0
for host in "${test_hosts[@]}"; do
if timeout 3 ping -c 1 "$host" >/dev/null 2>&1; then
((reachable++))
fi
done
if [[ $reachable -gt 0 ]]; then
echo " ✅ 外部连通性正常 ($reachable/3 个主机可达)"
else
echo " ❌ 外部连通性异常"
return 1
fi
return 0
}
# 检查性能状态
check_performance_status() {
echo " 📊 检查系统性能"
# CPU 使用率
local cpu_usage
cpu_usage=$(top -bn1 | grep "Cpu(s)" | sed "s/.*, *\([0-9.]*\)%* id.*/\1/" | awk '{print 100 - $1}')
echo " 💻 CPU 使用率: ${cpu_usage}%"
# 内存使用率
local mem_usage
mem_usage=$(free | awk 'NR==2{printf "%.1f", $3*100/$2}')
echo " 🧠 内存使用率: ${mem_usage}%"
# 磁盘使用率
local disk_usage
disk_usage=$(df / | awk 'NR==2{print $5}' | sed 's/%//')
echo " 💾 磁盘使用率: ${disk_usage}%"
# 系统负载
local load_avg
load_avg=$(uptime | awk -F'load average:' '{print $2}' | awk '{print $1}' | sed 's/,//')
echo " ⚖️ 系统负载: $load_avg"
# 检查是否有性能问题
if (( $(echo "$cpu_usage > 80" | bc -l) )); then
echo " ⚠️ CPU 使用率过高"
fi
if (( $(echo "$mem_usage > 90" | bc -l) )); then
echo " ⚠️ 内存使用率过高"
fi
if (( disk_usage > 90 )); then
echo " ⚠️ 磁盘使用率过高"
fi
# 检查 Hysteria2 进程资源使用
local hysteria_pid
hysteria_pid=$(pgrep -f hysteria | head -1)
if [[ -n "$hysteria_pid" ]]; then
local process_info
process_info=$(ps -p "$hysteria_pid" -o %cpu,%mem,pid,comm --no-headers 2>/dev/null || echo "")
if [[ -n "$process_info" ]]; then
echo " 🔄 Hysteria2 进程: $process_info"
fi
else
echo " ❌ 未找到 Hysteria2 进程"
return 1
fi
return 0
}
# 生成检查报告
generate_check_report() {
local passed="$1"
local total="$2"
shift 2
local failed=("$@")
echo -e "${CYAN}=== 检查结果总结 ===${NC}"
echo ""
local success_rate=$((passed * 100 / total))
echo "📊 检查统计:"
echo " • 总检查项: $total"
echo " • 通过检查: $passed"
echo " • 失败检查: $((total - passed))"
echo " • 成功率: $success_rate%"
echo ""
if [[ $success_rate -eq 100 ]]; then
echo -e "${GREEN}🎉 恭喜!所有检查都通过了!${NC}"
echo -e "${GREEN}Hysteria2 节点部署完全成功,可以正常使用。${NC}"
elif [[ $success_rate -ge 75 ]]; then
echo -e "${YELLOW}⚠️ 大部分检查通过,但有一些小问题。${NC}"
echo -e "${YELLOW}节点基本可用,建议修复以下问题:${NC}"
else
echo -e "${RED}❌ 检查失败较多,需要重点关注。${NC}"
echo -e "${RED}节点可能无法正常工作,需要修复以下问题:${NC}"
fi
if [[ ${#failed[@]} -gt 0 ]]; then
echo ""
echo "🔧 需要修复的问题:"
for item in "${failed[@]}"; do
echo "$item"
done
fi
echo ""
echo "💡 建议操作:"
echo " • 如有问题,请查看详细日志: journalctl -u hysteria-server -f"
echo " • 检查配置文件: $HYSTERIA_CONFIG"
echo " • 重启服务: systemctl restart hysteria-server"
echo " • 检查防火墙: 使用防火墙管理功能"
# 保存检查报告
save_check_report "$passed" "$total" "${failed[@]}"
}
# 保存检查报告
save_check_report() {
local passed="$1"
local total="$2"
shift 2
local failed=("$@")
local report_dir="/var/log/s-hy2"
local report_file="$report_dir/deploy-check-$(date +%Y%m%d_%H%M%S).log"
mkdir -p "$report_dir"
{
echo "Hysteria2 部署检查报告"
echo "=========================="
echo "检查时间: $(date)"
echo "通过检查: $passed/$total"
echo "成功率: $((passed * 100 / total))%"
echo ""
if [[ ${#failed[@]} -gt 0 ]]; then
echo "失败项目:"
for item in "${failed[@]}"; do
echo "- $item"
done
fi
echo ""
echo "系统信息:"
echo "- 系统: $(uname -a)"
echo "- 时间: $(date)"
echo "- 用户: $(whoami)"
} > "$report_file"
log_info "检查报告已保存: $report_file"
}
# 快速健康检查
quick_health_check() {
log_info "执行快速健康检查"
echo -e "${CYAN}=== 快速健康检查 ===${NC}"
echo ""
# 服务状态
if systemctl is-active --quiet "$HYSTERIA_SERVICE"; then
echo "✅ 服务运行正常"
else
echo "❌ 服务未运行"
return 1
fi
# 端口监听
local port
port=$(grep -E "^\s*listen:" "$HYSTERIA_CONFIG" | awk -F':' '{print $NF}' | tr -d ' ' | head -1)
port=${port:-443}
if ss -tulpn | grep ":$port " >/dev/null; then
echo "✅ 端口 $port 监听正常"
else
echo "❌ 端口 $port 未监听"
return 1
fi
# 配置文件
if [[ -f "$HYSTERIA_CONFIG" ]] && hysteria config check "$HYSTERIA_CONFIG" >/dev/null 2>&1; then
echo "✅ 配置文件正常"
else
echo "❌ 配置文件异常"
return 1
fi
echo ""
echo -e "${GREEN}✅ 快速检查通过,节点运行正常${NC}"
return 0
}
# 修复常见问题
fix_common_issues() {
log_info "尝试修复常见问题"
echo -e "${BLUE}=== 自动修复常见问题 ===${NC}"
echo ""
local fixed_count=0
# 修复 1: 重启服务
echo "1. 检查并重启服务"
if ! systemctl is-active --quiet "$HYSTERIA_SERVICE"; then
if systemctl restart "$HYSTERIA_SERVICE"; then
echo " ✅ 服务已重启"
((fixed_count++))
else
echo " ❌ 服务重启失败"
fi
else
echo " ✅ 服务运行正常"
fi
# 修复 2: 检查防火墙
echo "2. 检查防火墙规则"
local port
port=$(grep -E "^\s*listen:" "$HYSTERIA_CONFIG" | awk -F':' '{print $NF}' | tr -d ' ' | head -1)
port=${port:-443}
if command -v firewall-cmd >/dev/null 2>&1 && systemctl is-active --quiet firewalld; then
if ! firewall-cmd --query-port="$port/tcp" >/dev/null 2>&1; then
if firewall-cmd --add-port="$port/tcp" --permanent && firewall-cmd --reload; then
echo " ✅ 已开放 TCP 端口 $port"
((fixed_count++))
fi
fi
if ! firewall-cmd --query-port="$port/udp" >/dev/null 2>&1; then
if firewall-cmd --add-port="$port/udp" --permanent && firewall-cmd --reload; then
echo " ✅ 已开放 UDP 端口 $port"
((fixed_count++))
fi
fi
fi
# 修复 3: 权限检查
echo "3. 检查文件权限"
if [[ -f "$HYSTERIA_CONFIG" ]]; then
if [[ ! -r "$HYSTERIA_CONFIG" ]]; then
if chmod 644 "$HYSTERIA_CONFIG"; then
echo " ✅ 已修复配置文件权限"
((fixed_count++))
fi
else
echo " ✅ 配置文件权限正常"
fi
fi
echo ""
if [[ $fixed_count -gt 0 ]]; then
echo -e "${GREEN}🔧 已修复 $fixed_count 个问题${NC}"
echo "建议重新运行完整检查验证修复效果"
else
echo -e "${YELLOW}⚠️ 没有发现可自动修复的问题${NC}"
fi
wait_for_user
}
# 如果脚本被直接执行
if [[ "${BASH_SOURCE[0]}" == "${0}" ]]; then
comprehensive_deploy_check
fi