#!/bin/bash # Hysteria2 配置生成脚本 (安全版本) # 严格错误处理 set -euo pipefail # 加载安全输入验证模块 script_dir="$(cd "$(dirname "${BASH_SOURCE[0]}")" && pwd)" if [[ -f "$script_dir/input-validation.sh" ]]; then source "$script_dir/input-validation.sh" else echo "警告: 安全输入验证模块未找到" >&2 fi # 等待用户确认 wait_for_user() { echo "" read -p "按回车键继续..." -r } # 生成随机密码 (安全版本) generate_password() { local length="${1:-12}" # 验证长度参数 if command -v validate_number_secure >/dev/null 2>&1; then if ! validate_number_secure "$length" 8 64; then echo "警告: 密码长度无效,使用默认值12" >&2 length=12 fi else # 基础验证 if [[ ! "$length" =~ ^[0-9]+$ ]] || [[ $length -lt 8 ]] || [[ $length -gt 64 ]]; then echo "警告: 密码长度无效,使用默认值12" >&2 length=12 fi fi # 安全生成密码 openssl rand -base64 "$length" | tr -d "=+/" | cut -c1-"$length" } # 验证域名格式 validate_domain() { local domain=$1 if [[ $domain =~ ^[a-zA-Z0-9]([a-zA-Z0-9\-]{0,61}[a-zA-Z0-9])?(\.[a-zA-Z0-9]([a-zA-Z0-9\-]{0,61}[a-zA-Z0-9])?)*$ ]]; then return 0 else return 1 fi } # 验证邮箱格式 validate_email() { local email=$1 if [[ $email =~ ^[a-zA-Z0-9._%+-]+@[a-zA-Z0-9.-]+\.[a-zA-Z]{2,}$ ]]; then return 0 else return 1 fi } # 获取服务器域名配置 get_server_domain() { if [[ -f "/etc/hysteria/server-domain.conf" ]]; then cat "/etc/hysteria/server-domain.conf" else echo "" fi } # 获取当前配置文件中的监听端口 get_current_listen_port() { if [[ -f "$CONFIG_PATH" ]]; then local port=$(grep -E "^\s*listen:" "$CONFIG_PATH" | awk -F':' '{print $3}' | tr -d ' ' | head -1) echo "${port:-443}" else echo "443" fi } # ACME 配置模式 configure_acme_mode() { echo -e "${BLUE}ACME 自动证书配置${NC}" echo "" # 检查是否已配置服务器域名 local configured_domain=$(get_server_domain) local domain="" if [[ -n "$configured_domain" ]]; then echo -e "${GREEN}检测到已配置的服务器域名: $configured_domain${NC}" echo "" echo -n -e "${YELLOW}是否使用已配置的域名? [Y/n]: ${NC}" read -r use_configured if [[ ! $use_configured =~ ^[Nn]$ ]]; then domain="$configured_domain" echo -e "${GREEN}使用已配置域名: $domain${NC}" fi fi # 如果没有使用已配置域名,则手动输入 if [[ -z "$domain" ]]; then echo -e "${BLUE}手动输入域名${NC}" while true; do echo -n -e "${BLUE}请输入域名 (例: your.domain.com): ${NC}" read -r domain if validate_domain "$domain"; then break else echo -e "${RED}域名格式无效,请重新输入${NC}" fi done fi # 输入邮箱 while true; do echo -n -e "${BLUE}请输入邮箱地址: ${NC}" read -r email if validate_email "$email"; then break else echo -e "${RED}邮箱格式无效,请重新输入${NC}" fi done # 输入监听端口 echo -n -e "${BLUE}请输入监听端口 (默认 443): ${NC}" read -r listen_port listen_port=${listen_port:-443} # 验证端口范围 if [[ ! "$listen_port" =~ ^[0-9]+$ ]] || [[ "$listen_port" -lt 1 ]] || [[ "$listen_port" -gt 65535 ]]; then echo -e "${YELLOW}端口范围无效,使用默认端口 443${NC}" listen_port=443 fi # 输入认证密码 echo -n -e "${BLUE}请输入认证密码 (留空自动生成): ${NC}" read -r password if [[ -z "$password" ]]; then password=$(generate_password 16) echo -e "${GREEN}自动生成密码: $password${NC}" fi # 询问是否启用混淆 echo "" echo -n -e "${BLUE}是否启用混淆功能? [Y/n]: ${NC}" read -r enable_obfs local obfs_config="" if [[ ! $enable_obfs =~ ^[Nn]$ ]]; then echo -n -e "${BLUE}请输入混淆密码 (留空自动生成): ${NC}" read -r obfs_password if [[ -z "$obfs_password" ]]; then obfs_password=$(generate_password 16) echo -e "${GREEN}自动生成混淆密码: $obfs_password${NC}" fi obfs_config=" obfs: type: salamander salamander: password: $obfs_password" fi # 选择伪装网站 echo "" echo -e "${BLUE}选择伪装网站:${NC}" echo "1. 使用默认 (news.ycombinator.com)" echo "2. 自动测试选择最优域名" echo "3. 手动输入" echo -n -e "${BLUE}请选择 [1-3]: ${NC}" read -r masq_choice case $masq_choice in 1) masquerade_url="https://news.ycombinator.com/" ;; 2) echo -e "${BLUE}正在测试域名延迟...${NC}" if [[ -f "$SCRIPTS_DIR/domain-test.sh" ]]; then source "$SCRIPTS_DIR/domain-test.sh" masquerade_url=$(get_best_domain) else masquerade_url="https://news.ycombinator.com/" fi ;; 3) echo -n -e "${BLUE}请输入伪装网站URL: ${NC}" read -r masquerade_url ;; *) masquerade_url="https://news.ycombinator.com/" ;; esac # 生成配置文件 cat > "$CONFIG_PATH" << EOF # Hysteria2 配置文件 - ACME 模式 # 生成时间: $(date) listen: :$listen_port acme: domains: - $domain email: $email auth: type: password password: $password$obfs_config masquerade: type: proxy proxy: url: $masquerade_url rewriteHost: true EOF echo "" echo -e "${GREEN}ACME 配置文件生成成功!${NC}" echo -e "${YELLOW}域名: $domain${NC}" echo -e "${YELLOW}邮箱: $email${NC}" echo -e "${YELLOW}监听端口: $listen_port${NC}" echo -e "${YELLOW}认证密码: $password${NC}" if [[ -n "$obfs_password" ]]; then echo -e "${YELLOW}混淆密码: $obfs_password${NC}" echo -e "${YELLOW}混淆类型: Salamander${NC}" else echo -e "${YELLOW}混淆功能: 未启用${NC}" fi echo -e "${YELLOW}伪装网站: $masquerade_url${NC}" wait_for_user } # 自签名证书配置模式 configure_self_cert_mode() { echo -e "${BLUE}自签名证书配置${NC}" echo "" # 选择伪装域名 echo -e "${BLUE}选择伪装域名:${NC}" echo "1. 使用默认 (cdn.jsdelivr.net)" echo "2. 自动测试选择最优域名" echo "3. 手动输入" echo -n -e "${BLUE}请选择 [1-3]: ${NC}" read -r domain_choice case $domain_choice in 1) cert_domain="cdn.jsdelivr.net" masquerade_url="https://cdn.jsdelivr.net/" ;; 2) echo -e "${BLUE}正在测试域名延迟...${NC}" if [[ -f "$SCRIPTS_DIR/domain-test.sh" ]]; then source "$SCRIPTS_DIR/domain-test.sh" best_domain=$(get_best_domain_name) cert_domain="$best_domain" masquerade_url="https://$best_domain/" else cert_domain="cdn.jsdelivr.net" masquerade_url="https://cdn.jsdelivr.net/" fi ;; 3) echo -n -e "${BLUE}请输入伪装域名: ${NC}" read -r cert_domain masquerade_url="https://$cert_domain/" ;; *) cert_domain="cdn.jsdelivr.net" masquerade_url="https://cdn.jsdelivr.net/" ;; esac # 输入监听端口 echo -n -e "${BLUE}请输入监听端口 (默认 443): ${NC}" read -r listen_port listen_port=${listen_port:-443} # 验证端口范围 if [[ ! "$listen_port" =~ ^[0-9]+$ ]] || [[ "$listen_port" -lt 1 ]] || [[ "$listen_port" -gt 65535 ]]; then echo -e "${YELLOW}端口范围无效,使用默认端口 443${NC}" listen_port=443 fi # 输入认证密码 echo -n -e "${BLUE}请输入认证密码 (留空自动生成): ${NC}" read -r password if [[ -z "$password" ]]; then password=$(generate_password 16) echo -e "${GREEN}自动生成密码: $password${NC}" fi # 询问是否启用混淆 echo "" echo -n -e "${BLUE}是否启用混淆功能? [Y/n]: ${NC}" read -r enable_obfs local obfs_config="" if [[ ! $enable_obfs =~ ^[Nn]$ ]]; then echo -n -e "${BLUE}请输入混淆密码 (留空自动生成): ${NC}" read -r obfs_password if [[ -z "$obfs_password" ]]; then obfs_password=$(generate_password 16) echo -e "${GREEN}自动生成混淆密码: $obfs_password${NC}" fi obfs_config=" obfs: type: salamander salamander: password: $obfs_password" fi # 生成自签名证书 echo -e "${BLUE}生成自签名证书...${NC}" mkdir -p /etc/hysteria openssl req -x509 -nodes -newkey ec:<(openssl ecparam -name prime256v1) \ -keyout /etc/hysteria/server.key \ -out /etc/hysteria/server.crt \ -subj "/CN=$cert_domain" \ -days 3650 # 设置证书权限 if id "hysteria" &>/dev/null; then chown hysteria:hysteria /etc/hysteria/server.key chown hysteria:hysteria /etc/hysteria/server.crt fi # 生成配置文件 cat > "$CONFIG_PATH" << EOF # Hysteria2 配置文件 - 自签名证书模式 # 生成时间: $(date) listen: :$listen_port tls: cert: /etc/hysteria/server.crt key: /etc/hysteria/server.key auth: type: password password: $password$obfs_config masquerade: type: proxy proxy: url: $masquerade_url rewriteHost: true EOF echo "" echo -e "${GREEN}自签名证书配置生成成功!${NC}" echo -e "${YELLOW}证书域名: $cert_domain${NC}" echo -e "${YELLOW}监听端口: $listen_port${NC}" echo -e "${YELLOW}认证密码: $password${NC}" if [[ -n "$obfs_password" ]]; then echo -e "${YELLOW}混淆密码: $obfs_password${NC}" echo -e "${YELLOW}混淆类型: Salamander${NC}" else echo -e "${YELLOW}混淆功能: 未启用${NC}" fi echo -e "${YELLOW}伪装网站: $masquerade_url${NC}" wait_for_user } # 获取服务器公网IP get_server_ip() { local ip="" # 尝试多种方法获取公网IP ip=$(curl -s --connect-timeout 5 ipv4.icanhazip.com 2>/dev/null) || \ ip=$(curl -s --connect-timeout 5 ifconfig.me 2>/dev/null) || \ ip=$(curl -s --connect-timeout 5 ip.sb 2>/dev/null) || \ ip=$(curl -s --connect-timeout 5 checkip.amazonaws.com 2>/dev/null) if [[ -n "$ip" && "$ip" =~ ^[0-9]{1,3}\.[0-9]{1,3}\.[0-9]{1,3}\.[0-9]{1,3}$ ]]; then echo "$ip" else # 如果无法获取公网IP,尝试获取本地IP ip=$(ip route get 8.8.8.8 2>/dev/null | grep -oP 'src \K\S+') echo "${ip:-127.0.0.1}" fi } # 自动检测网卡 get_network_interface() { # 获取默认路由的网卡 local interface=$(ip route | grep default | head -1 | awk '{print $5}') # 如果没有找到,尝试其他方法 if [[ -z "$interface" ]]; then interface=$(ip link show | grep -E "^[0-9]+:" | grep -v lo | head -1 | awk -F': ' '{print $2}') fi # 最后的备选方案 if [[ -z "$interface" ]]; then interface="eth0" fi echo "$interface" } # 改进的端口跳跃状态检查 check_port_hopping_status() { local interface=$(get_network_interface) local target_port=$(get_current_listen_port) # 多种检测方式 local found=false # 方式1: 检查 REDIRECT 规则到目标端口 if iptables -t nat -L PREROUTING -n --line-numbers 2>/dev/null | grep -q "REDIRECT.*dpt:.*--to-ports $target_port"; then found=true fi # 方式2: 检查端口范围规则 if iptables -t nat -L PREROUTING -n 2>/dev/null | grep -E "REDIRECT.*dpts:[0-9]+:[0-9]+.*--to-ports $target_port" >/dev/null; then found=true fi # 方式3: 检查保存的配置文件 if [[ -f "/etc/hysteria/port-hopping.conf" ]]; then source /etc/hysteria/port-hopping.conf 2>/dev/null if [[ -n "$IPTABLES_RULE" ]]; then # 验证规则是否实际存在 local rule_parts IFS=' ' read -ra rule_parts <<< "$IPTABLES_RULE" local check_rule="" for part in "${rule_parts[@]}"; do if [[ "$part" != "iptables" && "$part" != "-t" && "$part" != "nat" && "$part" != "-A" ]]; then check_rule+="$part " fi done if iptables -t nat -C PREROUTING $check_rule 2>/dev/null; then found=true fi fi fi # 方式4: 通用检查 - 查找所有 REDIRECT 到目标端口的规则 if iptables -t nat -S PREROUTING 2>/dev/null | grep -E "REDIRECT.*--to-ports $target_port" >/dev/null; then found=true fi if $found; then return 0 # 已开启 else return 1 # 未开启 fi } # 获取当前端口跳跃配置信息 get_port_hopping_info() { local interface=$(get_network_interface) local info="" # 尝试从配置文件获取信息 if [[ -f "/etc/hysteria/port-hopping.conf" ]]; then source /etc/hysteria/port-hopping.conf 2>/dev/null if [[ -n "$START_PORT" && -n "$END_PORT" && -n "$TARGET_PORT" ]]; then info="端口范围: $START_PORT-$END_PORT -> $TARGET_PORT" fi fi # 如果配置文件没有信息,尝试从 iptables 规则解析 if [[ -z "$info" ]]; then local target_port=$(get_current_listen_port) local rule_info=$(iptables -t nat -L PREROUTING -n 2>/dev/null | grep "REDIRECT.*--to-ports $target_port" | head -1) if [[ -n "$rule_info" ]]; then # 尝试提取端口范围信息 if [[ "$rule_info" =~ dpts:([0-9]+):([0-9]+) ]]; then local start_port="${BASH_REMATCH[1]}" local end_port="${BASH_REMATCH[2]}" info="端口范围: $start_port-$end_port -> $target_port" elif [[ "$rule_info" =~ dpt:([0-9]+) ]]; then local port="${BASH_REMATCH[1]}" info="单端口: $port -> $target_port" else info="检测到端口跳跃规则" fi fi fi echo "$info" } # 清除端口跳跃规则 clear_port_hopping_rules() { local cleared=false local interface=$(get_network_interface) echo -e "${BLUE}正在清除端口跳跃规则...${NC}" # 方式1: 使用保存的配置文件中的规则 if [[ -f "/etc/hysteria/port-hopping.conf" ]]; then source /etc/hysteria/port-hopping.conf 2>/dev/null if [[ -n "$IPTABLES_RULE" ]]; then # 将 -A 替换为 -D 来删除规则 local delete_rule="${IPTABLES_RULE/-A/-D}" if eval "$delete_rule" 2>/dev/null; then echo "已清除配置文件中记录的规则" cleared=true fi fi fi # 方式2: 清除所有到目标端口的REDIRECT规则 local target_port=$(get_current_listen_port) local rules_to_delete=() while IFS= read -r line; do if [[ "$line" =~ ^-A\ PREROUTING.*REDIRECT.*--to-ports\ $target_port ]]; then rules_to_delete+=("${line/-A/-D}") fi done < <(iptables -t nat -S PREROUTING 2>/dev/null) for rule in "${rules_to_delete[@]}"; do if iptables -t nat $rule 2>/dev/null; then echo "已清除规则: $rule" cleared=true fi done # 方式3: 通用清理方式(基于行号) local line_numbers=($(iptables -t nat -L PREROUTING --line-numbers 2>/dev/null | grep "REDIRECT.*--to-ports $target_port" | awk '{print $1}' | sort -rn)) for line_num in "${line_numbers[@]}"; do if iptables -t nat -D PREROUTING "$line_num" 2>/dev/null; then echo "已清除第 $line_num 行规则" cleared=true fi done # 删除配置文件 if [[ -f "/etc/hysteria/port-hopping.conf" ]]; then rm -f "/etc/hysteria/port-hopping.conf" echo "已删除端口跳跃配置文件" fi if $cleared; then echo -e "${GREEN}端口跳跃规则清除成功${NC}" else echo -e "${YELLOW}没有找到需要清除的端口跳跃规则${NC}" fi } # 清除所有端口跳跃规则(系统级别) clear_all_port_hopping_rules() { local cleared=false echo -e "${BLUE}正在清除所有端口跳跃规则...${NC}" # 获取所有REDIRECT规则 local all_redirect_rules=() while IFS= read -r line; do if [[ "$line" =~ ^-A\ PREROUTING.*REDIRECT ]]; then all_redirect_rules+=("${line/-A/-D}") fi done < <(iptables -t nat -S PREROUTING 2>/dev/null) # 删除所有REDIRECT规则 for rule in "${all_redirect_rules[@]}"; do if iptables -t nat $rule 2>/dev/null; then echo "已清除规则: $rule" cleared=true fi done # 备选方法:按行号删除所有REDIRECT规则 local line_numbers=($(iptables -t nat -L PREROUTING --line-numbers 2>/dev/null | grep "REDIRECT" | awk '{print $1}' | sort -rn)) for line_num in "${line_numbers[@]}"; do if iptables -t nat -D PREROUTING "$line_num" 2>/dev/null; then echo "已清除第 $line_num 行REDIRECT规则" cleared=true fi done # 删除所有相关的配置文件 if [[ -f "/etc/hysteria/port-hopping.conf" ]]; then rm -f "/etc/hysteria/port-hopping.conf" echo "已删除端口跳跃配置文件" fi if $cleared; then echo -e "${GREEN}所有端口跳跃规则清除成功${NC}" local remaining_rules=$(iptables -t nat -L PREROUTING -n 2>/dev/null | grep "REDIRECT" | wc -l) if [[ $remaining_rules -eq 0 ]]; then echo -e "${GREEN}确认:系统中没有剩余的端口重定向规则${NC}" else echo -e "${YELLOW}警告:系统中还有 $remaining_rules 条端口重定向规则${NC}" fi else echo -e "${YELLOW}没有找到需要清除的端口跳跃规则${NC}" fi } # 清除指定端口的跳跃规则 clear_specific_port_rules() { local target_port="$1" local cleared=false if [[ -z "$target_port" ]]; then echo -e "${RED}错误: 未指定目标端口${NC}" return 1 fi echo -e "${BLUE}正在清除指向端口 $target_port 的跳跃规则...${NC}" # 清除指向特定端口的REDIRECT规则 local rules_to_delete=() while IFS= read -r line; do if [[ "$line" =~ ^-A\ PREROUTING.*REDIRECT.*--to-ports\ $target_port ]]; then rules_to_delete+=("${line/-A/-D}") fi done < <(iptables -t nat -S PREROUTING 2>/dev/null) for rule in "${rules_to_delete[@]}"; do if iptables -t nat $rule 2>/dev/null; then echo "已清除规则: $rule" cleared=true fi done # 备选方法:按行号删除 local line_numbers=($(iptables -t nat -L PREROUTING --line-numbers 2>/dev/null | grep "REDIRECT.*--to-ports $target_port" | awk '{print $1}' | sort -rn)) for line_num in "${line_numbers[@]}"; do if iptables -t nat -D PREROUTING "$line_num" 2>/dev/null; then echo "已清除第 $line_num 行规则" cleared=true fi done if $cleared; then echo -e "${GREEN}指向端口 $target_port 的跳跃规则清除成功${NC}" else echo -e "${YELLOW}没有找到指向端口 $target_port 的跳跃规则${NC}" fi } # 添加端口跳跃规则 add_port_hopping_rules() { local interface=$(get_network_interface) local start_port=${1:-20000} local end_port=${2:-50000} local target_port=${3:-$(get_current_listen_port)} echo -e "${BLUE}正在添加端口跳跃规则...${NC}" # 生成 iptables 规则 local iptables_rule="iptables -t nat -A PREROUTING -i $interface -p udp --dport $start_port:$end_port -j REDIRECT --to-ports $target_port" if eval "$iptables_rule" 2>/dev/null; then echo -e "${GREEN}端口跳跃规则添加成功${NC}" echo "规则: $start_port-$end_port -> $target_port (接口: $interface)" # 保存配置到文件 cat > "/etc/hysteria/port-hopping.conf" << EOF # 端口跳跃配置 # 生成时间: $(date) INTERFACE=$interface START_PORT=$start_port END_PORT=$end_port TARGET_PORT=$target_port IPTABLES_RULE="$iptables_rule" EOF echo "配置已保存到: /etc/hysteria/port-hopping.conf" return 0 else echo -e "${RED}端口跳跃规则添加失败${NC}" echo "请检查 iptables 权限或网络接口设置" return 1 fi } # 询问端口跳跃设置 ask_port_hopping_config() { echo -e "${BLUE}检查端口跳跃状态...${NC}" if check_port_hopping_status; then local hopping_info=$(get_port_hopping_info) echo -e "${GREEN}✅ 端口跳跃已开启${NC}" if [[ -n "$hopping_info" ]]; then echo " $hopping_info" fi echo "" echo -n -e "${YELLOW}是否保持端口跳跃开启? [Y/n]: ${NC}" read -r keep_hopping if [[ $keep_hopping =~ ^[Nn]$ ]]; then clear_port_hopping_rules else echo -e "${GREEN}保持端口跳跃开启${NC}" fi else echo -e "${YELLOW}❌ 端口跳跃未开启${NC}" echo "" echo -n -e "${YELLOW}是否开启端口跳跃? [y/N]: ${NC}" read -r enable_hopping if [[ $enable_hopping =~ ^[Yy]$ ]]; then # 询问端口范围 echo "" echo -e "${BLUE}配置端口跳跃范围:${NC}" echo -n -e "${BLUE}起始端口 (默认 20000): ${NC}" read -r start_port start_port=${start_port:-20000} echo -n -e "${BLUE}结束端口 (默认 50000): ${NC}" read -r end_port end_port=${end_port:-50000} local current_port=$(get_current_listen_port) if add_port_hopping_rules "$start_port" "$end_port" "$current_port"; then echo -e "${GREEN}端口跳跃配置完成${NC}" fi else echo -e "${BLUE}保持端口跳跃关闭${NC}" fi fi echo "" } # 询问是否重启服务 ask_restart_service() { echo "" echo -n -e "${YELLOW}配置已完成,是否立即重启 Hysteria2 服务? [Y/n]: ${NC}" read -r restart_service if [[ ! $restart_service =~ ^[Nn]$ ]]; then echo -e "${BLUE}正在重启 Hysteria2 服务...${NC}" systemctl restart hysteria-server sleep 2 if systemctl is-active --quiet hysteria-server; then echo -e "${GREEN}✅ 服务重启成功${NC}" else echo -e "${RED}❌ 服务重启失败${NC}" echo "请检查配置文件或查看日志: journalctl -u hysteria-server.service" fi else echo -e "${YELLOW}请稍后手动重启服务: systemctl restart hysteria-server${NC}" fi } # 一键快速配置 quick_setup_hysteria() { echo -e "${CYAN}=== Hysteria2 一键快速配置 ===${NC}" echo "" # 检查是否已安装 if ! check_hysteria_installed; then echo -e "${RED}错误: Hysteria2 未安装${NC}" echo "请先安装 Hysteria2" return fi # 检查现有配置 if [[ -f "$CONFIG_PATH" ]]; then echo -e "${YELLOW}检测到现有配置文件${NC}" echo -n -e "${BLUE}是否覆盖现有配置? [y/N]: ${NC}" read -r overwrite if [[ ! $overwrite =~ ^[Yy]$ ]]; then echo -e "${BLUE}取消配置生成${NC}" return fi # 备份现有配置 cp "$CONFIG_PATH" "$CONFIG_PATH.backup.$(date +%Y%m%d_%H%M%S)" echo -e "${GREEN}已备份现有配置${NC}" fi echo -e "${BLUE}正在执行一键快速配置...${NC}" echo "" # 1. 获取服务器信息 echo -e "${BLUE}步骤 1/7: 获取服务器信息...${NC}" local server_ip=$(get_server_ip) local network_interface=$(get_network_interface) echo "服务器IP: $server_ip" echo "网络接口: $network_interface" # 2. 测试最优伪装域名 echo -e "${BLUE}步骤 2/7: 测试最优伪装域名...${NC}" if [[ -f "$SCRIPTS_DIR/domain-test.sh" ]]; then source "$SCRIPTS_DIR/domain-test.sh" local best_domain=$(get_best_domain_name) local masquerade_url="https://$best_domain/" echo "最优伪装域名: $best_domain" else local best_domain="cdn.jsdelivr.net" local masquerade_url="https://cdn.jsdelivr.net/" echo "使用默认伪装域名: $best_domain" fi # 3. 生成密码 echo -e "${BLUE}步骤 3/7: 生成随机密码...${NC}" local auth_password=$(generate_password 16) local obfs_password=$(generate_password 16) echo "认证密码: $auth_password" echo "混淆密码: $obfs_password" # 4. 生成自签名证书 echo -e "${BLUE}步骤 4/7: 生成自签名证书...${NC}" mkdir -p /etc/hysteria openssl req -x509 -nodes -newkey ec:<(openssl ecparam -name prime256v1) \ -keyout /etc/hysteria/server.key \ -out /etc/hysteria/server.crt \ -subj "/CN=$best_domain" \ -days 3650 &>/dev/null # 设置证书权限 if id "hysteria" &>/dev/null; then chown hysteria:hysteria /etc/hysteria/server.key chown hysteria:hysteria /etc/hysteria/server.crt fi echo "证书生成完成" # 5. 生成配置文件 echo -e "${BLUE}步骤 5/7: 生成配置文件...${NC}" cat > "$CONFIG_PATH" << EOF # Hysteria2 配置文件 - 一键快速配置 # 生成时间: $(date) # 服务器IP: $server_ip listen: :443 tls: cert: /etc/hysteria/server.crt key: /etc/hysteria/server.key auth: type: password password: $auth_password masquerade: type: proxy proxy: url: $masquerade_url rewriteHost: true obfs: type: salamander salamander: password: $obfs_password EOF # 设置配置文件权限 if id "hysteria" &>/dev/null; then chown hysteria:hysteria "$CONFIG_PATH" fi chmod 600 "$CONFIG_PATH" echo "配置文件生成完成" # 6. 配置端口跳跃 echo -e "${BLUE}步骤 6/7: 配置端口跳跃...${NC}" local start_port=20000 local end_port=50000 local target_port=$(get_current_listen_port) if add_port_hopping_rules "$start_port" "$end_port" "$target_port"; then echo "端口跳跃配置成功 ($start_port-$end_port -> $target_port)" else echo "端口跳跃配置失败,跳过此步骤" fi # 7. 启动服务 echo -e "${BLUE}步骤 7/7: 启动服务...${NC}" # 启用并启动服务 systemctl enable hysteria-server.service &>/dev/null if systemctl start hysteria-server.service; then sleep 3 if systemctl is-active --quiet hysteria-server.service; then echo -e "${GREEN}服务启动成功!${NC}" # 显示配置信息 echo "" echo -e "${CYAN}=== 一键快速配置完成 ===${NC}" echo "" echo -e "${YELLOW}配置信息:${NC}" echo "服务器地址: $server_ip:443" echo "认证密码: $auth_password" echo "混淆密码: $obfs_password" echo "伪装域名: $best_domain" echo "端口跳跃: $start_port-$end_port" echo "" # 生成节点信息 generate_node_info "$server_ip" "$auth_password" "$obfs_password" "$best_domain" "$start_port" "$end_port" else echo -e "${RED}服务启动失败${NC}" echo "请查看日志: journalctl -u hysteria-server.service" fi else echo -e "${RED}服务启动失败${NC}" fi echo "" wait_for_user } # 生成节点信息 generate_node_info() { local server_ip="$1" local auth_password="$2" local obfs_password="$3" local sni_domain="$4" local start_port="$5" local end_port="$6" # 检查是否有配置的服务器域名 local configured_domain=$(get_server_domain) local server_address="" if [[ -n "$configured_domain" ]]; then server_address="$configured_domain:443" echo -e "${GREEN}使用已配置的服务器域名: $configured_domain${NC}" else server_address="$server_ip:443" echo -e "${YELLOW}使用服务器IP地址: $server_ip${NC}" fi # 保存节点信息到文件 local node_file="/etc/hysteria/node-info.txt" cat > "$node_file" << EOF # Hysteria2 节点信息 # 生成时间: $(date) 服务器地址: $server_address 认证密码: $auth_password 混淆密码: $obfs_password SNI域名: $sni_domain 端口跳跃: $start_port-$end_port 证书验证: 忽略 (自签名证书) # 客户端配置示例 server: $server_address auth: $auth_password tls: sni: $sni_domain insecure: true obfs: type: salamander salamander: password: $obfs_password socks5: listen: 127.0.0.1:1080 http: listen: 127.0.0.1:8080 # 节点链接 (Hysteria2://) hysteria2://$auth_password@$server_ip:443?sni=$sni_domain&insecure=1&obfs=salamander&obfs-password=$obfs_password#Hysteria2-QuickSetup # 订阅链接 (Base64编码) $(echo "hysteria2://$auth_password@$server_ip:443?sni=$sni_domain&insecure=1&obfs=salamander&obfs-password=$obfs_password#Hysteria2-QuickSetup" | base64 -w 0) EOF echo -e "${GREEN}节点信息已保存到: $node_file${NC}" } # 主配置生成函数 generate_hysteria_config() { # 检查是否已安装 if ! check_hysteria_installed; then echo -e "${RED}错误: Hysteria2 未安装${NC}" echo "请先安装 Hysteria2" return fi # 检查现有配置 if [[ -f "$CONFIG_PATH" ]]; then echo -e "${YELLOW}检测到现有配置文件${NC}" echo -n -e "${BLUE}是否覆盖现有配置? [y/N]: ${NC}" read -r overwrite if [[ ! $overwrite =~ ^[Yy]$ ]]; then echo -e "${BLUE}取消配置生成${NC}" return fi # 备份现有配置 cp "$CONFIG_PATH" "$CONFIG_PATH.backup.$(date +%Y%m%d_%H%M%S)" echo -e "${GREEN}已备份现有配置${NC}" fi echo "" echo -e "${BLUE}选择配置模式:${NC}" echo "" echo -e "${GREEN}1.${NC} ACME 自动证书 (推荐,需要域名)" echo -e "${GREEN}2.${NC} 自签名证书 (快速部署,无需域名)" echo "" echo -n -e "${BLUE}请选择模式 [1-2]: ${NC}" read -r config_mode case $config_mode in 1) configure_acme_mode ;; 2) configure_self_cert_mode ;; *) echo -e "${RED}无效选择${NC}" return ;; esac # 设置配置文件权限 if id "hysteria" &>/dev/null; then chown hysteria:hysteria "$CONFIG_PATH" fi chmod 600 "$CONFIG_PATH" echo "" echo -e "${GREEN}配置文件已保存到: $CONFIG_PATH${NC}" # 检查端口跳跃状态并询问 ask_port_hopping_config # 询问是否重启服务 ask_restart_service echo "" echo -e "${YELLOW}其他管理命令:${NC}" echo "1. 查看状态: systemctl status hysteria-server.service" echo "2. 查看日志: journalctl -u hysteria-server.service" wait_for_user }