Files
sh/hy2.sh
2026-03-19 14:13:59 +08:00

359 lines
9.0 KiB
Bash
Raw Blame History

This file contains ambiguous Unicode characters
This file contains Unicode characters that might be confused with other characters. If you think that this is intentional, you can safely ignore this warning. Use the Escape button to reveal them.
#!/usr/bin/env bash
set -Eeuo pipefail
CONFIG_FILE="/etc/hysteria/config.yaml"
SERVICE_NAME="hysteria-server.service"
red() { printf '\033[31m%s\033[0m\n' "$*"; }
green() { printf '\033[32m%s\033[0m\n' "$*"; }
yellow() { printf '\033[33m%s\033[0m\n' "$*"; }
blue() { printf '\033[36m%s\033[0m\n' "$*"; }
require_root() {
if [[ "${EUID}" -ne 0 ]]; then
red "请使用 root 运行此脚本。"
exit 1
fi
}
require_cmd() {
command -v "$1" >/dev/null 2>&1 || {
red "缺少命令: $1"
exit 1
}
}
prompt_nonempty() {
local prompt="$1"
local value=""
while true; do
read -r -p "$prompt" value
if [[ -n "${value// }" ]]; then
printf '%s' "$value"
return 0
fi
yellow "输入不能为空,请重新输入。"
done
}
confirm_yes() {
local prompt="${1:-确认继续?输入 yes 继续: }"
local answer
read -r -p "$prompt" answer
[[ "$answer" == "yes" ]]
}
double_confirm() {
local title="$1"
local detail="$2"
echo
yellow "========== 二次确认 =========="
yellow "$title"
echo "$detail"
echo
confirm_yes "第一次确认,输入 yes 继续: " || return 1
confirm_yes "第二次确认,输入 yes 最终执行: " || return 1
return 0
}
generate_password() {
tr -dc 'A-Za-z0-9' </dev/urandom | head -c 24
}
get_server_ip() {
local ipv4 ipv6
ipv4="$(curl -4 -fsSL https://api.ipify.org || true)"
ipv6="$(curl -6 -fsSL https://api64.ipify.org || true)"
echo "${ipv4}|${ipv6}"
}
apt_update_and_install_base() {
if ! double_confirm \
"即将更新 APT 软件库并安装基础依赖" \
$'将执行:\n- apt update -y\n- apt install -y curl sed ufw iptables ip6tables'; then
red "用户取消:未执行软件库更新和基础依赖安装。"
exit 1
fi
blue "==> 更新 APT 软件库"
export DEBIAN_FRONTEND=noninteractive
apt update -y
blue "==> 安装基础依赖"
apt install -y curl sed ufw iptables ip6tables
}
disable_existing_firewalls() {
if ! double_confirm \
"即将停用当前系统防火墙并清空规则" \
$'将尝试执行以下操作:\n- 关闭并重置 UFW\n- 停止并禁用 firewalld\n- 停止并禁用 nftables\n- 清空 nftables ruleset\n- 清空 iptables / ip6tables 规则\n\n该操作可能影响当前网络访问控制策略。'; then
red "用户取消:未停用现有防火墙。"
exit 1
fi
blue "==> 自动检测并关闭当前系统防火墙"
if command -v ufw >/dev/null 2>&1; then
yellow "检测到 UFW正在关闭并重置"
ufw disable || true
yes | ufw reset || true
fi
if systemctl list-unit-files 2>/dev/null | grep -q '^firewalld\.service'; then
yellow "检测到 firewalld正在停止并禁用"
systemctl stop firewalld || true
systemctl disable firewalld || true
systemctl mask firewalld || true
fi
if systemctl list-unit-files 2>/dev/null | grep -q '^nftables\.service'; then
yellow "检测到 nftables正在停止并禁用"
systemctl stop nftables || true
systemctl disable nftables || true
fi
if command -v nft >/dev/null 2>&1; then
yellow "清空 nftables 规则"
nft flush ruleset || true
fi
yellow "清空 iptables / ip6tables 规则"
iptables -I INPUT 1 -p tcp --dport 22 -j ACCEPT || true
ip6tables -I INPUT 1 -p tcp --dport 22 -j ACCEPT || true
iptables -F || true
iptables -X || true
iptables -Z || true
iptables -P INPUT ACCEPT || true
iptables -P FORWARD ACCEPT || true
iptables -P OUTPUT ACCEPT || true
ip6tables -F || true
ip6tables -X || true
ip6tables -Z || true
ip6tables -P INPUT ACCEPT || true
ip6tables -P FORWARD ACCEPT || true
ip6tables -P OUTPUT ACCEPT || true
green "现有防火墙已处理完成。"
}
configure_ufw() {
if ! double_confirm \
"即将启用并配置 UFW" \
$'将执行以下规则:\n- 默认拒绝入站\n- 默认允许出站\n- 放行 22/tcp\n- 放行 80/tcp\n- 放行 443/tcp\n- 放行 443/udp\n- 启用 IPv6'; then
red "用户取消:未配置 UFW。"
exit 1
fi
blue "==> 配置 UFW"
sed -i 's/^IPV6=.*/IPV6=yes/' /etc/default/ufw || true
ufw default deny incoming || true
ufw default allow outgoing || true
ufw allow 22/tcp || true
ufw allow 80/tcp || true
ufw allow 443/tcp || true
ufw allow 443/udp || true
yes | ufw enable || true
green "UFW 配置完成。"
}
install_hysteria2() {
if ! double_confirm \
"即将安装 Hysteria 2" \
$'将执行:\n- bash <(curl -fsSL https://get.hy2.sh/)\n\n该步骤会从外部下载安装脚本并执行。'; then
red "用户取消:未安装 Hysteria 2。"
exit 1
fi
blue "==> 安装 Hysteria 2"
bash <(curl -fsSL https://get.hy2.sh/)
green "Hysteria 2 安装完成。"
}
run_domain_selector() {
blue "==> 执行域名筛选脚本"
yellow "请根据脚本输出结果,手动输入最终伪装 URL"
if ! confirm_yes "确认执行外部域名筛选脚本?输入 yes 继续: "; then
red "用户取消:未执行域名筛选脚本。"
return 0
fi
bash <(curl -sL https://raw.githubusercontent.com/ccxkai233/Domain_Selector/main/domain_check.sh) || true
}
backup_existing_config() {
if [[ -f "${CONFIG_FILE}" ]]; then
local backup_file="${CONFIG_FILE}.bak.$(date +%Y%m%d_%H%M%S)"
cp -a "${CONFIG_FILE}" "${backup_file}"
yellow "检测到已有配置,已备份到: ${backup_file}"
fi
}
write_config() {
local domain="$1"
local email="$2"
local cf_token="$3"
local password="$4"
local proxy_url="$5"
echo
blue "==> 即将写入以下配置"
cat <<EOF
listen: :443
acme:
domains:
- ${domain}
email: ${email}
type: dns
dns:
name: cloudflare
config:
cloudflare_api_token: ${cf_token}
auth:
type: password
password: ${password}
masquerade:
type: proxy
proxy:
url: ${proxy_url}
rewriteHost: true
EOF
echo
if ! double_confirm \
"即将写入 Hysteria 配置文件" \
"目标文件:${CONFIG_FILE}
如已存在旧配置,将先自动备份,再覆盖写入。"; then
red "用户取消:未写入配置文件。"
exit 1
fi
mkdir -p /etc/hysteria
backup_existing_config
cat > "${CONFIG_FILE}" <<EOF
listen: :443
acme:
domains:
- ${domain}
email: ${email}
type: dns
dns:
name: cloudflare
config:
cloudflare_api_token: ${cf_token}
auth:
type: password
password: ${password}
masquerade:
type: proxy
proxy:
url: ${proxy_url}
rewriteHost: true
EOF
chmod 600 "${CONFIG_FILE}"
green "配置已写入 ${CONFIG_FILE}"
}
start_service() {
if ! double_confirm \
"即将启动并设置 Hysteria 开机自启" \
$'将执行:\n- systemctl daemon-reload\n- systemctl enable --now hysteria-server.service\n- systemctl restart hysteria-server.service'; then
red "用户取消:未启动服务。"
exit 1
fi
blue "==> 启动并设置开机自启"
systemctl daemon-reload || true
systemctl enable --now "${SERVICE_NAME}"
systemctl restart "${SERVICE_NAME}"
green "服务已启动。"
}
show_result() {
local domain="$1"
local password="$2"
local proxy_url="$3"
local ip_info="$4"
local ipv4="${ip_info%%|*}"
local ipv6="${ip_info##*|}"
local share_link="hysteria2://${password}@${domain}:443/?sni=${domain}&insecure=0"
echo
green "================= HY2 节点信息 ================="
echo "服务名: ${SERVICE_NAME}"
echo "配置文件: ${CONFIG_FILE}"
echo "域名: ${domain}"
echo "端口: 443"
echo "认证方式: password"
echo "密码: ${password}"
echo "伪装站点: ${proxy_url}"
[[ -n "${ipv4}" ]] && echo "服务器 IPv4: ${ipv4}"
[[ -n "${ipv6}" ]] && echo "服务器 IPv6: ${ipv6}"
echo
echo "代理链接:"
echo "${share_link}"
echo
echo "systemd 状态:"
systemctl --no-pager --full status "${SERVICE_NAME}" || true
echo
echo "最近日志:"
journalctl --no-pager -n 30 -u "${SERVICE_NAME}" || true
echo "================================================"
}
main() {
require_root
if ! double_confirm \
"脚本总确认" \
$'本脚本将执行以下操作:\n- apt update -y\n- 安装基础依赖\n- 自动检测并停用当前系统防火墙\n- 重建 UFW 规则\n- 安装 Hysteria 2\n- 写入 /etc/hysteria/config.yaml\n- 启动并启用 hysteria-server.service'; then
red "用户取消执行。"
exit 1
fi
local domain email cf_token password proxy_url ip_info
apt_update_and_install_base
require_cmd curl
require_cmd sed
require_cmd systemctl
require_cmd iptables
require_cmd ip6tables
require_cmd ufw
domain="$(prompt_nonempty '请输入用于签发证书的域名: ')"
email="$(prompt_nonempty '请输入 ACME 邮箱: ')"
cf_token="$(prompt_nonempty '请输入 Cloudflare API Token: ')"
password="$(generate_password)"
disable_existing_firewalls
configure_ufw
install_hysteria2
run_domain_selector
proxy_url="$(prompt_nonempty '请输入最终用于 masquerade 的完整 URL例如 https://example.com/: ')"
write_config "${domain}" "${email}" "${cf_token}" "${password}" "${proxy_url}"
start_service
ip_info="$(get_server_ip)"
show_result "${domain}" "${password}" "${proxy_url}" "${ip_info}"
}
main "$@"