├── README.md ├── hy1 ├── hysteria.sh └── install_server.sh └── hy2 ├── hysteria.sh └── install_server.sh /README.md: -------------------------------------------------------------------------------- 1 | # Hysteria-script 2 | 3 | Hysteria 协议一键部署脚本 4 | 5 | ## 一键脚本地址 6 | 7 | ### Hysteria 2 8 | 9 | ```shell 10 | wget -N --no-check-certificate https://raw.githubusercontent.com/Misaka-blog/hysteria-install/main/hy2/hysteria.sh && bash hysteria.sh 11 | ``` 12 | 13 | ### Hysteria 1 14 | 15 | ```shell 16 | wget -N --no-check-certificate https://raw.githubusercontent.com/Misaka-blog/hysteria-install/main/hy1/hysteria.sh && bash hysteria.sh 17 | ``` 18 | 19 | ## 赞助 20 | 21 | 爱发电:https://afdian.net/a/Misaka-blog 22 | 23 | ![afdian-MisakaNo の 小破站](https://user-images.githubusercontent.com/122191366/211533469-351009fb-9ae8-4601-992a-abbf54665b68.jpg) 24 | -------------------------------------------------------------------------------- /hy1/hysteria.sh: -------------------------------------------------------------------------------- 1 | #!/bin/bash 2 | 3 | RED="\033[31m" 4 | GREEN="\033[32m" 5 | YELLOW="\033[33m" 6 | PLAIN='\033[0m' 7 | 8 | red() { 9 | echo -e "\033[31m\033[01m$1\033[0m" 10 | } 11 | 12 | green() { 13 | echo -e "\033[32m\033[01m$1\033[0m" 14 | } 15 | 16 | yellow() { 17 | echo -e "\033[33m\033[01m$1\033[0m" 18 | } 19 | 20 | REGEX=("debian" "ubuntu" "centos|red hat|kernel|oracle linux|alma|rocky" "'amazon linux'" "fedora" "alpine") 21 | RELEASE=("Debian" "Ubuntu" "CentOS" "CentOS" "Fedora" "Alpine") 22 | PACKAGE_UPDATE=("apt-get update" "apt-get update" "yum -y update" "yum -y update" "yum -y update" "apk update -f") 23 | PACKAGE_INSTALL=("apt -y install" "apt -y install" "yum -y install" "yum -y install" "yum -y install" "apk add -f") 24 | PACKAGE_UNINSTALL=("apt -y autoremove" "apt -y autoremove" "yum -y autoremove" "yum -y autoremove" "yum -y autoremove" "apk del -f") 25 | 26 | [[ $EUID -ne 0 ]] && red "注意:请在root用户下运行脚本" && exit 1 27 | 28 | CMD=("$(grep -i pretty_name /etc/os-release 2>/dev/null | cut -d \" -f2)" "$(hostnamectl 2>/dev/null | grep -i system | cut -d : -f2)" "$(lsb_release -sd 2>/dev/null)" "$(grep -i description /etc/lsb-release 2>/dev/null | cut -d \" -f2)" "$(grep . /etc/redhat-release 2>/dev/null)" "$(grep . /etc/issue 2>/dev/null | cut -d \\ -f1 | sed '/^[ ]*$/d')") 29 | 30 | for i in "${CMD[@]}"; do 31 | SYS="$i" && [[ -n $SYS ]] && break 32 | done 33 | 34 | for ((int = 0; int < ${#REGEX[@]}; int++)); do 35 | if [[ $(echo "$SYS" | tr '[:upper:]' '[:lower:]') =~ ${REGEX[int]} ]]; then 36 | SYSTEM="${RELEASE[int]}" && [[ -n $SYSTEM ]] && break 37 | fi 38 | done 39 | 40 | [[ -z $SYSTEM ]] && red "不支持当前VPS系统, 请使用主流的操作系统" && exit 1 41 | 42 | realip(){ 43 | ip=$(curl -s4m8 ip.gs -k) || ip=$(curl -s6m8 ip.gs -k) 44 | } 45 | 46 | inst_cert(){ 47 | green "Hysteria 协议证书申请方式如下:" 48 | echo "" 49 | echo -e " ${GREEN}1.${PLAIN} 必应自签证书 ${YELLOW}(默认)${PLAIN}" 50 | echo -e " ${GREEN}2.${PLAIN} Acme 脚本自动申请" 51 | echo -e " ${GREEN}3.${PLAIN} 自定义证书路径" 52 | echo "" 53 | read -rp "请输入选项 [1-3]: " certInput 54 | if [[ $certInput == 2 ]]; then 55 | cert_path="/root/cert.crt" 56 | key_path="/root/private.key" 57 | if [[ -f /root/cert.crt && -f /root/private.key ]] && [[ -s /root/cert.crt && -s /root/private.key ]] && [[ -f /root/ca.log ]]; then 58 | domain=$(cat /root/ca.log) 59 | green "检测到原有域名:$domain 的证书,正在应用" 60 | hy_ym=$domain 61 | else 62 | WARPv4Status=$(curl -s4m8 https://www.cloudflare.com/cdn-cgi/trace -k | grep warp | cut -d= -f2) 63 | WARPv6Status=$(curl -s6m8 https://www.cloudflare.com/cdn-cgi/trace -k | grep warp | cut -d= -f2) 64 | if [[ $WARPv4Status =~ on|plus ]] || [[ $WARPv6Status =~ on|plus ]]; then 65 | wg-quick down wgcf >/dev/null 2>&1 66 | systemctl stop warp-go >/dev/null 2>&1 67 | realip 68 | wg-quick up wgcf >/dev/null 2>&1 69 | systemctl start warp-go >/dev/null 2>&1 70 | else 71 | realip 72 | fi 73 | 74 | read -p "请输入需要申请证书的域名:" domain 75 | [[ -z $domain ]] && red "未输入域名,无法执行操作!" && exit 1 76 | green "已输入的域名:$domain" && sleep 1 77 | domainIP=$(dig @8.8.8.8 +time=2 +short "$domain" 2>/dev/null) 78 | if echo $domainIP | grep -q "network unreachable\|timed out" || [[ -z $domainIP ]]; then 79 | domainIP=$(dig @2001:4860:4860::8888 +time=2 aaaa +short "$domain" 2>/dev/null) 80 | fi 81 | if echo $domainIP | grep -q "network unreachable\|timed out" || [[ -z $domainIP ]] ; then 82 | red "未解析出 IP,请检查域名是否输入有误" 83 | yellow "是否尝试强行匹配?" 84 | green "1. 是,将使用强行匹配" 85 | green "2. 否,退出脚本" 86 | read -p "请输入选项 [1-2]:" ipChoice 87 | if [[ $ipChoice == 1 ]]; then 88 | yellow "将尝试强行匹配以申请域名证书" 89 | else 90 | red "将退出脚本" 91 | exit 1 92 | fi 93 | fi 94 | if [[ $domainIP == $ip ]]; then 95 | ${PACKAGE_INSTALL[int]} curl wget sudo socat openssl 96 | if [[ $SYSTEM == "CentOS" ]]; then 97 | ${PACKAGE_INSTALL[int]} cronie 98 | systemctl start crond 99 | systemctl enable crond 100 | else 101 | ${PACKAGE_INSTALL[int]} cron 102 | systemctl start cron 103 | systemctl enable cron 104 | fi 105 | curl https://get.acme.sh | sh -s email=$(date +%s%N | md5sum | cut -c 1-16)@gmail.com 106 | source ~/.bashrc 107 | bash ~/.acme.sh/acme.sh --upgrade --auto-upgrade 108 | bash ~/.acme.sh/acme.sh --set-default-ca --server letsencrypt 109 | if [[ -n $(echo $ip | grep ":") ]]; then 110 | bash ~/.acme.sh/acme.sh --issue -d ${domain} --standalone -k ec-256 --listen-v6 --insecure 111 | else 112 | bash ~/.acme.sh/acme.sh --issue -d ${domain} --standalone -k ec-256 --insecure 113 | fi 114 | bash ~/.acme.sh/acme.sh --install-cert -d ${domain} --key-file /root/private.key --fullchain-file /root/cert.crt --ecc 115 | if [[ -f /root/cert.crt && -f /root/private.key ]] && [[ -s /root/cert.crt && -s /root/private.key ]]; then 116 | echo $domain > /root/ca.log 117 | sed -i '/--cron/d' /etc/crontab >/dev/null 2>&1 118 | echo "0 0 * * * root bash /root/.acme.sh/acme.sh --cron -f >/dev/null 2>&1" >> /etc/crontab 119 | green "证书申请成功! 脚本申请到的证书 (cert.crt) 和私钥 (private.key) 文件已保存到 /root 文件夹下" 120 | yellow "证书crt文件路径如下: /root/cert.crt" 121 | yellow "私钥key文件路径如下: /root/private.key" 122 | hy_ym=$domain 123 | fi 124 | else 125 | red "当前域名解析的IP与当前VPS使用的真实IP不匹配" 126 | green "建议如下:" 127 | yellow "1. 请确保CloudFlare小云朵为关闭状态(仅限DNS), 其他域名解析或CDN网站设置同理" 128 | yellow "2. 请检查DNS解析设置的IP是否为VPS的真实IP" 129 | yellow "3. 脚本可能跟不上时代, 建议截图发布到GitHub Issues、GitLab Issues、论坛或TG群询问" 130 | exit 1 131 | fi 132 | fi 133 | elif [[ $certInput == 3 ]]; then 134 | read -p "请输入公钥文件 crt 的路径:" certpath 135 | yellow "公钥文件 crt 的路径:$certpath " 136 | read -p "请输入密钥文件 key 的路径:" keypath 137 | yellow "密钥文件 key 的路径:$keypath " 138 | read -p "请输入证书的域名:" domain 139 | yellow "证书域名:$domain" 140 | hy_ym=$domain 141 | else 142 | green "将使用必应自签证书作为 Hysteria 的节点证书" 143 | 144 | cert_path="/etc/hysteria/cert.crt" 145 | key_path="/etc/hysteria/private.key" 146 | openssl ecparam -genkey -name prime256v1 -out /etc/hysteria/private.key 147 | openssl req -new -x509 -days 36500 -key /etc/hysteria/private.key -out /etc/hysteria/cert.crt -subj "/CN=www.bing.com" 148 | chmod 777 /etc/hysteria/cert.crt 149 | chmod 777 /etc/hysteria/private.key 150 | hy_ym="www.bing.com" 151 | domain="www.bing.com" 152 | fi 153 | } 154 | 155 | inst_pro(){ 156 | green "Hysteria 节点协议如下:" 157 | echo "" 158 | echo -e " ${GREEN}1.${PLAIN} UDP ${YELLOW}(默认)${PLAIN}" 159 | echo -e " ${GREEN}2.${PLAIN} wechat-video" 160 | echo -e " ${GREEN}3.${PLAIN} faketcp" 161 | echo "" 162 | read -rp "请输入选项 [1-3]: " proInput 163 | if [[ $proInput == 2 ]]; then 164 | protocol="wehcat-video" 165 | elif [[ $proInput == 3 ]]; then 166 | protocol="faketcp" 167 | else 168 | protocol="udp" 169 | fi 170 | yellow "将使用 $protocol 作为 Hysteria 的节点协议" 171 | } 172 | 173 | inst_port(){ 174 | iptables -t nat -F PREROUTING >/dev/null 2>&1 175 | 176 | read -p "设置 Hysteria 端口[1-65535](回车则随机分配端口):" port 177 | [[ -z $port ]] && port=$(shuf -i 2000-65535 -n 1) 178 | until [[ -z $(ss -tunlp | grep -w udp | awk '{print $5}' | sed 's/.*://g' | grep -w "$port") ]]; do 179 | if [[ -n $(ss -tunlp | grep -w udp | awk '{print $5}' | sed 's/.*://g' | grep -w "$port") ]]; then 180 | echo -e "${RED} $port ${PLAIN} 端口已经被其他程序占用,请更换端口重试!" 181 | read -p "设置 Hysteria 端口[1-65535](回车则随机分配端口):" port 182 | [[ -z $port ]] && port=$(shuf -i 2000-65535 -n 1) 183 | fi 184 | done 185 | 186 | yellow "将在 Hysteria 节点使用的端口是:$port" 187 | 188 | if [[ $protocol == "udp" ]]; then 189 | inst_jump 190 | fi 191 | } 192 | 193 | inst_jump(){ 194 | yellow "你当前选择的协议是 udp,可支持端口跳跃功能" 195 | green "Hysteria 端口使用模式如下:" 196 | echo "" 197 | echo -e " ${GREEN}1.${PLAIN} 单端口 ${YELLOW}(默认)${PLAIN}" 198 | echo -e " ${GREEN}2.${PLAIN} 端口跳跃" 199 | echo "" 200 | read -rp "请输入选项 [1-2]: " jumpInput 201 | if [[ $jumpInput == 2 ]]; then 202 | read -p "设置范围端口的起始端口 (建议10000-65535之间):" firstport 203 | read -p "设置一个范围端口的末尾端口 (建议10000-65535之间,一定要比上面起始端口大):" endport 204 | if [[ $firstport -ge $endport ]]; then 205 | until [[ $firstport -le $endport ]]; do 206 | if [[ $firstport -ge $endport ]]; then 207 | red "你设置的起始端口小于末尾端口,请重新输入起始和末尾端口" 208 | read -p "设置范围端口的起始端口 (建议10000-65535之间):" firstport 209 | read -p "设置一个范围端口的末尾端口 (建议10000-65535之间,一定要比上面起始端口大):" endport 210 | fi 211 | done 212 | fi 213 | iptables -t nat -A PREROUTING -p udp --dport $firstport:$endport -j DNAT --to-destination :$port 214 | ip6tables -t nat -A PREROUTING -p udp --dport $firstport:$endport -j DNAT --to-destination :$port 215 | netfilter-persistent save >/dev/null 2>&1 216 | else 217 | red "将继续使用单端口模式" 218 | fi 219 | } 220 | 221 | inst_pwd(){ 222 | read -p "设置 Hysteria 密码(回车跳过为随机字符):" auth_pwd 223 | [[ -z $auth_pwd ]] && auth_pwd=$(date +%s%N | md5sum | cut -c 1-8) 224 | yellow "使用在 Hysteria 节点的密码为:$auth_pwd" 225 | } 226 | 227 | inst_resolv(){ 228 | green "Hysteria 域名解析模式如下:" 229 | echo "" 230 | echo -e " ${GREEN}1.${PLAIN} IPv4 优先 ${YELLOW}(默认)${PLAIN}" 231 | echo -e " ${GREEN}2.${PLAIN} IPv6 优先" 232 | echo "" 233 | read -rp "请输入选项 [1-2]: " resolvInput 234 | if [[ $resolvInput == 2 ]]; then 235 | yellow "Hysteria 域名解析模式已设置成 IPv6 优先" 236 | resolv=64 237 | else 238 | yellow "Hysteria 域名解析模式已设置成 IPv4 优先" 239 | resolv=46 240 | fi 241 | } 242 | 243 | inst_hy(){ 244 | if [[ ! $SYSTEM == "CentOS" ]]; then 245 | ${PACKAGE_UPDATE[int]} 246 | fi 247 | ${PACKAGE_INSTALL[int]} curl wget sudo qrencode procps iptables-persistent netfilter-persistent 248 | 249 | wget -N https://raw.githubusercontent.com/Misaka-blog/hysteria-install/main/hy1/install_server.sh 250 | bash install_server.sh 251 | rm -f install_server.sh 252 | 253 | if [[ -f "/usr/local/bin/hysteria" ]]; then 254 | green "Hysteria 安装成功!" 255 | else 256 | red "Hysteria 安装失败!" 257 | fi 258 | 259 | # 询问用户 Hysteria 配置 260 | inst_cert 261 | inst_pro 262 | inst_port 263 | inst_pwd 264 | inst_resolv 265 | 266 | # 设置 Hysteria 配置文件 267 | cat < /etc/hysteria/config.json 268 | { 269 | "protocol": "$protocol", 270 | "listen": ":$port", 271 | "resolve_preference": "$resolv", 272 | "cert": "$cert_path", 273 | "key": "$key_path", 274 | "alpn": "h3", 275 | "auth": { 276 | "mode": "password", 277 | "config": { 278 | "password": "$auth_pwd" 279 | } 280 | } 281 | } 282 | EOF 283 | 284 | # 确定最终入站端口范围 285 | if [[ -n $firstport ]]; then 286 | last_port="$port,$firstport-$endport" 287 | else 288 | last_port=$port 289 | fi 290 | 291 | # 给 IPv6 地址加中括号 292 | if [[ -n $(echo $ip | grep ":") ]]; then 293 | last_ip="[$ip]" 294 | else 295 | last_ip=$ip 296 | fi 297 | 298 | # 判断证书是否为必应自签,如是则使用 IP 作为节点入站 299 | if [[ $hy_ym == "www.bing.com" ]]; then 300 | WARPv4Status=$(curl -s4m8 https://www.cloudflare.com/cdn-cgi/trace -k | grep warp | cut -d= -f2) 301 | WARPv6Status=$(curl -s6m8 https://www.cloudflare.com/cdn-cgi/trace -k | grep warp | cut -d= -f2) 302 | if [[ $WARPv4Status =~ on|plus ]] || [[ $WARPv6Status =~ on|plus ]]; then 303 | wg-quick down wgcf >/dev/null 2>&1 304 | systemctl stop warp-go >/dev/null 2>&1 305 | hy_ym=$last_ip 306 | wg-quick up wgcf >/dev/null 2>&1 307 | systemctl start warp-go >/dev/null 2>&1 308 | else 309 | hy_ym=$last_ip 310 | fi 311 | fi 312 | 313 | # 设置 V2rayN 及 Clash Meta 配置文件 314 | mkdir /root/hy >/dev/null 2>&1 315 | cat < /root/hy/hy-client.json 316 | { 317 | "protocol": "$protocol", 318 | "server": "$hy_ym:$last_port", 319 | "server_name": "$domain", 320 | "alpn": "h3", 321 | "up_mbps": 20, 322 | "down_mbps": 100, 323 | "auth_str": "$auth_pwd", 324 | "insecure": true, 325 | "retry": 3, 326 | "retry_interval": 3, 327 | "fast_open": true, 328 | "lazy_start": true, 329 | "hop_interval": 60, 330 | "socks5": { 331 | "listen": "127.0.0.1:5080" 332 | } 333 | } 334 | EOF 335 | 336 | cat < /root/hy/clash-meta.yaml 337 | mixed-port: 7890 338 | external-controller: 127.0.0.1:9090 339 | allow-lan: false 340 | mode: rule 341 | log-level: debug 342 | ipv6: true 343 | dns: 344 | enable: true 345 | listen: 0.0.0.0:53 346 | enhanced-mode: fake-ip 347 | nameserver: 348 | - 8.8.8.8 349 | - 1.1.1.1 350 | - 114.114.114.114 351 | proxies: 352 | - name: Misaka-Hysteria 353 | type: hysteria 354 | server: $hy_ym 355 | port: $port 356 | auth_str: $auth_pwd 357 | alpn: 358 | - h3 359 | protocol: $protocol 360 | up: 20 361 | down: 100 362 | sni: $domain 363 | skip-cert-verify: true 364 | proxy-groups: 365 | - name: Proxy 366 | type: select 367 | proxies: 368 | - Misaka-Hysteria 369 | 370 | rules: 371 | - GEOIP,CN,DIRECT 372 | - MATCH,Proxy 373 | EOF 374 | url="hysteria://$hy_ym:$port?protocol=$protocol&auth=$auth_pwd&peer=$domain&insecure=$true&upmbps=20&downmbps=100&alpn=h3#Misaka-Hysteria" 375 | echo $url > /root/hy/url.txt 376 | 377 | systemctl daemon-reload 378 | systemctl enable hysteria-server 379 | systemctl start hysteria-server 380 | 381 | if [[ -n $(systemctl status hysteria-server 2>/dev/null | grep -w active) && -f '/etc/hysteria/config.json' ]]; then 382 | green "Hysteria 服务启动成功" 383 | else 384 | red "Hysteria-server 服务启动失败,请运行 systemctl status hysteria-server 查看服务状态并反馈,脚本退出" && exit 1 385 | fi 386 | 387 | green "Hysteria 代理服务安装完成" 388 | yellow "客户端配置文件 hy-client.json 内容如下,并保存到 /root/hy/hy-client.json" 389 | cat /root/hy/hy-client.json 390 | yellow "Clash Meta 客户端配置文件已保存到 /root/hy/clash-meta.yaml" 391 | yellow "Hysteria 节点分享链接如下,并保存到 /root/hy/url.txt" 392 | red $(cat /root/hy/url.txt) 393 | } 394 | 395 | uninst_hy(){ 396 | systemctl stop hysteria-server.service >/dev/null 2>&1 397 | systemctl disable hysteria-server.service >/dev/null 2>&1 398 | rm -f /lib/systemd/system/hysteria-server.service /lib/systemd/system/hysteria-server@.service 399 | rm -rf /usr/local/bin/hysteria /etc/hysteria /root/hy /root/hysteria.sh 400 | iptables -t nat -F PREROUTING >/dev/null 2>&1 401 | netfilter-persistent save >/dev/null 2>&1 402 | green "Hysteria 已彻底卸载完成!" 403 | } 404 | 405 | starthy(){ 406 | systemctl start hysteria-server 407 | systemctl enable hysteria-server >/dev/null 2>&1 408 | } 409 | 410 | stophy(){ 411 | systemctl stop hysteria-server 412 | systemctl disable hysteria-server >/dev/null 2>&1 413 | } 414 | 415 | hyswitch(){ 416 | yellow "请选择你需要的操作:" 417 | echo "" 418 | echo -e " ${GREEN}1.${PLAIN} 启动 Hysteria" 419 | echo -e " ${GREEN}2.${PLAIN} 关闭 Hysteria" 420 | echo -e " ${GREEN}3.${PLAIN} 重启 Hysteria" 421 | echo "" 422 | read -rp "请输入选项 [0-3]: " switchInput 423 | case $switchInput in 424 | 1 ) starthy ;; 425 | 2 ) stophy ;; 426 | 3 ) stophy && starthy ;; 427 | * ) exit 1 ;; 428 | esac 429 | } 430 | 431 | change_cert(){ 432 | old_cert=$(cat /etc/hysteria/config.json | grep cert | awk -F " " '{print $2}' | sed "s/\"//g" | sed "s/,//g") 433 | old_key=$(cat /etc/hysteria/config.json | grep key | awk -F " " '{print $2}' | sed "s/\"//g" | sed "s/,//g") 434 | old_hyym=$(cat /root/hy/hy-client.json | grep server | awk -F " " '{print $2}' | sed "s/\"//g" | sed "s/,//g" | awk -F ":" '{print $1}') 435 | old_domain=$(cat /root/hy/hy-client.json | grep server_name | awk -F " " '{print $2}' | sed "s/\"//g" | sed "s/,//g") 436 | inst_cert 437 | if [[ $hy_ym == "www.bing.com" ]]; then 438 | WARPv4Status=$(curl -s4m8 https://www.cloudflare.com/cdn-cgi/trace -k | grep warp | cut -d= -f2) 439 | WARPv6Status=$(curl -s6m8 https://www.cloudflare.com/cdn-cgi/trace -k | grep warp | cut -d= -f2) 440 | if [[ $WARPv4Status =~ on|plus ]] || [[ $WARPv6Status =~ on|plus ]]; then 441 | wg-quick down wgcf >/dev/null 2>&1 442 | systemctl stop warp-go >/dev/null 2>&1 443 | hy_ym=$(curl -s4m8 ip.gs -k) || hy_ym="[$(curl -s6m8 ip.gs -k)]" 444 | wg-quick up wgcf >/dev/null 2>&1 445 | systemctl start warp-go >/dev/null 2>&1 446 | else 447 | hy_ym=$(curl -s4m8 ip.gs -k) || hy_ym="[$(curl -s6m8 ip.gs -k)]" 448 | fi 449 | fi 450 | sed -i "s!$old_cert!$cert_path!g" /etc/hysteria/config.json 451 | sed -i "s!$old_key!$key_path!g" /etc/hysteria/config.json 452 | sed -i "s/$old_hyym/$hy_ym/g" /root/hy/hy-client.json 453 | sed -i "s/$old_hyym/$hy_ym/g" /root/hy/clash-meta.yaml 454 | sed -i "s/$old_hyym/$hy_ym/g" /root/hy/url.txt 455 | stophy && starthy 456 | green "修改配置成功,请重新导入节点配置文件" 457 | } 458 | 459 | change_pro(){ 460 | old_pro=$(cat /etc/hysteria/config.json | grep protocol | awk -F " " '{print $2}' | sed "s/\"//g" | sed "s/,//g") 461 | inst_pro 462 | sed -i "s/$old_pro/$protocol" /etc/hysteria/config.json 463 | sed -i "s/$old_pro/$protocol" /root/hy/hy-client.json 464 | sed -i "s/$old_pro/$protocol" /root/hy/clash-meta.yaml 465 | sed -i "s/$old_pro/$protocol" /root/hy/url.txt 466 | stophy && starthy 467 | green "修改配置成功,请重新导入节点配置文件" 468 | } 469 | 470 | change_port(){ 471 | old_port=$(cat /etc/hysteria/config.json | grep listen | awk -F " " '{print $2}' | sed "s/\"//g" | sed "s/,//g" | sed "s/://g") 472 | inst_port 473 | 474 | iptables -t nat -F PREROUTING >/dev/null 2>&1 475 | netfilter-persistent save >/dev/null 2>&1 476 | 477 | if [[ -n $firstport ]]; then 478 | last_port="$port,$firstport-$endport" 479 | else 480 | last_port=$port 481 | fi 482 | 483 | sed -i "s/$old_port/$port" /etc/hysteria/config.json 484 | sed -i "s/$old_port/$last_port" /root/hy/hy-client.json 485 | sed -i "s/$old_port/$last_port" /root/hy/clash-meta.yaml 486 | sed -i "s/$old_port/$last_port" /root/hy/url.txt 487 | 488 | stophy && starthy 489 | green "修改配置成功,请重新导入节点配置文件" 490 | } 491 | 492 | change_pwd(){ 493 | old_pwd=$(cat /etc/hysteria/config.json | grep password | sed -n 2p | awk -F " " '{print $2}' | sed "s/\"//g" | sed "s/,//g") 494 | inst_pwd 495 | sed -i "s/$old_pwd/$auth_pwd" /etc/hysteria/config.json 496 | sed -i "s/$old_pwd/$auth_pwd" /root/hy/hy-client.json 497 | sed -i "s/$old_pwd/$auth_pwd" /root/hy/clash-meta.yaml 498 | sed -i "s/$old_pwd/$auth_pwd" /root/hy/url.txt 499 | stophy && starthy 500 | green "修改配置成功,请重新导入节点配置文件" 501 | } 502 | 503 | change_resolv(){ 504 | old_resolv=$(cat /etc/hysteria/config.json | grep resolv | awk -F " " '{print $2}' | sed "s/\"//g" | sed "s/,//g") 505 | inst_resolv 506 | sed -i "s/$old_resolv/$resolv" /etc/hysteria/config.json 507 | stophy && starthy 508 | green "修改配置成功,请重新导入节点配置文件" 509 | } 510 | 511 | editconf(){ 512 | green "Hysteria 配置变更选择如下:" 513 | echo -e " ${GREEN}1.${PLAIN} 修改证书类型" 514 | echo -e " ${GREEN}2.${PLAIN} 修改传输协议" 515 | echo -e " ${GREEN}3.${PLAIN} 修改连接端口" 516 | echo -e " ${GREEN}4.${PLAIN} 修改认证密码" 517 | echo -e " ${GREEN}5.${PLAIN} 修改域名解析优先级" 518 | echo "" 519 | read -p " 请选择操作 [1-5]:" confAnswer 520 | case $confAnswer in 521 | 1 ) change_cert ;; 522 | 2 ) change_pro ;; 523 | 3 ) change_port ;; 524 | 4 ) change_pwd ;; 525 | 5 ) change_resolv ;; 526 | * ) exit 1 ;; 527 | esac 528 | } 529 | 530 | showconf(){ 531 | yellow "客户端配置文件 hy-client.json 内容如下,并保存到 /root/hy/hy-client.json" 532 | cat /root/hy/hy-client.json 533 | yellow "Clash Meta 客户端配置文件已保存到 /root/hy/clash-meta.yaml" 534 | yellow "Hysteria 节点分享链接如下,并保存到 /root/hy/url.txt" 535 | red $(cat /root/hy/url.txt) 536 | } 537 | 538 | menu() { 539 | clear 540 | echo "#############################################################" 541 | echo -e "# ${RED}Hysteria 一键安装脚本${PLAIN} #" 542 | echo -e "# ${GREEN}作者${PLAIN}: MisakaNo の 小破站 #" 543 | echo -e "# ${GREEN}博客${PLAIN}: https://blog.misaka.cyou #" 544 | echo -e "# ${GREEN}GitHub 项目${PLAIN}: https://github.com/Misaka-blog #" 545 | echo -e "# ${GREEN}GitLab 项目${PLAIN}: https://gitlab.com/Misaka-blog #" 546 | echo -e "# ${GREEN}Telegram 频道${PLAIN}: https://t.me/misakanocchannel #" 547 | echo -e "# ${GREEN}Telegram 群组${PLAIN}: https://t.me/misakanoc #" 548 | echo -e "# ${GREEN}YouTube 频道${PLAIN}: https://www.youtube.com/@misaka-blog #" 549 | echo "#############################################################" 550 | echo "" 551 | echo -e " ${GREEN}1.${PLAIN} 安装 Hysteria" 552 | echo -e " ${GREEN}2.${PLAIN} ${RED}卸载 Hysteria${PLAIN}" 553 | echo " -------------" 554 | echo -e " ${GREEN}3.${PLAIN} 关闭、开启、重启 Hysteria" 555 | echo -e " ${GREEN}4.${PLAIN} 修改 Hysteria 配置" 556 | echo -e " ${GREEN}5.${PLAIN} 显示 Hysteria 配置文件" 557 | echo " -------------" 558 | echo -e " ${GREEN}0.${PLAIN} 退出脚本" 559 | echo "" 560 | read -rp "请输入选项 [0-5]: " menuInput 561 | case $menuInput in 562 | 1 ) inst_hy ;; 563 | 2 ) uninst_hy ;; 564 | 3 ) hyswitch ;; 565 | 4 ) editconf ;; 566 | 5 ) showconf ;; 567 | * ) exit 1 ;; 568 | esac 569 | } 570 | 571 | menu 572 | -------------------------------------------------------------------------------- /hy1/install_server.sh: -------------------------------------------------------------------------------- 1 | #!/usr/bin/env bash 2 | # modifed from https://github.com/v2fly/fhs-install-v2ray/blob/master/install-release.sh 3 | # You can set this variable whatever you want in shell session right before running this script by issuing: 4 | # export JSON_PATH='/usr/local/etc/hysteria' 5 | JSON_PATH=${JSON_PATH:-/etc/hysteria} 6 | 7 | curl() { 8 | $(type -P curl) -L -q --retry 5 --retry-delay 10 --retry-max-time 60 "$@" 9 | } 10 | 11 | 12 | ## Demo function for processing parameters 13 | judgment_parameters() { 14 | while [[ "$#" -gt '0' ]]; do 15 | case "$1" in 16 | '--remove') 17 | if [[ "$#" -gt '1' ]]; then 18 | echo 'error: Please enter the correct parameters.' 19 | exit 1 20 | fi 21 | REMOVE='1' 22 | ;; 23 | '--version') 24 | VERSION="${2:?error: Please specify the correct version.}" 25 | break 26 | ;; 27 | '-c' | '--check') 28 | CHECK='1' 29 | break 30 | ;; 31 | '-f' | '--force') 32 | FORCE='1' 33 | break 34 | ;; 35 | '-h' | '--help') 36 | HELP='1' 37 | break 38 | ;; 39 | '-l' | '--local') 40 | LOCAL_INSTALL='1' 41 | LOCAL_FILE="${2:?error: Please specify the correct local file.}" 42 | break 43 | ;; 44 | '-p' | '--proxy') 45 | if [[ -z "${2:?error: Please specify the proxy server address.}" ]]; then 46 | exit 1 47 | fi 48 | PROXY="$2" 49 | shift 50 | ;; 51 | *) 52 | echo "$0: unknown option -- -" 53 | exit 1 54 | ;; 55 | esac 56 | shift 57 | done 58 | } 59 | 60 | install_software() { 61 | package_name="$1" 62 | file_to_detect="$2" 63 | type -P "$file_to_detect" > /dev/null 2>&1 && return 64 | if ${PACKAGE_MANAGEMENT_INSTALL} "$package_name"; then 65 | echo "info: $package_name is installed." 66 | else 67 | echo "error: Installation of $package_name failed, please check your network." 68 | exit 1 69 | fi 70 | } 71 | check_if_running_as_root() { 72 | # If you want to run as another user, please modify $UID to be owned by this user 73 | if [[ "$UID" -ne '0' ]]; then 74 | echo "WARNING: The user currently executing this script is not root. You may encounter the insufficient privilege error." 75 | read -r -p "Are you sure you want to continue? [y/n] " cont_without_been_root 76 | if [[ x"${cont_without_been_root:0:1}" = x'y' ]]; then 77 | echo "Continuing the installation with current user..." 78 | else 79 | echo "Not running with root, exiting..." 80 | exit 1 81 | fi 82 | fi 83 | } 84 | 85 | identify_the_operating_system_and_architecture() { 86 | if [[ "$(uname)" == 'Linux' ]]; then 87 | case "$(uname -m)" in 88 | 'i386' | 'i686') 89 | MACHINE='386' 90 | ;; 91 | 'amd64' | 'x86_64') 92 | MACHINE='amd64' 93 | ;; 94 | 'armv5tel' | 'armv6l' | 'armv7' | 'armv7l') 95 | MACHINE='arm' 96 | ;; 97 | 'armv8' | 'aarch64') 98 | MACHINE='arm64' 99 | ;; 100 | 's390x') 101 | MACHINE='s390x' 102 | ;; 103 | 'mips' | 'mipsle' | 'mips64' | 'mips64le') 104 | MACHINE='mipsle' 105 | ;; 106 | *) 107 | echo "error: The architecture is not supported." 108 | exit 1 109 | ;; 110 | esac 111 | if [[ ! -f '/etc/os-release' ]]; then 112 | echo "error: Don't use outdated Linux distributions." 113 | exit 1 114 | fi 115 | # Do not combine this judgment condition with the following judgment condition. 116 | ## Be aware of Linux distribution like Gentoo, which kernel supports switch between Systemd and OpenRC. 117 | ### Refer: https://github.com/v2fly/fhs-install-v2ray/issues/84#issuecomment-688574989 118 | if [[ -f /.dockerenv ]] || grep -q 'docker\|lxc' /proc/1/cgroup && [[ "$(type -P systemctl)" ]]; then 119 | true 120 | elif [[ -d /run/systemd/system ]] || grep -q systemd <(ls -l /sbin/init); then 121 | true 122 | else 123 | echo "error: Only Linux distributions using systemd are supported." 124 | exit 1 125 | fi 126 | if [[ "$(type -P apt)" ]]; then 127 | PACKAGE_MANAGEMENT_INSTALL='apt -y --no-install-recommends install' 128 | PACKAGE_MANAGEMENT_REMOVE='apt purge' 129 | package_provide_tput='ncurses-bin' 130 | elif [[ "$(type -P dnf)" ]]; then 131 | PACKAGE_MANAGEMENT_INSTALL='dnf -y install' 132 | PACKAGE_MANAGEMENT_REMOVE='dnf remove' 133 | package_provide_tput='ncurses' 134 | elif [[ "$(type -P yum)" ]]; then 135 | PACKAGE_MANAGEMENT_INSTALL='yum -y install' 136 | PACKAGE_MANAGEMENT_REMOVE='yum remove' 137 | package_provide_tput='ncurses' 138 | elif [[ "$(type -P zypper)" ]]; then 139 | PACKAGE_MANAGEMENT_INSTALL='zypper install -y --no-recommends' 140 | PACKAGE_MANAGEMENT_REMOVE='zypper remove' 141 | package_provide_tput='ncurses-utils' 142 | elif [[ "$(type -P pacman)" ]]; then 143 | PACKAGE_MANAGEMENT_INSTALL='pacman -Syu --noconfirm' 144 | PACKAGE_MANAGEMENT_REMOVE='pacman -Rsn' 145 | package_provide_tput='ncurses' 146 | else 147 | echo "error: The script does not support the package manager in this operating system." 148 | exit 1 149 | fi 150 | else 151 | echo "error: This operating system is not supported." 152 | exit 1 153 | fi 154 | } 155 | 156 | get_version() { 157 | # 0: Install or update Hysteria. 158 | # 1: Installed or no new version of Hysteria. 159 | # 2: Install the specified version of Hysteria. 160 | if [[ -n "$VERSION" ]]; then 161 | RELEASE_VERSION="v${VERSION#v}" 162 | return 2 163 | fi 164 | # Determine the version number for Hysteria installed from a local file 165 | if [[ -f '/usr/local/bin/hysteria' ]]; then 166 | VERSION="$(/usr/local/bin/hysteria -v | awk 'NR==1 {print $3}')" 167 | CURRENT_VERSION="v${VERSION#v}" 168 | if [[ "$LOCAL_INSTALL" -eq '1' ]]; then 169 | RELEASE_VERSION="$CURRENT_VERSION" 170 | return 171 | fi 172 | fi 173 | # Get Hysteria release version number 174 | TMP_FILE="$(mktemp)" 175 | # if ! curl -x "${PROXY}" -sS -H "Accept: application/vnd.github.v3+json" -o "$TMP_FILE" 'https://api.github.com/repos/apernet/hysteria/releases/latest'; then 176 | # "rm" "$TMP_FILE" 177 | # echo 'error: Failed to get release list, please check your network.' 178 | # exit 1 179 | # fi 180 | # RELEASE_LATEST="$(curl -Ls "https://data.jsdelivr.com/v1/package/resolve/gh/apernet/Hysteria" | grep '"version":' | sed -E 's/.*"([^"]+)".*/\1/')" 181 | "rm" "$TMP_FILE" 182 | RELEASE_VERSION="v1.3.5" 183 | # Compare Hysteria version numbers 184 | if [[ "$RELEASE_VERSION" != "$CURRENT_VERSION" ]]; then 185 | RELEASE_VERSIONSION_NUMBER="${RELEASE_VERSION#v}" 186 | RELEASE_MAJOR_VERSION_NUMBER="${RELEASE_VERSIONSION_NUMBER%%.*}" 187 | RELEASE_MINOR_VERSION_NUMBER="$(echo "$RELEASE_VERSIONSION_NUMBER" | awk -F '.' '{print $2}')" 188 | RELEASE_MINIMUM_VERSION_NUMBER="${RELEASE_VERSIONSION_NUMBER##*.}" 189 | # shellcheck disable=SC2001 190 | CURRENT_VERSIONSION_NUMBER="$(echo "${CURRENT_VERSION#v}" | sed 's/-.*//')" 191 | CURRENT_MAJOR_VERSION_NUMBER="${CURRENT_VERSIONSION_NUMBER%%.*}" 192 | CURRENT_MINOR_VERSION_NUMBER="$(echo "$CURRENT_VERSIONSION_NUMBER" | awk -F '.' '{print $2}')" 193 | CURRENT_MINIMUM_VERSION_NUMBER="${CURRENT_VERSIONSION_NUMBER##*.}" 194 | if [[ "$RELEASE_MAJOR_VERSION_NUMBER" -gt "$CURRENT_MAJOR_VERSION_NUMBER" ]]; then 195 | return 0 196 | elif [[ "$RELEASE_MAJOR_VERSION_NUMBER" -eq "$CURRENT_MAJOR_VERSION_NUMBER" ]]; then 197 | if [[ "$RELEASE_MINOR_VERSION_NUMBER" -gt "$CURRENT_MINOR_VERSION_NUMBER" ]]; then 198 | return 0 199 | elif [[ "$RELEASE_MINOR_VERSION_NUMBER" -eq "$CURRENT_MINOR_VERSION_NUMBER" ]]; then 200 | if [[ "$RELEASE_MINIMUM_VERSION_NUMBER" -gt "$CURRENT_MINIMUM_VERSION_NUMBER" ]]; then 201 | return 0 202 | else 203 | return 1 204 | fi 205 | else 206 | return 1 207 | fi 208 | else 209 | return 1 210 | fi 211 | elif [[ "$RELEASE_VERSION" == "$CURRENT_VERSION" ]]; then 212 | return 1 213 | fi 214 | } 215 | 216 | download_hysteria() { 217 | DOWNLOAD_LINK="https://github.com/apernet/hysteria/releases/download/$RELEASE_VERSION/hysteria-linux-$MACHINE" 218 | echo "Downloading Hysteria archive: $DOWNLOAD_LINK" 219 | if ! curl -x "${PROXY}" -R -H 'Cache-Control: no-cache' -o "$BIN_FILE" "$DOWNLOAD_LINK"; then 220 | echo 'error: Download failed! Please check your network or try again.' 221 | return 1 222 | fi 223 | } 224 | 225 | install_file() { 226 | NAME="$1" 227 | if [[ "$NAME" == "hysteria-linux-$MACHINE" ]] ; then 228 | install -m 755 "${TMP_DIRECTORY}/$NAME" "/usr/local/bin/hysteria" 229 | fi 230 | } 231 | 232 | install_hysteria() { 233 | # Install hysteria binary to /usr/local/bin/ 234 | install_file hysteria-linux-$MACHINE 235 | 236 | # Install hysteria configuration file to $JSON_PATH 237 | # shellcheck disable=SC2153 238 | if [[ -z "$JSONS_PATH" ]] && [[ ! -d "$JSON_PATH" ]]; then 239 | install -d "$JSON_PATH" 240 | cat << EOF >> "${JSON_PATH}/config.json" 241 | { 242 | "listen": ":36712", 243 | "acme": { 244 | "domains": [ 245 | "your.domain.com" 246 | ], 247 | "email": "hacker@gmail.com" 248 | }, 249 | "obfs": "fuck me till the daylight", 250 | "up_mbps": 100, 251 | "down_mbps": 100 252 | } 253 | EOF 254 | CONFIG_NEW='1' 255 | fi 256 | } 257 | 258 | install_startup_service_file() { 259 | useradd -s /sbin/nologin --create-home hysteria 260 | [ $? -eq 0 ] && echo "User hysteria has been added." 261 | echo "[Unit] 262 | Description=Hysteria, a feature-packed network utility optimized for networks of poor quality 263 | Documentation=https://github.com/apernet/hysteria/wiki 264 | After=network.target 265 | 266 | [Service] 267 | CapabilityBoundingSet=CAP_NET_BIND_SERVICE CAP_NET_RAW 268 | AmbientCapabilities=CAP_NET_BIND_SERVICE CAP_NET_RAW 269 | NoNewPrivileges=true 270 | WorkingDirectory=/etc/hysteria 271 | Environment=HYSTERIA_LOG_LEVEL=info 272 | ExecStart=/usr/local/bin/hysteria -c /etc/hysteria/config.json server 273 | Restart=on-failure 274 | RestartPreventExitStatus=1 275 | RestartSec=5 276 | 277 | [Install] 278 | WantedBy=multi-user.target" > /lib/systemd/system/hysteria-server.service 279 | echo "[Unit] 280 | Description=Hysteria, a feature-packed network utility optimized for networks of poor quality 281 | Documentation=https://github.com/apernet/hysteria/wiki 282 | After=network.target 283 | 284 | [Service] 285 | User=hysteria 286 | CapabilityBoundingSet=CAP_NET_BIND_SERVICE CAP_NET_RAW 287 | AmbientCapabilities=CAP_NET_BIND_SERVICE CAP_NET_RAW 288 | NoNewPrivileges=true 289 | WorkingDirectory=/etc/hysteria 290 | Environment=HYSTERIA_LOG_LEVEL=info 291 | ExecStart=/usr/local/bin/hysteria -c /etc/hysteria/%i.json server 292 | Restart=on-failure 293 | RestartPreventExitStatus=1 294 | RestartSec=5 295 | 296 | [Install] 297 | WantedBy=multi-user.target" > /lib/systemd/system/hysteria-server@.service 298 | echo "info: Systemd service files have been installed successfully!" 299 | systemctl daemon-reload 300 | SYSTEMD='1' 301 | } 302 | 303 | start_hysteria() { 304 | if [[ -f '/lib/systemd/system/hysteria-server.service' ]]; then 305 | if systemctl start "${HYSTERIA_CUSTOMIZE:-hysteria}"; then 306 | echo 'info: Start the Hystaria service.' 307 | else 308 | echo '${red}error: Failed to start Hystaria service.' 309 | exit 1 310 | fi 311 | fi 312 | } 313 | 314 | stop_hysteria() { 315 | HYSTERIA_CUSTOMIZE="$(systemctl list-units | grep 'hysteria@' | awk -F ' ' '{print $1}')" 316 | if [[ -z "$HYSTERIA_CUSTOMIZE" ]]; then 317 | local hysteria_daemon_to_stop='hysteria-server.service' 318 | else 319 | local hysteria_daemon_to_stop="$HYSTERIA_CUSTOMIZE" 320 | fi 321 | if ! systemctl stop "$hysteria_daemon_to_stop"; then 322 | echo 'error: Stopping the Hystaria service failed.' 323 | exit 1 324 | fi 325 | echo 'info: Stop the Hystaria service.' 326 | } 327 | 328 | check_update() { 329 | if [[ -f '/lib/systemd/system/hysteria-server.service' ]]; then 330 | get_version 331 | local get_ver_exit_code=$? 332 | if [[ "$get_ver_exit_code" -eq '0' ]]; then 333 | echo "info: Found the latest release of Hystaria $RELEASE_VERSION . (Current release: $CURRENT_VERSION)" 334 | elif [[ "$get_ver_exit_code" -eq '1' ]]; then 335 | echo "info: No new version. The current version of Hystaria is $CURRENT_VERSION ." 336 | fi 337 | exit 0 338 | else 339 | echo 'error: Hystaria is not installed.' 340 | exit 1 341 | fi 342 | } 343 | 344 | remove_hysteria() { 345 | if systemctl list-unit-files | grep -qw 'hysteria'; then 346 | if [[ -n "$(pidof hysteria)" ]]; then 347 | stop_hysteria 348 | fi 349 | if ! ("rm" -r '/usr/local/bin/hysteria' \ 350 | '/lib/systemd/system/hysteria-server.service' \ 351 | '/lib/systemd/system/hysteria-server@.service'); then 352 | echo 'error: Failed to remove Hysteria.' 353 | exit 1 354 | else 355 | echo 'removed: /usr/local/bin/hysteria' 356 | echo 'removed: /lib/systemd/system/hysteria-server.service' 357 | echo 'removed: /lib/systemd/system/hysteria-server@.service' 358 | echo 'Please execute the command: systemctl disable hysteria' 359 | echo 'info: Hysteria has been removed.' 360 | echo 'info: If necessary, manually delete the configuration and log files.' 361 | exit 0 362 | fi 363 | else 364 | echo 'error: Hysteria is not installed.' 365 | exit 1 366 | fi 367 | } 368 | 369 | # Explanation of parameters in the script 370 | show_help() { 371 | echo "usage: $0 [--remove | --version number | -c | -f | -h | -l | -p]" 372 | echo ' [-p address] [--version number | -c | -f]' 373 | echo ' --remove Remove Hysteria' 374 | echo ' --version Install the specified version of Hysteria, e.g., --version v0.9.6' 375 | echo ' -c, --check Check if Hysteria can be updated' 376 | echo ' -f, --force Force installation of the latest version of Hysteria' 377 | echo ' -h, --help Show help' 378 | echo ' -l, --local Install Hysteria from a local file' 379 | echo ' -p, --proxy Download through a proxy server, e.g., -p http://127.0.0.1:8118 or -p socks5://127.0.0.1:1080' 380 | exit 0 381 | } 382 | 383 | 384 | main() { 385 | check_if_running_as_root 386 | identify_the_operating_system_and_architecture 387 | judgment_parameters "$@" 388 | 389 | install_software "$package_provide_tput" 'tput' 390 | red=$(tput setaf 1) 391 | green=$(tput setaf 2) 392 | aoi=$(tput setaf 6) 393 | reset=$(tput sgr0) 394 | 395 | # Parameter information 396 | [[ "$HELP" -eq '1' ]] && show_help 397 | [[ "$CHECK" -eq '1' ]] && check_update 398 | [[ "$REMOVE" -eq '1' ]] && remove_hysteria 399 | 400 | # Two very important variables 401 | TMP_DIRECTORY="$(mktemp -d)" 402 | BIN_FILE="${TMP_DIRECTORY}/hysteria-linux-$MACHINE" 403 | 404 | # Install Hysteria from a local file, but still need to make sure the network is available 405 | if [[ "$LOCAL_INSTALL" -eq '1' ]]; then 406 | echo 'warn: Install Hysteria from a local file, but still need to make sure the network is available.' 407 | echo -n 'warn: Please make sure the file is valid because we cannot confirm it. (Press any key) ...' 408 | read -r 409 | else 410 | # Normal way 411 | install_software 'curl' 'curl' 412 | get_version 413 | NUMBER="$?" 414 | if [[ "$NUMBER" -eq '0' ]] || [[ "$FORCE" -eq '1' ]] || [[ "$NUMBER" -eq 2 ]]; then 415 | echo "info: Installing Hysteria $RELEASE_VERSION for $(uname -m)" 416 | download_hysteria 417 | if [[ "$?" -eq '1' ]]; then 418 | "rm" -r "$TMP_DIRECTORY" 419 | echo "removed: $TMP_DIRECTORY" 420 | exit 1 421 | fi 422 | elif [[ "$NUMBER" -eq '1' ]]; then 423 | echo "info: No new version. The current version of Hysteria is $CURRENT_VERSION ." 424 | exit 0 425 | fi 426 | fi 427 | 428 | # Determine if Hysteria is running 429 | if systemctl list-unit-files | grep -qw 'hysteria'; then 430 | if [[ -n "$(pidof hysteria)" ]]; then 431 | stop_hysteria 432 | HYSTERIA_RUNNING='1' 433 | fi 434 | fi 435 | install_hysteria 436 | install_startup_service_file 437 | echo 'installed: /usr/local/bin/hysteria' 438 | # If the file exists, the content output of installing or updating geoip.dat and geosite.dat will not be displayed 439 | if [[ "$CONFIG_NEW" -eq '1' ]]; then 440 | echo "installed: ${JSON_PATH}/config.json" 441 | fi 442 | if [[ "$SYSTEMD" -eq '1' ]]; then 443 | echo 'installed: /lib/systemd/system/hysteria-server.service' 444 | echo 'installed: /lib/systemd/system/hysteria-server@.service' 445 | fi 446 | "rm" -r "$TMP_DIRECTORY" 447 | echo "removed: $TMP_DIRECTORY" 448 | if [[ "$LOCAL_INSTALL" -eq '1' ]]; then 449 | get_version 450 | fi 451 | echo "info: Hysteria $RELEASE_VERSION is installed." 452 | if [[ "$HYSTERIA_RUNNING" -eq '1' ]]; then 453 | start_hysteria 454 | else 455 | echo 'Please execute the command: systemctl enable hysteria-server; systemctl start hysteria-server' 456 | fi 457 | } 458 | 459 | main "$@" -------------------------------------------------------------------------------- /hy2/hysteria.sh: -------------------------------------------------------------------------------- 1 | #!/bin/bash 2 | 3 | export LANG=en_US.UTF-8 4 | 5 | RED="\033[31m" 6 | GREEN="\033[32m" 7 | YELLOW="\033[33m" 8 | PLAIN="\033[0m" 9 | 10 | red(){ 11 | echo -e "\033[31m\033[01m$1\033[0m" 12 | } 13 | 14 | green(){ 15 | echo -e "\033[32m\033[01m$1\033[0m" 16 | } 17 | 18 | yellow(){ 19 | echo -e "\033[33m\033[01m$1\033[0m" 20 | } 21 | 22 | # 判断系统及定义系统安装依赖方式 23 | REGEX=("debian" "ubuntu" "centos|red hat|kernel|oracle linux|alma|rocky" "'amazon linux'" "fedora") 24 | RELEASE=("Debian" "Ubuntu" "CentOS" "CentOS" "Fedora") 25 | PACKAGE_UPDATE=("apt-get update" "apt-get update" "yum -y update" "yum -y update" "yum -y update") 26 | PACKAGE_INSTALL=("apt -y install" "apt -y install" "yum -y install" "yum -y install" "yum -y install") 27 | PACKAGE_REMOVE=("apt -y remove" "apt -y remove" "yum -y remove" "yum -y remove" "yum -y remove") 28 | PACKAGE_UNINSTALL=("apt -y autoremove" "apt -y autoremove" "yum -y autoremove" "yum -y autoremove" "yum -y autoremove") 29 | 30 | [[ $EUID -ne 0 ]] && red "注意: 请在root用户下运行脚本" && exit 1 31 | 32 | CMD=("$(grep -i pretty_name /etc/os-release 2>/dev/null | cut -d \" -f2)" "$(hostnamectl 2>/dev/null | grep -i system | cut -d : -f2)" "$(lsb_release -sd 2>/dev/null)" "$(grep -i description /etc/lsb-release 2>/dev/null | cut -d \" -f2)" "$(grep . /etc/redhat-release 2>/dev/null)" "$(grep . /etc/issue 2>/dev/null | cut -d \\ -f1 | sed '/^[ ]*$/d')") 33 | 34 | for i in "${CMD[@]}"; do 35 | SYS="$i" && [[ -n $SYS ]] && break 36 | done 37 | 38 | for ((int = 0; int < ${#REGEX[@]}; int++)); do 39 | [[ $(echo "$SYS" | tr '[:upper:]' '[:lower:]') =~ ${REGEX[int]} ]] && SYSTEM="${RELEASE[int]}" && [[ -n $SYSTEM ]] && break 40 | done 41 | 42 | [[ -z $SYSTEM ]] && red "目前暂不支持你的VPS的操作系统!" && exit 1 43 | 44 | if [[ -z $(type -P curl) ]]; then 45 | if [[ ! $SYSTEM == "CentOS" ]]; then 46 | ${PACKAGE_UPDATE[int]} 47 | fi 48 | ${PACKAGE_INSTALL[int]} curl 49 | fi 50 | 51 | realip(){ 52 | ip=$(curl -s4m8 ip.gs -k) || ip=$(curl -s6m8 ip.gs -k) 53 | } 54 | 55 | inst_cert(){ 56 | green "Hysteria 2 协议证书申请方式如下:" 57 | echo "" 58 | echo -e " ${GREEN}1.${PLAIN} 必应自签证书 ${YELLOW}(默认)${PLAIN}" 59 | echo -e " ${GREEN}2.${PLAIN} Acme 脚本自动申请" 60 | echo -e " ${GREEN}3.${PLAIN} 自定义证书路径" 61 | echo "" 62 | read -rp "请输入选项 [1-3]: " certInput 63 | if [[ $certInput == 2 ]]; then 64 | cert_path="/root/cert.crt" 65 | key_path="/root/private.key" 66 | 67 | chmod -R 777 /root 68 | 69 | chmod +rw /root/cert.crt 70 | chmod +rw /root/private.key 71 | 72 | if [[ -f /root/cert.crt && -f /root/private.key ]] && [[ -s /root/cert.crt && -s /root/private.key ]] && [[ -f /root/ca.log ]]; then 73 | domain=$(cat /root/ca.log) 74 | green "检测到原有域名:$domain 的证书,正在应用" 75 | hy_domain=$domain 76 | else 77 | WARPv4Status=$(curl -s4m8 https://www.cloudflare.com/cdn-cgi/trace -k | grep warp | cut -d= -f2) 78 | WARPv6Status=$(curl -s6m8 https://www.cloudflare.com/cdn-cgi/trace -k | grep warp | cut -d= -f2) 79 | if [[ $WARPv4Status =~ on|plus ]] || [[ $WARPv6Status =~ on|plus ]]; then 80 | wg-quick down wgcf >/dev/null 2>&1 81 | systemctl stop warp-go >/dev/null 2>&1 82 | realip 83 | wg-quick up wgcf >/dev/null 2>&1 84 | systemctl start warp-go >/dev/null 2>&1 85 | else 86 | realip 87 | fi 88 | 89 | read -p "请输入需要申请证书的域名:" domain 90 | [[ -z $domain ]] && red "未输入域名,无法执行操作!" && exit 1 91 | green "已输入的域名:$domain" && sleep 1 92 | domainIP=$(dig @8.8.8.8 +time=2 +short "$domain" 2>/dev/null) 93 | if echo $domainIP | grep -q "network unreachable\|timed out" || [[ -z $domainIP ]]; then 94 | domainIP=$(dig @2001:4860:4860::8888 +time=2 aaaa +short "$domain" 2>/dev/null) 95 | fi 96 | if echo $domainIP | grep -q "network unreachable\|timed out" || [[ -z $domainIP ]] ; then 97 | red "未解析出 IP,请检查域名是否输入有误" 98 | yellow "是否尝试强行匹配?" 99 | green "1. 是,将使用强行匹配" 100 | green "2. 否,退出脚本" 101 | read -p "请输入选项 [1-2]:" ipChoice 102 | if [[ $ipChoice == 1 ]]; then 103 | yellow "将尝试强行匹配以申请域名证书" 104 | else 105 | red "将退出脚本" 106 | exit 1 107 | fi 108 | fi 109 | if [[ $domainIP == $ip ]]; then 110 | ${PACKAGE_INSTALL[int]} curl wget sudo socat openssl 111 | if [[ $SYSTEM == "CentOS" ]]; then 112 | ${PACKAGE_INSTALL[int]} cronie 113 | systemctl start crond 114 | systemctl enable crond 115 | else 116 | ${PACKAGE_INSTALL[int]} cron 117 | systemctl start cron 118 | systemctl enable cron 119 | fi 120 | curl https://get.acme.sh | sh -s email=$(date +%s%N | md5sum | cut -c 1-16)@gmail.com 121 | source ~/.bashrc 122 | bash ~/.acme.sh/acme.sh --upgrade --auto-upgrade 123 | bash ~/.acme.sh/acme.sh --set-default-ca --server letsencrypt 124 | if [[ -n $(echo $ip | grep ":") ]]; then 125 | bash ~/.acme.sh/acme.sh --issue -d ${domain} --standalone -k ec-256 --listen-v6 --insecure 126 | else 127 | bash ~/.acme.sh/acme.sh --issue -d ${domain} --standalone -k ec-256 --insecure 128 | fi 129 | bash ~/.acme.sh/acme.sh --install-cert -d ${domain} --key-file /root/private.key --fullchain-file /root/cert.crt --ecc 130 | if [[ -f /root/cert.crt && -f /root/private.key ]] && [[ -s /root/cert.crt && -s /root/private.key ]]; then 131 | echo $domain > /root/ca.log 132 | sed -i '/--cron/d' /etc/crontab >/dev/null 2>&1 133 | echo "0 0 * * * root bash /root/.acme.sh/acme.sh --cron -f >/dev/null 2>&1" >> /etc/crontab 134 | green "证书申请成功! 脚本申请到的证书 (cert.crt) 和私钥 (private.key) 文件已保存到 /root 文件夹下" 135 | yellow "证书crt文件路径如下: /root/cert.crt" 136 | yellow "私钥key文件路径如下: /root/private.key" 137 | hy_domain=$domain 138 | fi 139 | else 140 | red "当前域名解析的IP与当前VPS使用的真实IP不匹配" 141 | green "建议如下:" 142 | yellow "1. 请确保CloudFlare小云朵为关闭状态(仅限DNS), 其他域名解析或CDN网站设置同理" 143 | yellow "2. 请检查DNS解析设置的IP是否为VPS的真实IP" 144 | yellow "3. 脚本可能跟不上时代, 建议截图发布到GitHub Issues、GitLab Issues、论坛或TG群询问" 145 | exit 1 146 | fi 147 | fi 148 | elif [[ $certInput == 3 ]]; then 149 | read -p "请输入公钥文件 crt 的路径:" cert_path 150 | yellow "公钥文件 crt 的路径:$cert_path " 151 | read -p "请输入密钥文件 key 的路径:" key_path 152 | yellow "密钥文件 key 的路径:$key_path " 153 | read -p "请输入证书的域名:" domain 154 | yellow "证书域名:$domain" 155 | hy_domain=$domain 156 | 157 | chmod +rw $cert_path 158 | chmod +rw $key_path 159 | else 160 | green "将使用必应自签证书作为 Hysteria 2 的节点证书" 161 | 162 | cert_path="/etc/hysteria/cert.crt" 163 | key_path="/etc/hysteria/private.key" 164 | openssl ecparam -genkey -name prime256v1 -out /etc/hysteria/private.key 165 | openssl req -new -x509 -days 36500 -key /etc/hysteria/private.key -out /etc/hysteria/cert.crt -subj "/CN=www.bing.com" 166 | chmod 777 /etc/hysteria/cert.crt 167 | chmod 777 /etc/hysteria/private.key 168 | hy_domain="www.bing.com" 169 | domain="www.bing.com" 170 | fi 171 | } 172 | 173 | inst_port(){ 174 | iptables -t nat -F PREROUTING >/dev/null 2>&1 175 | 176 | read -p "设置 Hysteria 2 端口 [1-65535](回车则随机分配端口):" port 177 | [[ -z $port ]] && port=$(shuf -i 2000-65535 -n 1) 178 | until [[ -z $(ss -tunlp | grep -w udp | awk '{print $5}' | sed 's/.*://g' | grep -w "$port") ]]; do 179 | if [[ -n $(ss -tunlp | grep -w udp | awk '{print $5}' | sed 's/.*://g' | grep -w "$port") ]]; then 180 | echo -e "${RED} $port ${PLAIN} 端口已经被其他程序占用,请更换端口重试!" 181 | read -p "设置 Hysteria 2 端口 [1-65535](回车则随机分配端口):" port 182 | [[ -z $port ]] && port=$(shuf -i 2000-65535 -n 1) 183 | fi 184 | done 185 | 186 | yellow "将在 Hysteria 2 节点使用的端口是:$port" 187 | inst_jump 188 | } 189 | 190 | inst_jump(){ 191 | green "Hysteria 2 端口使用模式如下:" 192 | echo "" 193 | echo -e " ${GREEN}1.${PLAIN} 单端口 ${YELLOW}(默认)${PLAIN}" 194 | echo -e " ${GREEN}2.${PLAIN} 端口跳跃" 195 | echo "" 196 | read -rp "请输入选项 [1-2]: " jumpInput 197 | if [[ $jumpInput == 2 ]]; then 198 | read -p "设置范围端口的起始端口 (建议10000-65535之间):" firstport 199 | read -p "设置一个范围端口的末尾端口 (建议10000-65535之间,一定要比上面起始端口大):" endport 200 | if [[ $firstport -ge $endport ]]; then 201 | until [[ $firstport -le $endport ]]; do 202 | if [[ $firstport -ge $endport ]]; then 203 | red "你设置的起始端口小于末尾端口,请重新输入起始和末尾端口" 204 | read -p "设置范围端口的起始端口 (建议10000-65535之间):" firstport 205 | read -p "设置一个范围端口的末尾端口 (建议10000-65535之间,一定要比上面起始端口大):" endport 206 | fi 207 | done 208 | fi 209 | iptables -t nat -A PREROUTING -p udp --dport $firstport:$endport -j DNAT --to-destination :$port 210 | ip6tables -t nat -A PREROUTING -p udp --dport $firstport:$endport -j DNAT --to-destination :$port 211 | netfilter-persistent save >/dev/null 2>&1 212 | else 213 | red "将继续使用单端口模式" 214 | fi 215 | } 216 | 217 | inst_pwd(){ 218 | read -p "设置 Hysteria 2 密码(回车跳过为随机字符):" auth_pwd 219 | [[ -z $auth_pwd ]] && auth_pwd=$(date +%s%N | md5sum | cut -c 1-8) 220 | yellow "使用在 Hysteria 2 节点的密码为:$auth_pwd" 221 | } 222 | 223 | inst_site(){ 224 | read -rp "请输入 Hysteria 2 的伪装网站地址 (去除https://) [回车世嘉maimai日本网站]:" proxysite 225 | [[ -z $proxysite ]] && proxysite="maimai.sega.jp" 226 | yellow "使用在 Hysteria 2 节点的伪装网站为:$proxysite" 227 | } 228 | 229 | insthysteria(){ 230 | warpv6=$(curl -s6m8 https://www.cloudflare.com/cdn-cgi/trace -k | grep warp | cut -d= -f2) 231 | warpv4=$(curl -s4m8 https://www.cloudflare.com/cdn-cgi/trace -k | grep warp | cut -d= -f2) 232 | if [[ $warpv4 =~ on|plus || $warpv6 =~ on|plus ]]; then 233 | wg-quick down wgcf >/dev/null 2>&1 234 | systemctl stop warp-go >/dev/null 2>&1 235 | realip 236 | systemctl start warp-go >/dev/null 2>&1 237 | wg-quick up wgcf >/dev/null 2>&1 238 | else 239 | realip 240 | fi 241 | 242 | if [[ ! ${SYSTEM} == "CentOS" ]]; then 243 | ${PACKAGE_UPDATE} 244 | fi 245 | ${PACKAGE_INSTALL} curl wget sudo qrencode procps iptables-persistent netfilter-persistent 246 | 247 | wget -N https://raw.githubusercontent.com/Misaka-blog/hysteria-install/main/hy2/install_server.sh 248 | bash install_server.sh 249 | rm -f install_server.sh 250 | 251 | if [[ -f "/usr/local/bin/hysteria" ]]; then 252 | green "Hysteria 2 安装成功!" 253 | else 254 | red "Hysteria 2 安装失败!" 255 | exit 1 256 | fi 257 | 258 | # 询问用户 Hysteria 配置 259 | inst_cert 260 | inst_port 261 | inst_pwd 262 | inst_site 263 | 264 | # 设置 Hysteria 配置文件 265 | cat << EOF > /etc/hysteria/config.yaml 266 | listen: :$port 267 | 268 | tls: 269 | cert: $cert_path 270 | key: $key_path 271 | 272 | quic: 273 | initStreamReceiveWindow: 16777216 274 | maxStreamReceiveWindow: 16777216 275 | initConnReceiveWindow: 33554432 276 | maxConnReceiveWindow: 33554432 277 | 278 | auth: 279 | type: password 280 | password: $auth_pwd 281 | 282 | masquerade: 283 | type: proxy 284 | proxy: 285 | url: https://$proxysite 286 | rewriteHost: true 287 | EOF 288 | 289 | # 确定最终入站端口范围 290 | if [[ -n $firstport ]]; then 291 | last_port="$port,$firstport-$endport" 292 | else 293 | last_port=$port 294 | fi 295 | 296 | # 给 IPv6 地址加中括号 297 | if [[ -n $(echo $ip | grep ":") ]]; then 298 | last_ip="[$ip]" 299 | else 300 | last_ip=$ip 301 | fi 302 | 303 | mkdir /root/hy 304 | cat << EOF > /root/hy/hy-client.yaml 305 | server: $last_ip:$last_port 306 | 307 | auth: $auth_pwd 308 | 309 | tls: 310 | sni: $hy_domain 311 | insecure: true 312 | 313 | quic: 314 | initStreamReceiveWindow: 16777216 315 | maxStreamReceiveWindow: 16777216 316 | initConnReceiveWindow: 33554432 317 | maxConnReceiveWindow: 33554432 318 | 319 | fastOpen: true 320 | 321 | socks5: 322 | listen: 127.0.0.1:5080 323 | 324 | transport: 325 | udp: 326 | hopInterval: 30s 327 | EOF 328 | cat << EOF > /root/hy/hy-client.json 329 | { 330 | "server": "$last_ip:$last_port", 331 | "auth": "$auth_pwd", 332 | "tls": { 333 | "sni": "$hy_domain", 334 | "insecure": true 335 | }, 336 | "quic": { 337 | "initStreamReceiveWindow": 16777216, 338 | "maxStreamReceiveWindow": 16777216, 339 | "initConnReceiveWindow": 33554432, 340 | "maxConnReceiveWindow": 33554432 341 | }, 342 | "fastOpen": true, 343 | "socks5": { 344 | "listen": "127.0.0.1:5080" 345 | }, 346 | "transport": { 347 | "udp": { 348 | "hopInterval": "30s" 349 | } 350 | } 351 | } 352 | EOF 353 | cat < /root/hy/clash-meta.yaml 354 | mixed-port: 7890 355 | external-controller: 127.0.0.1:9090 356 | allow-lan: false 357 | mode: rule 358 | log-level: debug 359 | ipv6: true 360 | dns: 361 | enable: true 362 | listen: 0.0.0.0:53 363 | enhanced-mode: fake-ip 364 | nameserver: 365 | - 8.8.8.8 366 | - 1.1.1.1 367 | - 114.114.114.114 368 | proxies: 369 | - name: Misaka-Hysteria2 370 | type: hysteria2 371 | server: $last_ip 372 | port: $port 373 | password: $auth_pwd 374 | sni: $hy_domain 375 | skip-cert-verify: true 376 | proxy-groups: 377 | - name: Proxy 378 | type: select 379 | proxies: 380 | - Misaka-Hysteria2 381 | 382 | rules: 383 | - GEOIP,CN,DIRECT 384 | - MATCH,Proxy 385 | EOF 386 | url="hysteria2://$auth_pwd@$last_ip:$last_port/?insecure=1&sni=$hy_domain#Misaka-Hysteria2" 387 | echo $url > /root/hy/url.txt 388 | nohopurl="hysteria2://$auth_pwd@$last_ip:$port/?insecure=1&sni=$hy_domain#Misaka-Hysteria2" 389 | echo $nohopurl > /root/hy/url-nohop.txt 390 | 391 | systemctl daemon-reload 392 | systemctl enable hysteria-server 393 | systemctl start hysteria-server 394 | if [[ -n $(systemctl status hysteria-server 2>/dev/null | grep -w active) && -f '/etc/hysteria/config.yaml' ]]; then 395 | green "Hysteria 2 服务启动成功" 396 | else 397 | red "Hysteria 2 服务启动失败,请运行 systemctl status hysteria-server 查看服务状态并反馈,脚本退出" && exit 1 398 | fi 399 | red "======================================================================================" 400 | green "Hysteria 2 代理服务安装完成" 401 | yellow "Hysteria 2 客户端 YAML 配置文件 hy-client.yaml 内容如下,并保存到 /root/hy/hy-client.yaml" 402 | red "$(cat /root/hy/hy-client.yaml)" 403 | yellow "Hysteria 2 客户端 JSON 配置文件 hy-client.json 内容如下,并保存到 /root/hy/hy-client.json" 404 | red "$(cat /root/hy/hy-client.json)" 405 | yellow "Clash Meta 客户端配置文件已保存到 /root/hy/clash-meta.yaml" 406 | yellow "Hysteria 2 节点分享链接如下,并保存到 /root/hy/url.txt" 407 | red "$(cat /root/hy/url.txt)" 408 | yellow "Hysteria 2 节点单端口的分享链接如下,并保存到 /root/hy/url.txt" 409 | red "$(cat /root/hy/url-nohop.txt)" 410 | } 411 | 412 | unsthysteria(){ 413 | systemctl stop hysteria-server.service >/dev/null 2>&1 414 | systemctl disable hysteria-server.service >/dev/null 2>&1 415 | rm -f /lib/systemd/system/hysteria-server.service /lib/systemd/system/hysteria-server@.service 416 | rm -rf /usr/local/bin/hysteria /etc/hysteria /root/hy /root/hysteria.sh 417 | iptables -t nat -F PREROUTING >/dev/null 2>&1 418 | netfilter-persistent save >/dev/null 2>&1 419 | 420 | green "Hysteria 2 已彻底卸载完成!" 421 | } 422 | 423 | starthysteria(){ 424 | systemctl start hysteria-server 425 | systemctl enable hysteria-server >/dev/null 2>&1 426 | } 427 | 428 | stophysteria(){ 429 | systemctl stop hysteria-server 430 | systemctl disable hysteria-server >/dev/null 2>&1 431 | } 432 | 433 | hysteriaswitch(){ 434 | yellow "请选择你需要的操作:" 435 | echo "" 436 | echo -e " ${GREEN}1.${PLAIN} 启动 Hysteria 2" 437 | echo -e " ${GREEN}2.${PLAIN} 关闭 Hysteria 2" 438 | echo -e " ${GREEN}3.${PLAIN} 重启 Hysteria 2" 439 | echo "" 440 | read -rp "请输入选项 [0-3]: " switchInput 441 | case $switchInput in 442 | 1 ) starthysteria ;; 443 | 2 ) stophysteria ;; 444 | 3 ) stophysteria && starthysteria ;; 445 | * ) exit 1 ;; 446 | esac 447 | } 448 | 449 | changeport(){ 450 | oldport=$(cat /etc/hysteria/config.yaml 2>/dev/null | sed -n 1p | awk '{print $2}' | awk -F ":" '{print $2}') 451 | 452 | read -p "设置 Hysteria 2 端口[1-65535](回车则随机分配端口):" port 453 | [[ -z $port ]] && port=$(shuf -i 2000-65535 -n 1) 454 | 455 | until [[ -z $(ss -tunlp | grep -w udp | awk '{print $5}' | sed 's/.*://g' | grep -w "$port") ]]; do 456 | if [[ -n $(ss -tunlp | grep -w udp | awk '{print $5}' | sed 's/.*://g' | grep -w "$port") ]]; then 457 | echo -e "${RED} $port ${PLAIN} 端口已经被其他程序占用,请更换端口重试!" 458 | read -p "设置 Hysteria 2 端口 [1-65535](回车则随机分配端口):" port 459 | [[ -z $port ]] && port=$(shuf -i 2000-65535 -n 1) 460 | fi 461 | done 462 | 463 | sed -i "1s#$oldport#$port#g" /etc/hysteria/config.yaml 464 | sed -i "1s#$oldport#$port#g" /root/hy/hy-client.yaml 465 | sed -i "2s#$oldport#$port#g" /root/hy/hy-client.json 466 | 467 | stophysteria && starthysteria 468 | 469 | green "Hysteria 2 端口已成功修改为:$port" 470 | yellow "请手动更新客户端配置文件以使用节点" 471 | showconf 472 | } 473 | 474 | changepasswd(){ 475 | oldpasswd=$(cat /etc/hysteria/config.yaml 2>/dev/null | sed -n 15p | awk '{print $2}') 476 | 477 | read -p "设置 Hysteria 2 密码(回车跳过为随机字符):" passwd 478 | [[ -z $passwd ]] && passwd=$(date +%s%N | md5sum | cut -c 1-8) 479 | 480 | sed -i "1s#$oldpasswd#$passwd#g" /etc/hysteria/config.yaml 481 | sed -i "1s#$oldpasswd#$passwd#g" /root/hy/hy-client.yaml 482 | sed -i "3s#$oldpasswd#$passwd#g" /root/hy/hy-client.json 483 | 484 | stophysteria && starthysteria 485 | 486 | green "Hysteria 2 节点密码已成功修改为:$passwd" 487 | yellow "请手动更新客户端配置文件以使用节点" 488 | showconf 489 | } 490 | 491 | change_cert(){ 492 | old_cert=$(cat /etc/hysteria/config.yaml | grep cert | awk -F " " '{print $2}') 493 | old_key=$(cat /etc/hysteria/config.yaml | grep key | awk -F " " '{print $2}') 494 | old_hydomain=$(cat /root/hy/hy-client.yaml | grep sni | awk '{print $2}') 495 | 496 | inst_cert 497 | 498 | sed -i "s!$old_cert!$cert_path!g" /etc/hysteria/config.yaml 499 | sed -i "s!$old_key!$key_path!g" /etc/hysteria/config.yaml 500 | sed -i "6s/$old_hydomain/$hy_domain/g" /root/hy/hy-client.yaml 501 | sed -i "5s/$old_hydomain/$hy_domain/g" /root/hy/hy-client.json 502 | 503 | stophysteria && starthysteria 504 | 505 | green "Hysteria 2 节点证书类型已成功修改" 506 | yellow "请手动更新客户端配置文件以使用节点" 507 | showconf 508 | } 509 | 510 | changeproxysite(){ 511 | oldproxysite=$(cat /etc/hysteria/config.yaml | grep url | awk -F " " '{print $2}' | awk -F "https://" '{print $2}') 512 | 513 | inst_site 514 | 515 | sed -i "s#$oldproxysite#$proxysite#g" /etc/caddy/Caddyfile 516 | 517 | stophysteria && starthysteria 518 | 519 | green "Hysteria 2 节点伪装网站已成功修改为:$proxysite" 520 | } 521 | 522 | changeconf(){ 523 | green "Hysteria 2 配置变更选择如下:" 524 | echo -e " ${GREEN}1.${PLAIN} 修改端口" 525 | echo -e " ${GREEN}2.${PLAIN} 修改密码" 526 | echo -e " ${GREEN}3.${PLAIN} 修改证书类型" 527 | echo -e " ${GREEN}4.${PLAIN} 修改伪装网站" 528 | echo "" 529 | read -p " 请选择操作 [1-4]:" confAnswer 530 | case $confAnswer in 531 | 1 ) changeport ;; 532 | 2 ) changepasswd ;; 533 | 3 ) change_cert ;; 534 | 4 ) changeproxysite ;; 535 | * ) exit 1 ;; 536 | esac 537 | } 538 | 539 | showconf(){ 540 | yellow "Hysteria 2 客户端 YAML 配置文件 hy-client.yaml 内容如下,并保存到 /root/hy/hy-client.yaml" 541 | red "$(cat /root/hy/hy-client.yaml)" 542 | yellow "Hysteria 2 客户端 JSON 配置文件 hy-client.json 内容如下,并保存到 /root/hy/hy-client.json" 543 | red "$(cat /root/hy/hy-client.json)" 544 | yellow "Clash Meta 客户端配置文件已保存到 /root/hy/clash-meta.yaml" 545 | yellow "Hysteria 2 节点分享链接如下,并保存到 /root/hy/url.txt" 546 | red "$(cat /root/hy/url.txt)" 547 | yellow "Hysteria 2 节点单端口的分享链接如下,并保存到 /root/hy/url.txt" 548 | red "$(cat /root/hy/url-nohop.txt)" 549 | } 550 | 551 | update_core(){ 552 | wget -N https://raw.githubusercontent.com/Misaka-blog/hysteria-install/main/hy2/install_server.sh 553 | bash install_server.sh 554 | 555 | rm -f install_server.sh 556 | } 557 | 558 | menu() { 559 | clear 560 | echo "#############################################################" 561 | echo -e "# ${RED}Hysteria 2 一键安装脚本${PLAIN} #" 562 | echo -e "# ${GREEN}作者${PLAIN}: MisakaNo の 小破站 #" 563 | echo -e "# ${GREEN}博客${PLAIN}: https://blog.misaka.cyou #" 564 | echo -e "# ${GREEN}GitHub 项目${PLAIN}: https://github.com/Misaka-blog #" 565 | echo -e "# ${GREEN}GitLab 项目${PLAIN}: https://gitlab.com/Misaka-blog #" 566 | echo -e "# ${GREEN}Telegram 频道${PLAIN}: https://t.me/misakanocchannel #" 567 | echo -e "# ${GREEN}Telegram 群组${PLAIN}: https://t.me/misakanoc #" 568 | echo -e "# ${GREEN}YouTube 频道${PLAIN}: https://www.youtube.com/@misaka-blog #" 569 | echo "#############################################################" 570 | echo "" 571 | echo -e " ${GREEN}1.${PLAIN} 安装 Hysteria 2" 572 | echo -e " ${GREEN}2.${PLAIN} ${RED}卸载 Hysteria 2${PLAIN}" 573 | echo " -------------" 574 | echo -e " ${GREEN}3.${PLAIN} 关闭、开启、重启 Hysteria 2" 575 | echo -e " ${GREEN}4.${PLAIN} 修改 Hysteria 2 配置" 576 | echo -e " ${GREEN}5.${PLAIN} 显示 Hysteria 2 配置文件" 577 | echo " -------------" 578 | echo -e " ${GREEN}6.${PLAIN} 更新 Hysteria 2 内核" 579 | echo " -------------" 580 | echo -e " ${GREEN}0.${PLAIN} 退出脚本" 581 | echo "" 582 | read -rp "请输入选项 [0-5]: " menuInput 583 | case $menuInput in 584 | 1 ) insthysteria ;; 585 | 2 ) unsthysteria ;; 586 | 3 ) hysteriaswitch ;; 587 | 4 ) changeconf ;; 588 | 5 ) showconf ;; 589 | 6 ) update_core ;; 590 | * ) exit 1 ;; 591 | esac 592 | } 593 | 594 | menu 595 | -------------------------------------------------------------------------------- /hy2/install_server.sh: -------------------------------------------------------------------------------- 1 | #!/usr/bin/env bash 2 | # 3 | # install_server.sh - hysteria server install script 4 | # Try `install_server.sh --help` for usage. 5 | # 6 | # SPDX-License-Identifier: MIT 7 | # Copyright (c) 2023 Aperture Internet Laboratory 8 | # 9 | 10 | set -e 11 | 12 | 13 | ### 14 | # SCRIPT CONFIGURATION 15 | ### 16 | 17 | # Basename of this script 18 | SCRIPT_NAME="$(basename "$0")" 19 | 20 | # Command line arguments of this script 21 | SCRIPT_ARGS=("$@") 22 | 23 | # Path for installing executable 24 | EXECUTABLE_INSTALL_PATH="/usr/local/bin/hysteria" 25 | 26 | # Paths to install systemd files 27 | SYSTEMD_SERVICES_DIR="/etc/systemd/system" 28 | 29 | # Directory to store hysteria config file 30 | CONFIG_DIR="/etc/hysteria" 31 | 32 | # URLs of GitHub 33 | REPO_URL="https://github.com/apernet/hysteria" 34 | API_BASE_URL="https://api.github.com/repos/apernet/hysteria" 35 | 36 | # curl command line flags. 37 | # To using a proxy, please specify ALL_PROXY in the environ variable, such like: 38 | # export ALL_PROXY=socks5h://192.0.2.1:1080 39 | CURL_FLAGS=(-L -f -q --retry 5 --retry-delay 10 --retry-max-time 60) 40 | 41 | 42 | ### 43 | # AUTO DETECTED GLOBAL VARIABLE 44 | ### 45 | 46 | # Package manager 47 | PACKAGE_MANAGEMENT_INSTALL="${PACKAGE_MANAGEMENT_INSTALL:-}" 48 | 49 | # Operating System of current machine, supported: linux 50 | OPERATING_SYSTEM="${OPERATING_SYSTEM:-}" 51 | 52 | # Architecture of current machine, supported: 386, amd64, arm, arm64, mipsle, s390x 53 | ARCHITECTURE="${ARCHITECTURE:-}" 54 | 55 | # User for running hysteria 56 | HYSTERIA_USER="${HYSTERIA_USER:-}" 57 | 58 | # Directory for ACME certificates storage 59 | HYSTERIA_HOME_DIR="${HYSTERIA_HOME_DIR:-}" 60 | 61 | 62 | ### 63 | # ARGUMENTS 64 | ### 65 | 66 | # Supported operation: install, remove, check_update 67 | OPERATION= 68 | 69 | # User specified version to install 70 | VERSION= 71 | 72 | # Force install even if installed 73 | FORCE= 74 | 75 | # User specified binary to install 76 | LOCAL_FILE= 77 | 78 | 79 | ### 80 | # COMMAND REPLACEMENT & UTILITIES 81 | ### 82 | 83 | has_command() { 84 | local _command=$1 85 | 86 | type -P "$_command" > /dev/null 2>&1 87 | } 88 | 89 | curl() { 90 | command curl "${CURL_FLAGS[@]}" "$@" 91 | } 92 | 93 | mktemp() { 94 | command mktemp "$@" "/tmp/hyservinst.XXXXXXXXXX" 95 | } 96 | 97 | tput() { 98 | if has_command tput; then 99 | command tput "$@" 100 | fi 101 | } 102 | 103 | tred() { 104 | tput setaf 1 105 | } 106 | 107 | tgreen() { 108 | tput setaf 2 109 | } 110 | 111 | tyellow() { 112 | tput setaf 3 113 | } 114 | 115 | tblue() { 116 | tput setaf 4 117 | } 118 | 119 | taoi() { 120 | tput setaf 6 121 | } 122 | 123 | tbold() { 124 | tput bold 125 | } 126 | 127 | treset() { 128 | tput sgr0 129 | } 130 | 131 | note() { 132 | local _msg="$1" 133 | 134 | echo -e "$SCRIPT_NAME: $(tbold)note: $_msg$(treset)" 135 | } 136 | 137 | warning() { 138 | local _msg="$1" 139 | 140 | echo -e "$SCRIPT_NAME: $(tyellow)warning: $_msg$(treset)" 141 | } 142 | 143 | error() { 144 | local _msg="$1" 145 | 146 | echo -e "$SCRIPT_NAME: $(tred)error: $_msg$(treset)" 147 | } 148 | 149 | has_prefix() { 150 | local _s="$1" 151 | local _prefix="$2" 152 | 153 | if [[ -z "$_prefix" ]]; then 154 | return 0 155 | fi 156 | 157 | if [[ -z "$_s" ]]; then 158 | return 1 159 | fi 160 | 161 | [[ "x$_s" != "x${_s#"$_prefix"}" ]] 162 | } 163 | 164 | generate_random_password() { 165 | dd if=/dev/random bs=18 count=1 status=none | base64 166 | } 167 | 168 | systemctl() { 169 | if [[ "x$FORCE_NO_SYSTEMD" == "x2" ]] || ! has_command systemctl; then 170 | warning "Ignored systemd command: systemctl $@" 171 | return 172 | fi 173 | 174 | command systemctl "$@" 175 | } 176 | 177 | show_argument_error_and_exit() { 178 | local _error_msg="$1" 179 | 180 | error "$_error_msg" 181 | echo "Try \"$0 --help\" for usage." >&2 182 | exit 22 183 | } 184 | 185 | install_content() { 186 | local _install_flags="$1" 187 | local _content="$2" 188 | local _destination="$3" 189 | local _overwrite="$4" 190 | 191 | local _tmpfile="$(mktemp)" 192 | 193 | echo -ne "Install $_destination ... " 194 | echo "$_content" > "$_tmpfile" 195 | if [[ -z "$_overwrite" && -e "$_destination" ]]; then 196 | echo -e "exists" 197 | elif install "$_install_flags" "$_tmpfile" "$_destination"; then 198 | echo -e "ok" 199 | fi 200 | 201 | rm -f "$_tmpfile" 202 | } 203 | 204 | remove_file() { 205 | local _target="$1" 206 | 207 | echo -ne "Remove $_target ... " 208 | if rm "$_target"; then 209 | echo -e "ok" 210 | fi 211 | } 212 | 213 | exec_sudo() { 214 | # exec sudo with configurable environ preserved. 215 | local _saved_ifs="$IFS" 216 | IFS=$'\n' 217 | local _preserved_env=( 218 | $(env | grep "^PACKAGE_MANAGEMENT_INSTALL=" || true) 219 | $(env | grep "^OPERATING_SYSTEM=" || true) 220 | $(env | grep "^ARCHITECTURE=" || true) 221 | $(env | grep "^HYSTERIA_\w*=" || true) 222 | $(env | grep "^FORCE_\w*=" || true) 223 | ) 224 | IFS="$_saved_ifs" 225 | 226 | exec sudo env \ 227 | "${_preserved_env[@]}" \ 228 | "$@" 229 | } 230 | 231 | detect_package_manager() { 232 | if [[ -n "$PACKAGE_MANAGEMENT_INSTALL" ]]; then 233 | return 0 234 | fi 235 | 236 | if has_command apt; then 237 | PACKAGE_MANAGEMENT_INSTALL='apt -y --no-install-recommends install' 238 | return 0 239 | fi 240 | 241 | if has_command dnf; then 242 | PACKAGE_MANAGEMENT_INSTALL='dnf -y install' 243 | return 0 244 | fi 245 | 246 | if has_command yum; then 247 | PACKAGE_MANAGEMENT_INSTALL='yum -y install' 248 | return 0 249 | fi 250 | 251 | if has_command zypper; then 252 | PACKAGE_MANAGEMENT_INSTALL='zypper install -y --no-recommends' 253 | return 0 254 | fi 255 | 256 | if has_command pacman; then 257 | PACKAGE_MANAGEMENT_INSTALL='pacman -Syu --noconfirm' 258 | return 0 259 | fi 260 | 261 | return 1 262 | } 263 | 264 | install_software() { 265 | local _package_name="$1" 266 | 267 | if ! detect_package_manager; then 268 | error "Supported package manager is not detected, please install the following package manually:" 269 | echo 270 | echo -e "\t* $_package_name" 271 | echo 272 | exit 65 273 | fi 274 | 275 | echo "Installing missing dependence '$_package_name' with '$PACKAGE_MANAGEMENT_INSTALL' ... " 276 | if $PACKAGE_MANAGEMENT_INSTALL "$_package_name"; then 277 | echo "ok" 278 | else 279 | error "Cannot install '$_package_name' with detected package manager, please install it manually." 280 | exit 65 281 | fi 282 | } 283 | 284 | is_user_exists() { 285 | local _user="$1" 286 | 287 | id "$_user" > /dev/null 2>&1 288 | } 289 | 290 | rerun_with_sudo() { 291 | if ! has_command sudo; then 292 | return 13 293 | fi 294 | 295 | local _target_script 296 | 297 | if has_prefix "$0" "/dev/fd/"; then 298 | local _tmp_script="$(mktemp)" 299 | chmod +x "$_tmp_script" 300 | 301 | if has_command curl; then 302 | curl -o "$_tmp_script" 'https://get.hy2.sh/' 303 | elif has_command wget; then 304 | wget -O "$_tmp_script" 'https://get.hy2.sh' 305 | else 306 | return 127 307 | fi 308 | 309 | _target_script="$_tmp_script" 310 | else 311 | _target_script="$0" 312 | fi 313 | 314 | note "Re-running this script with sudo. You can also specify FORCE_NO_ROOT=1 to force this script to run as the current user." 315 | exec_sudo "$_target_script" "${SCRIPT_ARGS[@]}" 316 | } 317 | 318 | check_permission() { 319 | if [[ "$UID" -eq '0' ]]; then 320 | return 321 | fi 322 | 323 | note "The user running this script is not root." 324 | 325 | case "$FORCE_NO_ROOT" in 326 | '1') 327 | warning "FORCE_NO_ROOT=1 detected, we will proceed without root, but you may get insufficient privileges errors." 328 | ;; 329 | *) 330 | if ! rerun_with_sudo; then 331 | error "Please run this script with root or specify FORCE_NO_ROOT=1 to force this script to run as the current user." 332 | exit 13 333 | fi 334 | ;; 335 | esac 336 | } 337 | 338 | check_environment_operating_system() { 339 | if [[ -n "$OPERATING_SYSTEM" ]]; then 340 | warning "OPERATING_SYSTEM=$OPERATING_SYSTEM detected, operating system detection will not be performed." 341 | return 342 | fi 343 | 344 | if [[ "x$(uname)" == "xLinux" ]]; then 345 | OPERATING_SYSTEM=linux 346 | return 347 | fi 348 | 349 | error "This script only supports Linux." 350 | note "Specify OPERATING_SYSTEM=[linux|darwin|freebsd|windows] to bypass this check and force this script to run on this $(uname)." 351 | exit 95 352 | } 353 | 354 | check_environment_architecture() { 355 | if [[ -n "$ARCHITECTURE" ]]; then 356 | warning "ARCHITECTURE=$ARCHITECTURE detected, architecture detection will not be performed." 357 | return 358 | fi 359 | 360 | case "$(uname -m)" in 361 | 'i386' | 'i686') 362 | ARCHITECTURE='386' 363 | ;; 364 | 'amd64' | 'x86_64') 365 | ARCHITECTURE='amd64' 366 | ;; 367 | 'armv5tel' | 'armv6l' | 'armv7' | 'armv7l') 368 | ARCHITECTURE='arm' 369 | ;; 370 | 'armv8' | 'aarch64') 371 | ARCHITECTURE='arm64' 372 | ;; 373 | 'mips' | 'mipsle' | 'mips64' | 'mips64le') 374 | ARCHITECTURE='mipsle' 375 | ;; 376 | 's390x') 377 | ARCHITECTURE='s390x' 378 | ;; 379 | *) 380 | error "The architecture '$(uname -a)' is not supported." 381 | note "Specify ARCHITECTURE= to bypass this check and force this script to run on this $(uname -m)." 382 | exit 8 383 | ;; 384 | esac 385 | } 386 | 387 | check_environment_systemd() { 388 | if [[ -d "/run/systemd/system" ]] || grep -q systemd <(ls -l /sbin/init); then 389 | return 390 | fi 391 | 392 | case "$FORCE_NO_SYSTEMD" in 393 | '1') 394 | warning "FORCE_NO_SYSTEMD=1, we will proceed as normal even if systemd is not detected." 395 | ;; 396 | '2') 397 | warning "FORCE_NO_SYSTEMD=2, we will proceed but skip all systemd related commands." 398 | ;; 399 | *) 400 | error "This script only supports Linux distributions with systemd." 401 | note "Specify FORCE_NO_SYSTEMD=1 to disable this check and force this script to run as if systemd exists." 402 | note "Specify FORCE_NO_SYSTEMD=2 to disable this check and skip all systemd related commands." 403 | ;; 404 | esac 405 | } 406 | 407 | check_environment_curl() { 408 | if has_command curl; then 409 | return 410 | fi 411 | 412 | install_software curl 413 | } 414 | 415 | check_environment_grep() { 416 | if has_command grep; then 417 | return 418 | fi 419 | 420 | install_software grep 421 | } 422 | 423 | check_environment() { 424 | check_environment_operating_system 425 | check_environment_architecture 426 | check_environment_systemd 427 | check_environment_curl 428 | check_environment_grep 429 | } 430 | 431 | vercmp_segment() { 432 | local _lhs="$1" 433 | local _rhs="$2" 434 | 435 | if [[ "x$_lhs" == "x$_rhs" ]]; then 436 | echo 0 437 | return 438 | fi 439 | if [[ -z "$_lhs" ]]; then 440 | echo -1 441 | return 442 | fi 443 | if [[ -z "$_rhs" ]]; then 444 | echo 1 445 | return 446 | fi 447 | 448 | local _lhs_num="${_lhs//[A-Za-z]*/}" 449 | local _rhs_num="${_rhs//[A-Za-z]*/}" 450 | 451 | if [[ "x$_lhs_num" == "x$_rhs_num" ]]; then 452 | echo 0 453 | return 454 | fi 455 | if [[ -z "$_lhs_num" ]]; then 456 | echo -1 457 | return 458 | fi 459 | if [[ -z "$_rhs_num" ]]; then 460 | echo 1 461 | return 462 | fi 463 | local _numcmp=$(($_lhs_num - $_rhs_num)) 464 | if [[ "$_numcmp" -ne 0 ]]; then 465 | echo "$_numcmp" 466 | return 467 | fi 468 | 469 | local _lhs_suffix="${_lhs#"$_lhs_num"}" 470 | local _rhs_suffix="${_rhs#"$_rhs_num"}" 471 | 472 | if [[ "x$_lhs_suffix" == "x$_rhs_suffix" ]]; then 473 | echo 0 474 | return 475 | fi 476 | if [[ -z "$_lhs_suffix" ]]; then 477 | echo 1 478 | return 479 | fi 480 | if [[ -z "$_rhs_suffix" ]]; then 481 | echo -1 482 | return 483 | fi 484 | if [[ "$_lhs_suffix" < "$_rhs_suffix" ]]; then 485 | echo -1 486 | return 487 | fi 488 | echo 1 489 | } 490 | 491 | vercmp() { 492 | local _lhs=${1#v} 493 | local _rhs=${2#v} 494 | 495 | while [[ -n "$_lhs" && -n "$_rhs" ]]; do 496 | local _clhs="${_lhs/.*/}" 497 | local _crhs="${_rhs/.*/}" 498 | 499 | local _segcmp="$(vercmp_segment "$_clhs" "$_crhs")" 500 | if [[ "$_segcmp" -ne 0 ]]; then 501 | echo "$_segcmp" 502 | return 503 | fi 504 | 505 | _lhs="${_lhs#"$_clhs"}" 506 | _lhs="${_lhs#.}" 507 | _rhs="${_rhs#"$_crhs"}" 508 | _rhs="${_rhs#.}" 509 | done 510 | 511 | if [[ "x$_lhs" == "x$_rhs" ]]; then 512 | echo 0 513 | return 514 | fi 515 | 516 | if [[ -z "$_lhs" ]]; then 517 | echo -1 518 | return 519 | fi 520 | 521 | if [[ -z "$_rhs" ]]; then 522 | echo 1 523 | return 524 | fi 525 | 526 | return 527 | } 528 | 529 | check_hysteria_user() { 530 | local _default_hysteria_user="$1" 531 | 532 | if [[ -n "$HYSTERIA_USER" ]]; then 533 | return 534 | fi 535 | 536 | if [[ ! -e "$SYSTEMD_SERVICES_DIR/hysteria-server.service" ]]; then 537 | HYSTERIA_USER="$_default_hysteria_user" 538 | return 539 | fi 540 | 541 | HYSTERIA_USER="$(grep -o '^User=\w*' "$SYSTEMD_SERVICES_DIR/hysteria-server.service" | tail -1 | cut -d '=' -f 2 || true)" 542 | 543 | if [[ -z "$HYSTERIA_USER" ]]; then 544 | HYSTERIA_USER="$_default_hysteria_user" 545 | fi 546 | } 547 | 548 | check_hysteria_homedir() { 549 | local _default_hysteria_homedir="$1" 550 | 551 | if [[ -n "$HYSTERIA_HOME_DIR" ]]; then 552 | return 553 | fi 554 | 555 | if ! is_user_exists "$HYSTERIA_USER"; then 556 | HYSTERIA_HOME_DIR="$_default_hysteria_homedir" 557 | return 558 | fi 559 | 560 | HYSTERIA_HOME_DIR="$(eval echo ~"$HYSTERIA_USER")" 561 | } 562 | 563 | 564 | ### 565 | # ARGUMENTS PARSER 566 | ### 567 | 568 | show_usage_and_exit() { 569 | echo 570 | echo -e "\t$(tbold)$SCRIPT_NAME$(treset) - hysteria server install script" 571 | echo 572 | echo -e "Usage:" 573 | echo 574 | echo -e "$(tbold)Install hysteria$(treset)" 575 | echo -e "\t$0 [ -f | -l | --version ]" 576 | echo -e "Flags:" 577 | echo -e "\t-f, --force\tForce re-install latest or specified version even if it has been installed." 578 | echo -e "\t-l, --local \tInstall specified hysteria binary instead of download it." 579 | echo -e "\t--version \tInstall specified version instead of the latest." 580 | echo 581 | echo -e "$(tbold)Remove hysteria$(treset)" 582 | echo -e "\t$0 --remove" 583 | echo 584 | echo -e "$(tbold)Check for the update$(treset)" 585 | echo -e "\t$0 -c" 586 | echo -e "\t$0 --check" 587 | echo 588 | echo -e "$(tbold)Show this help$(treset)" 589 | echo -e "\t$0 -h" 590 | echo -e "\t$0 --help" 591 | exit 0 592 | } 593 | 594 | parse_arguments() { 595 | while [[ "$#" -gt '0' ]]; do 596 | case "$1" in 597 | '--remove') 598 | if [[ -n "$OPERATION" && "$OPERATION" != 'remove' ]]; then 599 | show_argument_error_and_exit "Option '--remove' is in conflict with other options." 600 | fi 601 | OPERATION='remove' 602 | ;; 603 | '--version') 604 | VERSION="$2" 605 | if [[ -z "$VERSION" ]]; then 606 | show_argument_error_and_exit "Please specify the version for option '--version'." 607 | fi 608 | shift 609 | if ! has_prefix "$VERSION" 'v'; then 610 | show_argument_error_and_exit "Version numbers should begin with 'v' (such as 'v2.0.0'), got '$VERSION'" 611 | fi 612 | ;; 613 | '-c' | '--check') 614 | if [[ -n "$OPERATION" && "$OPERATION" != 'check' ]]; then 615 | show_argument_error_and_exit "Option '-c' or '--check' is in conflict with other options." 616 | fi 617 | OPERATION='check_update' 618 | ;; 619 | '-f' | '--force') 620 | FORCE='1' 621 | ;; 622 | '-h' | '--help') 623 | show_usage_and_exit 624 | ;; 625 | '-l' | '--local') 626 | LOCAL_FILE="$2" 627 | if [[ -z "$LOCAL_FILE" ]]; then 628 | show_argument_error_and_exit "Please specify the local binary to install for option '-l' or '--local'." 629 | fi 630 | break 631 | ;; 632 | *) 633 | show_argument_error_and_exit "Unknown option '$1'" 634 | ;; 635 | esac 636 | shift 637 | done 638 | 639 | if [[ -z "$OPERATION" ]]; then 640 | OPERATION='install' 641 | fi 642 | 643 | # validate arguments 644 | case "$OPERATION" in 645 | 'install') 646 | if [[ -n "$VERSION" && -n "$LOCAL_FILE" ]]; then 647 | show_argument_error_and_exit '--version and --local cannot be used together.' 648 | fi 649 | ;; 650 | *) 651 | if [[ -n "$VERSION" ]]; then 652 | show_argument_error_and_exit "--version is only valid for install operation." 653 | fi 654 | if [[ -n "$LOCAL_FILE" ]]; then 655 | show_argument_error_and_exit "--local is only valid for install operation." 656 | fi 657 | ;; 658 | esac 659 | } 660 | 661 | 662 | ### 663 | # FILE TEMPLATES 664 | ### 665 | 666 | # /etc/systemd/system/hysteria-server.service 667 | tpl_hysteria_server_service_base() { 668 | local _config_name="$1" 669 | 670 | cat << EOF 671 | [Unit] 672 | Description=Hysteria Server Service (${_config_name}.yaml) 673 | After=network.target 674 | 675 | [Service] 676 | Type=simple 677 | ExecStart=$EXECUTABLE_INSTALL_PATH server --config ${CONFIG_DIR}/${_config_name}.yaml 678 | WorkingDirectory=$HYSTERIA_HOME_DIR 679 | User=$HYSTERIA_USER 680 | Group=$HYSTERIA_USER 681 | Environment=HYSTERIA_LOG_LEVEL=info 682 | CapabilityBoundingSet=CAP_NET_ADMIN CAP_NET_BIND_SERVICE CAP_NET_RAW 683 | AmbientCapabilities=CAP_NET_ADMIN CAP_NET_BIND_SERVICE CAP_NET_RAW 684 | NoNewPrivileges=true 685 | 686 | [Install] 687 | WantedBy=multi-user.target 688 | EOF 689 | } 690 | 691 | # /etc/systemd/system/hysteria-server.service 692 | tpl_hysteria_server_service() { 693 | tpl_hysteria_server_service_base 'config' 694 | } 695 | 696 | # /etc/systemd/system/hysteria-server@.service 697 | tpl_hysteria_server_x_service() { 698 | tpl_hysteria_server_service_base '%i' 699 | } 700 | 701 | # /etc/hysteria/config.yaml 702 | tpl_etc_hysteria_config_yaml() { 703 | cat << EOF 704 | # listen: :443 705 | 706 | acme: 707 | domains: 708 | - your.domain.net 709 | email: your@email.com 710 | 711 | auth: 712 | type: password 713 | password: $(generate_random_password) 714 | 715 | masquerade: 716 | type: proxy 717 | proxy: 718 | url: https://news.ycombinator.com/ 719 | rewriteHost: true 720 | EOF 721 | } 722 | 723 | 724 | ### 725 | # SYSTEMD 726 | ### 727 | 728 | get_running_services() { 729 | if [[ "x$FORCE_NO_SYSTEMD" == "x2" ]]; then 730 | return 731 | fi 732 | 733 | systemctl list-units --state=active --plain --no-legend \ 734 | | grep -o "hysteria-server@*[^\s]*.service" || true 735 | } 736 | 737 | restart_running_services() { 738 | if [[ "x$FORCE_NO_SYSTEMD" == "x2" ]]; then 739 | return 740 | fi 741 | 742 | echo "Restarting running service ... " 743 | 744 | for service in $(get_running_services); do 745 | echo -ne "Restarting $service ... " 746 | systemctl restart "$service" 747 | echo "done" 748 | done 749 | } 750 | 751 | stop_running_services() { 752 | if [[ "x$FORCE_NO_SYSTEMD" == "x2" ]]; then 753 | return 754 | fi 755 | 756 | echo "Stopping running service ... " 757 | 758 | for service in $(get_running_services); do 759 | echo -ne "Stopping $service ... " 760 | systemctl stop "$service" 761 | echo "done" 762 | done 763 | } 764 | 765 | 766 | ### 767 | # HYSTERIA & GITHUB API 768 | ### 769 | 770 | is_hysteria_installed() { 771 | # RETURN VALUE 772 | # 0: hysteria is installed 773 | # 1: hysteria is not installed 774 | 775 | if [[ -f "$EXECUTABLE_INSTALL_PATH" || -h "$EXECUTABLE_INSTALL_PATH" ]]; then 776 | return 0 777 | fi 778 | return 1 779 | } 780 | 781 | is_hysteria1_version() { 782 | local _version="$1" 783 | 784 | has_prefix "$_version" "v1." || has_prefix "$_version" "v0." 785 | } 786 | 787 | get_installed_version() { 788 | if is_hysteria_installed; then 789 | if "$EXECUTABLE_INSTALL_PATH" version > /dev/null 2>&1; then 790 | "$EXECUTABLE_INSTALL_PATH" version | grep Version | grep -o 'v[.0-9]*' 791 | elif "$EXECUTABLE_INSTALL_PATH" -v > /dev/null 2>&1; then 792 | # hysteria 1 793 | "$EXECUTABLE_INSTALL_PATH" -v | cut -d ' ' -f 3 794 | fi 795 | fi 796 | } 797 | 798 | get_latest_version() { 799 | if [[ -n "$VERSION" ]]; then 800 | echo "$VERSION" 801 | return 802 | fi 803 | 804 | local _tmpfile=$(mktemp) 805 | if ! curl -sS -H 'Accept: application/vnd.github.v3+json' "$API_BASE_URL/releases/latest" -o "$_tmpfile"; then 806 | error "Failed to get the latest version from GitHub API, please check your network and try again." 807 | exit 11 808 | fi 809 | 810 | local _latest_version=$(grep 'tag_name' "$_tmpfile" | head -1 | grep -o '"app/v.*"') 811 | _latest_version=${_latest_version#'"app/'} 812 | _latest_version=${_latest_version%'"'} 813 | 814 | if [[ -n "$_latest_version" ]]; then 815 | echo "$_latest_version" 816 | fi 817 | 818 | rm -f "$_tmpfile" 819 | } 820 | 821 | download_hysteria() { 822 | local _version="$1" 823 | local _destination="$2" 824 | 825 | local _download_url="$REPO_URL/releases/download/app/$_version/hysteria-$OPERATING_SYSTEM-$ARCHITECTURE" 826 | echo "Downloading hysteria binary: $_download_url ..." 827 | if ! curl -R -H 'Cache-Control: no-cache' "$_download_url" -o "$_destination"; then 828 | error "Download failed, please check your network and try again." 829 | return 11 830 | fi 831 | return 0 832 | } 833 | 834 | check_update() { 835 | # RETURN VALUE 836 | # 0: update available 837 | # 1: installed version is latest 838 | 839 | echo -ne "Checking for installed version ... " 840 | local _installed_version="$(get_installed_version)" 841 | if [[ -n "$_installed_version" ]]; then 842 | echo "$_installed_version" 843 | else 844 | echo "not installed" 845 | fi 846 | 847 | echo -ne "Checking for latest version ... " 848 | local _latest_version="$(get_latest_version)" 849 | if [[ -n "$_latest_version" ]]; then 850 | echo "$_latest_version" 851 | VERSION="$_latest_version" 852 | else 853 | echo "failed" 854 | return 1 855 | fi 856 | 857 | local _vercmp="$(vercmp "$_installed_version" "$_latest_version")" 858 | if [[ "$_vercmp" -lt 0 ]]; then 859 | return 0 860 | fi 861 | 862 | return 1 863 | } 864 | 865 | 866 | ### 867 | # ENTRY 868 | ### 869 | 870 | perform_install_hysteria_binary() { 871 | if [[ -n "$LOCAL_FILE" ]]; then 872 | note "Performing local install: $LOCAL_FILE" 873 | 874 | echo -ne "Installing hysteria executable ... " 875 | 876 | if install -Dm755 "$LOCAL_FILE" "$EXECUTABLE_INSTALL_PATH"; then 877 | echo "ok" 878 | else 879 | exit 2 880 | fi 881 | 882 | return 883 | fi 884 | 885 | local _tmpfile=$(mktemp) 886 | 887 | if ! download_hysteria "$VERSION" "$_tmpfile"; then 888 | rm -f "$_tmpfile" 889 | exit 11 890 | fi 891 | 892 | echo -ne "Installing hysteria executable ... " 893 | 894 | if install -Dm755 "$_tmpfile" "$EXECUTABLE_INSTALL_PATH"; then 895 | echo "ok" 896 | else 897 | exit 13 898 | fi 899 | 900 | rm -f "$_tmpfile" 901 | } 902 | 903 | perform_remove_hysteria_binary() { 904 | remove_file "$EXECUTABLE_INSTALL_PATH" 905 | } 906 | 907 | perform_install_hysteria_example_config() { 908 | install_content -Dm644 "$(tpl_etc_hysteria_config_yaml)" "$CONFIG_DIR/config.yaml" "" 909 | } 910 | 911 | perform_install_hysteria_systemd() { 912 | if [[ "x$FORCE_NO_SYSTEMD" == "x2" ]]; then 913 | return 914 | fi 915 | 916 | install_content -Dm644 "$(tpl_hysteria_server_service)" "$SYSTEMD_SERVICES_DIR/hysteria-server.service" "1" 917 | install_content -Dm644 "$(tpl_hysteria_server_x_service)" "$SYSTEMD_SERVICES_DIR/hysteria-server@.service" "1" 918 | 919 | systemctl daemon-reload 920 | } 921 | 922 | perform_remove_hysteria_systemd() { 923 | remove_file "$SYSTEMD_SERVICES_DIR/hysteria-server.service" 924 | remove_file "$SYSTEMD_SERVICES_DIR/hysteria-server@.service" 925 | 926 | systemctl daemon-reload 927 | } 928 | 929 | perform_install_hysteria_home_legacy() { 930 | if ! is_user_exists "$HYSTERIA_USER"; then 931 | echo -ne "Creating user $HYSTERIA_USER ... " 932 | useradd -r -d "$HYSTERIA_HOME_DIR" -m "$HYSTERIA_USER" 933 | echo "ok" 934 | fi 935 | } 936 | 937 | perform_install() { 938 | local _is_frash_install 939 | local _is_upgrade_from_hysteria1 940 | if ! is_hysteria_installed; then 941 | _is_frash_install=1 942 | elif is_hysteria1_version "$(get_installed_version)"; then 943 | _is_upgrade_from_hysteria1=1 944 | fi 945 | 946 | local _is_update_required 947 | 948 | if [[ -n "$LOCAL_FILE" ]] || [[ -n "$VERSION" ]] || check_update; then 949 | _is_update_required=1 950 | fi 951 | 952 | if [[ "x$FORCE" == "x1" ]]; then 953 | if [[ -z "$_is_update_required" ]]; then 954 | note "Option '--force' detected, re-install even if installed version is the latest." 955 | fi 956 | _is_update_required=1 957 | fi 958 | 959 | if [[ -z "$_is_update_required" ]]; then 960 | echo "$(tgreen)Installed version is up-to-date, there is nothing to do.$(treset)" 961 | return 962 | fi 963 | 964 | if is_hysteria1_version "$VERSION"; then 965 | error "This script can only install Hysteria 2." 966 | exit 95 967 | fi 968 | 969 | perform_install_hysteria_binary 970 | perform_install_hysteria_example_config 971 | perform_install_hysteria_home_legacy 972 | perform_install_hysteria_systemd 973 | 974 | if [[ -n "$_is_frash_install" ]]; then 975 | echo 976 | echo -e "$(tbold)Congratulation! Hysteria 2 has been successfully installed on your server.$(treset)" 977 | echo 978 | echo -e "What's next?" 979 | echo 980 | echo -e "\t+ Take a look at the differences between Hysteria 2 and Hysteria 1 at https://hysteria.network/docs/misc/2-vs-1/" 981 | echo -e "\t+ Check out the quick server config guide at $(tblue)https://hysteria.network/docs/getting-started/Server/$(treset)" 982 | echo -e "\t+ Edit server config file at $(tred)$CONFIG_DIR/config.yaml$(treset)" 983 | echo -e "\t+ Start your hysteria server with $(tred)systemctl start hysteria-server.service$(treset)" 984 | echo -e "\t+ Configure hysteria start on system boot with $(tred)systemctl enable hysteria-server.service$(treset)" 985 | echo 986 | elif [[ -n "$_is_upgrade_from_hysteria1" ]]; then 987 | echo -e "Skip automatic service restart due to $(tred)incompatible$(treset) upgrade." 988 | echo 989 | echo -e "$(tbold)Hysteria has been successfully update to $VERSION from Hysteria 1.$(treset)" 990 | echo 991 | echo -e "$(tred)Hysteria 2 uses a completely redesigned protocol & config, which is NOT compatible with the version 1.x.x in any way.$(treset)" 992 | echo 993 | echo -e "\t+ Take a look at the behavior changes in Hysteria 2 at $(tblue)https://hysteria.network/docs/misc/2-vs-1/$(treset)" 994 | echo -e "\t+ Check out the quick server configuration guide for Hysteria 2 at $(tblue)https://hysteria.network/docs/getting-started/Server/$(treset)" 995 | echo -e "\t+ Migrate server config file to the Hysteria 2 at $(tred)$CONFIG_DIR/config.yaml$(treset)" 996 | echo -e "\t+ Start your hysteria server with $(tred)systemctl restart hysteria-server.service$(treset)" 997 | echo -e "\t+ Configure hysteria start on system boot with $(tred)systemctl enable hysteria-server.service$(treset)" 998 | else 999 | restart_running_services 1000 | 1001 | echo 1002 | echo -e "$(tbold)Hysteria has been successfully update to $VERSION.$(treset)" 1003 | echo 1004 | echo -e "Check out the latest changelog $(tblue)https://github.com/apernet/hysteria/blob/master/CHANGELOG.md$(treset)" 1005 | echo 1006 | fi 1007 | } 1008 | 1009 | perform_remove() { 1010 | perform_remove_hysteria_binary 1011 | stop_running_services 1012 | perform_remove_hysteria_systemd 1013 | 1014 | echo 1015 | echo -e "$(tbold)Congratulation! Hysteria has been successfully removed from your server.$(treset)" 1016 | echo 1017 | echo -e "You still need to remove configuration files and ACME certificates manually with the following commands:" 1018 | echo 1019 | echo -e "\t$(tred)rm -rf "$CONFIG_DIR"$(treset)" 1020 | if [[ "x$HYSTERIA_USER" != "xroot" ]]; then 1021 | echo -e "\t$(tred)userdel -r "$HYSTERIA_USER"$(treset)" 1022 | fi 1023 | if [[ "x$FORCE_NO_SYSTEMD" != "x2" ]]; then 1024 | echo 1025 | echo -e "You still might need to disable all related systemd services with the following commands:" 1026 | echo 1027 | echo -e "\t$(tred)rm -f /etc/systemd/system/multi-user.target.wants/hysteria-server.service$(treset)" 1028 | echo -e "\t$(tred)rm -f /etc/systemd/system/multi-user.target.wants/hysteria-server@*.service$(treset)" 1029 | echo -e "\t$(tred)systemctl daemon-reload$(treset)" 1030 | fi 1031 | echo 1032 | } 1033 | 1034 | perform_check_update() { 1035 | if check_update; then 1036 | echo 1037 | echo -e "$(tbold)Update available: $VERSION$(treset)" 1038 | echo 1039 | echo -e "$(tgreen)You can download and install the latest version by execute this script without any arguments.$(treset)" 1040 | echo 1041 | else 1042 | echo 1043 | echo "$(tgreen)Installed version is up-to-date.$(treset)" 1044 | echo 1045 | fi 1046 | } 1047 | 1048 | main() { 1049 | parse_arguments "$@" 1050 | 1051 | check_permission 1052 | check_environment 1053 | check_hysteria_user "hysteria" 1054 | check_hysteria_homedir "/var/lib/$HYSTERIA_USER" 1055 | 1056 | case "$OPERATION" in 1057 | "install") 1058 | perform_install 1059 | ;; 1060 | "remove") 1061 | perform_remove 1062 | ;; 1063 | "check_update") 1064 | perform_check_update 1065 | ;; 1066 | *) 1067 | error "Unknown operation '$OPERATION'." 1068 | ;; 1069 | esac 1070 | } 1071 | 1072 | main "$@" 1073 | 1074 | # vim:set ft=bash ts=2 sw=2 sts=2 et: --------------------------------------------------------------------------------