之前建立了完整的 VPS 服务器,由于其中的步骤比较繁琐,当更换服务器后,再次恢复成原来的服务会很麻烦。
因此,把其中的固定步骤转换为脚本,通过脚本可快速的重新搭建 VPS。
脚本内容
脚本分为两个,一个是主脚本,包含所有模块,另一个脚本是用于调用主脚本的外壳。脚本也同步分享在 github 仓库 中。
1#!/usr/bin/env bash2#==================================================================3# ██╗ ██╗ ██╗███╗ ██╗██████╗ ██████╗ █████╗4# ██║ ╚██╗ ██╔╝████╗ ██║██╔══██╗██╔══██╗██╔══██╗5# ██║ ╚████╔╝ ██╔██╗ ██║██║ ██║██████╔╝███████║6# ██║ ╚██╔╝ ██║╚██╗██║██║ ██║██╔══██╗██╔══██║7# ███████╗██║ ██║ ╚████║██████╔╝██║ ██║██║ ██║8# ╚══════╝╚═╝ ╚═╝ ╚═══╝╚═════╝ ╚═╝ ╚═╝╚═╝ ╚═╝9#==================================================================10#11# 文件名称: build-all.sh12# 文件描述: VPS 搭建脚本,包含域名申请,3XUI面板搭建、Sub-Store服务安装、13# Hysteria2 安装、Nginx分流配置。需 root 用户运行。14# 运行前请自定义修改117-131的端口号。15#722 collapsed lines
16# 作者: Lyndra <lyndra.hyst@gmail.com>17# 版本: 1.0.018# 创建日期: 2025-04-2519# 最后修改: 2025-05-2920#21# 使用许可: GPLv2 or other licenses22# Copyright (c) 2025 Lyndra23#24#==================================================================25
26set -eo pipefail27
28# 颜色配置29RED='\033[0;31m'30GREEN='\033[0;32m'31YELLOW='\033[1;33m'32BLUE='\033[0;34m'33NC='\033[0m'34
35# 命令配置,格式为:[命令名]="描述::处理函数::选项声明1::选项声明2::..."36declare -A COMMAND_MAP=(37 ["setup"]="基础环境设置::handle_setup::-u,--user:指定新建用户名(必须)::-p,--pass:指定新建用户密码(必须)::-s,--ssh-port:指定SSH端口(默认:22222)"38 ["cert"]="证书管理::handle_cert::-d,--domain:指定主域名(必须,建议优先使用二级域名,可免费开启cloudflare代理保护,三级域名不可免费使用)::-e,--email:指定邮箱(必须)::-t,--token:指定Cloudflare API Token(必须)::-z,--zone-id:指定Cloudflare Zone ID(必须)::-a,--account-id:指定Cloudflare Account ID(必须)"39 ["hysteria"]="Hysteria2服务::handle_hysteria::-d,--domain:指定域名(必须,确定证书路径)::-p,--port:指定端口(默认:8443)::-u,--user:指定用户名(必须)::-w,--pass:指定密码(必须)"40 ["xui"]="X-UI面板::handle_xui"41 ["substore"]="Sub-Store服务::handle_substore::-a,--api-key:指定API密钥(必须)"42 ["nginx"]="Nginx分流配置::handle_nginx::-d,--domain:指定域名(必须,确定证书路径)::-x,--xui-domain:指定X-UI域名(必须)::-s,--substore-domain:指定Sub-Store域名(必须)::-p,--port-xui:指定xui访问端口(必须)"43)44
45# 错误处理函数46panic() {47 echo -e "${RED}[错误]${NC} $1" >&248 exit 149}50
51# 日志输出函数52log_info() {53 echo -e "${GREEN}[信息]${NC} $1" >&254}55
56log_warning() {57 echo -e "${YELLOW}[警告]${NC} $1" >&258}59
60log_success() {61 echo -e "${GREEN}[成功]${NC} $1" >&262}63
64log_debug() {65 echo -e "${BLUE}[调试]${NC} $1" >&266}67
68##############################################69# 通用的帮助信息生成函数 #70##############################################71
72show_command_help() {73 local cmd="$1"74 local info="${COMMAND_MAP[$cmd]}"75
76 # 1) 把所有 "::" 替换成一个不会在脚本中出现的分隔符,比如 '|'77 info="${info//::/|}"78
79 # 2) 这时才能安全地用 IFS='|' 来做分割80 local desc handler options_str81 IFS="|" read -r desc handler options_str <<<"$info"82
83 echo -e "${YELLOW}命令: ${GREEN}$cmd${NC}"84 echo -e "${YELLOW}描述: ${NC}$desc"85 echo -e "${YELLOW}选项:${NC}"86
87 # 3) 选项声明里可能有多段「::」分隔,继续替换并拆分88 options_str="${options_str//::/|}"89 IFS="|" read -ra opt_lines <<<"$options_str"90
91 for opt_line in "${opt_lines[@]}"; do92 [[ -z "$opt_line" ]] && continue93
94 # opt_line 类似 "-p,--package:指定包名(必须)"95 # 用 ":" 分割出(短+长选项)和描述96 IFS=":" read -r flags desc <<<"$opt_line"97 printf " ${GREEN}%-20s${NC} %s\n" "$flags" "$desc"98 done99}100
101# 主帮助信息102show_help() {103 echo -e "${YELLOW}使用方法:${NC}"104 echo " $0 [命令] [选项]"105 echo106 echo -e "${YELLOW}可用命令:${NC}"107 for cmd in "${!COMMAND_MAP[@]}"; do108 local desc=${COMMAND_MAP[$cmd]%%::*}109 printf " ${GREEN}%-15s${NC} %s\n" "$cmd" "$desc"110 done111 echo -e "\n使用 ${YELLOW}$0 命令 --help${NC} 查看具体命令帮助"112}113
114##############################################115# 命令处理函数 #116##############################################117
118
119# ==========================================120# 配置信息开始,请根据实际情况修改121# ==========================================122
123# 新建用户的组id和用户id,默认 1001124groupid=1001125userid=1001126
127# ssh 登陆端口配置,请确保该端口未被占用128port_ssh=22222129
130# Hysteria 主端口配置131port_hysteria=8443132
133# Hysteria 跳跃端口配置134port_hysteria_jump_1=50220135port_hysteria_jump_1_end=50959136port_hysteria_jump_2=60133137port_hysteria_jump_2_end=60968138
139# ==========================================140# 配置信息结束141# ==========================================142
143
144# 基础环境设置145handle_setup() {146 local username=""147 local password=""148
149 while [[ $# -gt 0 ]]; do150 case $1 in151 -u | --user)152 username="$2"153 shift 2154 ;;155 -p | --pass)156 password="$2"157 shift 2158 ;;159 -s | --ssh-port)160 port_ssh="$2"161 shift 2162 ;;163 -h | --help)164 show_command_help "setup"165 exit 0166 ;;167 *)168 panic "未知选项: $1"169 ;;170 esac171 done172
173 [[ -z "$username" ]] && panic "必须指定用户名"174 [[ -z "$password" ]] && panic "必须指定密码"175
176 log_info "开始设置基础环境..."177
178 # 安装常用软件179 log_info "安装常用软件..."180 apt update && apt upgrade -y&& apt-get install -y curl vim ufw sudo181
182 # 创建非root用户183 log_info "创建非root用户: $username"184
185 getent group ${groupid} || groupadd -g ${groupid} vps186 getent passwd "$username" || useradd -ms /bin/bash -u ${userid} -g ${groupid} -G sudo "$username"187 echo "$username:$password" | chpasswd188 echo "$username ALL=(ALL) NOPASSWD:ALL" >> /etc/sudoers189
190 log_info "非root用户创建完成,请在新终端中使用 $username 用户登录,确认是否生效,生效请输入 y/Y,否则请重新运行脚本"191 read -p "请输入y确认:" confirm192 if [ "$confirm" != "y" ] && [ "$confirm" != "Y" ]; then193 panic "非root用户创建完成未生效,请检测系统环境,重新运行脚本"194 fi195
196 # SSH安全加固197 log_info "配置SSH安全设置..."198
199 # 检查 SSH 端口是否已经修改200 if grep -q "^Port $port_ssh" /etc/ssh/sshd_config; then201 log_info "SSH 端口已设置为 $port_ssh,跳过修改"202 else203 sed -i "s/#Port 22/Port $port_ssh/" /etc/ssh/sshd_config204 sed -i "s/^Port 22/Port $port_ssh/" /etc/ssh/sshd_config205 log_info "SSH 端口已修改为 $port_ssh"206 fi207
208 # 检查 root 登录是否已经禁用209 if grep -q "^PermitRootLogin no" /etc/ssh/sshd_config; then210 log_info "Root 登录已禁用,跳过修改"211 else212 sed -i "s/#PermitRootLogin yes/PermitRootLogin no/" /etc/ssh/sshd_config213 sed -i "s/^PermitRootLogin yes/PermitRootLogin no/" /etc/ssh/sshd_config214 log_info "Root 登录已禁用"215 fi216
217 ufw allow "$port_ssh"218 ufw deny 22219
220 systemctl restart ssh221
222 log_info "SSH安全设置完成,请在新终端中使用新端口 ssh -p ${port_ssh} ${username}@ip,确认是否生效,生效请输入 y/Y,否则请重新运行脚本"223 read -p "请输入y确认:" confirm224 if [ "$confirm" != "y" ] && [ "$confirm" != "Y" ]; then225 panic "SSH安全设置未生效,请检测系统环境,重新运行脚本"226 fi227
228 # 防火墙设置229 log_info "配置防火墙..."230 ufw allow 80231 ufw allow 443232
233 ufw --force enable234
235 log_success "基础环境设置完成"236}237
238# 证书管理239# 证书管理 - 改进版本240handle_cert() {241 local email=""242 local cf_token=""243 local cf_zone_id=""244 local cf_account_id=""245 local domain=""246 local key_type="ec-256" # 新增:默认使用 EC-256247
248 while [[ $# -gt 0 ]]; do249 case $1 in250 -d | --domain)251 domain="$2"252 shift 2253 ;;254 -e | --email)255 email="$2"256 shift 2257 ;;258 -t | --token)259 cf_token="$2"260 shift 2261 ;;262 -z | --zone-id)263 cf_zone_id="$2"264 shift 2265 ;;266 -a | --account-id)267 cf_account_id="$2"268 shift 2269 ;;270 -k | --key-type)271 key_type="$2"272 shift 2273 ;;274 -h | --help)275 show_command_help "cert"276 exit 0277 ;;278 *)279 panic "未知选项: $1"280 ;;281 esac282 done283
284 [[ -z "$domain" ]] && panic "必须指定主域名"285 [[ -z "$email" ]] && panic "必须指定邮箱"286 [[ -z "$cf_token" ]] && panic "必须指定Cloudflare API Token"287 [[ -z "$cf_zone_id" ]] && panic "必须指定Cloudflare Zone ID"288 [[ -z "$cf_account_id" ]] && panic "必须指定Cloudflare Account ID"289
290 # 验证密钥类型291 case "$key_type" in292 "ec-256"|"ec-384"|"2048"|"3072"|"4096")293 ;;294 *)295 panic "不支持的密钥类型: $key_type,支持: ec-256, ec-384, 2048, 3072, 4096"296 ;;297 esac298
299 log_info "开始申请TLS证书(密钥类型: $key_type)..."300
301 # 安装acme.sh302 log_info "安装acme.sh..."303 curl https://get.acme.sh | sh -s email="$email"304 apt install socat -y305 ~/.acme.sh/acme.sh --set-default-ca --server letsencrypt306 source ~/.bashrc307 ~/.acme.sh/acme.sh --upgrade --auto-upgrade308
309 # 设置环境变量310 export CF_Token="$cf_token"311 export CF_Zone_ID="$cf_zone_id"312 export CF_Account_ID="$cf_account_id"313
314 # 申请证书315 local username=$(id -un 1001)316
317 log_info "申请证书: $domain(密钥类型: $key_type)"318
319 # 检查证书是否已经存在且有效320 if [[ -f "/home/$username/$domain.cer" ]] && [[ -f "/home/$username/$domain.key" ]]; then321 if openssl x509 -in "/home/$username/$domain.cer" -noout -checkend 2592000 > /dev/null 2>&1; then322 log_info "证书已存在且有效期超过30天,跳过申请"323 log_success "证书检查完成"324 return 0325 else326 log_warning "证书已存在但即将过期或无效,重新申请"327 fi328 fi329
330 # 构建 acme.sh 命令331 local acme_cmd="~/.acme.sh/acme.sh --issue --dns dns_cf -d \"$domain\" -d \"*.$domain\""332
333 # 添加密钥长度参数334 acme_cmd="$acme_cmd --keylength $key_type"335
336 # 添加输出文件参数337 acme_cmd="$acme_cmd --key-file /home/$username/$domain.key"338 acme_cmd="$acme_cmd --fullchain-file /home/$username/$domain.cer"339 acme_cmd="$acme_cmd --reloadcmd 'bash -c \"nginx -s reload && x-ui restart\"'"340
341 # 执行命令342 eval $acme_cmd || log_warning "证书申请结果请检查,目前没有安装 nginx,会导致reload失败,但不代表证书申请失败"343
344 # 修改权限345 log_info "修改证书权限..."346 chmod 644 "/home/$username/$domain.key"347 chmod 644 "/home/$username/$domain.cer"348
349 # 将证书重命名拷贝,并确保路径正确,主要用于xui设置路径350 mkdir -p "/root/cert/$domain"351 cp "/home/$username/$domain.cer" "/root/cert/$domain/fullchain.pem"352 cp "/home/$username/$domain.key" "/root/cert/$domain/privkey.pem"353
354 # 验证证书355 log_info "验证证书..."356 if openssl x509 -in "/home/$username/$domain.cer" -noout -text > /dev/null 2>&1; then357 log_info "证书文件有效"358
359 # 显示证书信息360 log_info "证书有效期:"361 openssl x509 -in "/home/$username/$domain.cer" -noout -dates362
363 log_info "证书包含的域名:"364 openssl x509 -in "/home/$username/$domain.cer" -noout -text | grep -A1 "Subject Alternative Name" || echo " $domain, *.$domain"365 else366 log_warning "证书文件可能有问题,请检查"367 fi368
369 log_success "证书申请完成"370}371
372# Hysteria2服务373# 逐步在Qos,建议搭建reality374handle_hysteria() {375 local username=""376 local password=""377 local domain=""378
379 while [[ $# -gt 0 ]]; do380 case $1 in381 -d | --domain)382 domain="$2"383 shift 2384 ;;385 -p | --port)386 port_hysteria="$2"387 shift 2388 ;;389 -u | --user)390 username="$2"391 shift 2392 ;;393 -w | --pass)394 password="$2"395 shift 2396 ;;397 -h | --help)398 show_command_help "hysteria"399 exit 0400 ;;401 *)402 panic "未知选项: $1"403 ;;404 esac405 done406
407 [[ -z "$domain" ]] && panic "必须指定主域名"408 [[ -z "$username" ]] && panic "必须指定用户名"409 [[ -z "$password" ]] && panic "必须指定密码"410
411 log_info "开始安装Hysteria2服务..."412
413 # 安装Hysteria2414 log_info "安装Hysteria2..."415 bash <(curl -fsSL https://get.hy2.sh/)416
417 # 配置Hysteria2418 log_info "配置Hysteria2..."419
420 cat > /etc/hysteria/config.yaml << EOF421listen: :$port_hysteria422
423tls:424 cert: /home/$(id -un $userid)/$domain.cer425 key: /home/$(id -un $userid)/$domain.key426
427auth:428 type: userpass429 userpass:430 $username: $password431
432masquerade:433 type: proxy434 proxy:435 url: https://bing.com436 rewriteHost: true437 listenHTTP: :80438 listenHTTPS: :$port_hysteria439
440bandwidth:441 up: 20 mbps442 down: 50 mbps443EOF444
445 # 配置端口跳跃446 log_info "配置端口跳跃..."447 ufw allow $port_hysteria_jump_1:$port_hysteria_jump_1_end/udp448 ufw allow $port_hysteria_jump_2:$port_hysteria_jump_2_end/udp449 iptables -t nat -A PREROUTING -i eth0 -p udp --dport $port_hysteria_jump_1:$port_hysteria_jump_1_end -j REDIRECT --to-ports "$port_hysteria"450 iptables -t nat -A PREROUTING -i eth0 -p udp --dport $port_hysteria_jump_2:$port_hysteria_jump_2_end -j REDIRECT --to-ports "$port_hysteria"451 ip6tables -t nat -A PREROUTING -i eth0 -p udp --dport $port_hysteria_jump_1:$port_hysteria_jump_1_end -j REDIRECT --to-ports "$port_hysteria"452 ip6tables -t nat -A PREROUTING -i eth0 -p udp --dport $port_hysteria_jump_2:$port_hysteria_jump_2_end -j REDIRECT --to-ports "$port_hysteria"453
454 ufw allow $port_hysteria455
456 log_info "启动Hysteria2服务..."457 systemctl enable hysteria-server.service --now458
459 log_success "Hysteria2服务安装完成"460}461
462# 3X-UI面板463handle_xui() {464 while [[ $# -gt 0 ]]; do465 case $1 in466 -h | --help)467 show_command_help "xui"468 exit 0469 ;;470 *)471 panic "未知选项: $1"472 ;;473 esac474 done475
476 log_info "开始安装3X-UI面板..."477
478 # 安装X-UI479 log_info "安装3X-UI..."480 bash <(curl -Ls https://raw.githubusercontent.com/MHSanaei/3x-ui/refs/tags/v2.6.0/install.sh)481
482 # 配置X-UI483 log_info "请手动配置3X-UI,或者使用3X-UI备份恢复"484 sleep 2485 x-ui486 log_success "3X-UI面板安装完成,请在 ngninx 反代后,手动完成 ssl 证书路径配置"487}488
489# Sub-Store服务490handle_substore() {491 local api_key=""492
493 while [[ $# -gt 0 ]]; do494 case $1 in495 -a | --api-key)496 api_key="$2"497 shift 2498 ;;499 -h | --help)500 show_command_help "substore"501 exit 0502 ;;503 *)504 panic "未知选项: $1"505 ;;506 esac507 done508
509 [[ -z "$api_key" ]] && panic "必须指定API密钥"510
511 log_info "开始安装Sub-Store服务..."512
513 # 安装依赖514 log_info "安装依赖..."515 apt update -y && apt install unzip curl wget git -y516
517 # 安装FNM518 log_info "安装FNM..."519 curl -fsSL https://fnm.vercel.app/install | bash520 source ~/.bashrc521
522 # 安装Node523 log_info "安装Node..."524 fnm install v20.18.0525
526 # 安装PNPM527 log_info "安装PNPM..."528 curl -fsSL https://get.pnpm.io/install.sh | sh -529 source ~/.bashrc530
531 # 创建目录532 log_info "创建目录..."533 mkdir -p /root/sub-store534 cd /root/sub-store535
536 # 下载Sub-Store537 log_info "下载Sub-Store..."538 curl -fsSL https://github.com/sub-store-org/Sub-Store/releases/latest/download/sub-store.bundle.js -o sub-store.bundle.js539 curl -fsSL https://github.com/sub-store-org/Sub-Store-Front-End/releases/latest/download/dist.zip -o dist.zip540 unzip -o dist.zip && mv dist frontend && rm dist.zip541
542 # 创建服务543 log_info "创建服务..."544 cat > /etc/systemd/system/sub-store.service << EOF545[Unit]546Description=Sub-Store547After=network-online.target548Wants=network-online.target systemd-networkd-wait-online.service549
550[Service]551LimitNOFILE=32767552Type=simple553Environment="SUB_STORE_FRONTEND_BACKEND_PATH=/$api_key"554Environment="SUB_STORE_BACKEND_CRON=0 0 * * *"555Environment="SUB_STORE_FRONTEND_PATH=/root/sub-store/frontend"556Environment="SUB_STORE_FRONTEND_HOST=0.0.0.0"557Environment="SUB_STORE_FRONTEND_PORT=3001"558Environment="SUB_STORE_DATA_BASE_PATH=/root/sub-store"559Environment="SUB_STORE_BACKEND_API_HOST=127.0.0.1"560Environment="SUB_STORE_BACKEND_API_PORT=3000"561ExecStart=/root/.local/share/fnm/fnm exec --using v20.18.0 node /root/sub-store/sub-store.bundle.js562User=root563Group=root564Restart=on-failure565RestartSec=5s566ExecStartPre=/bin/sh -c ulimit -n 51200567StandardOutput=journal568StandardError=journal569
570[Install]571WantedBy=multi-user.target572EOF573
574 # 启动服务575 log_info "启动服务..."576 systemctl enable sub-store.service --now577
578 source /root/.bashrc579 log_success "Sub-Store服务安装完成"580}581
582# Nginx分流配置583handle_nginx() {584 local xui_domain=""585 local substore_domain=""586 local domain=""587 local port_xui=""588
589 while [[ $# -gt 0 ]]; do590 case $1 in591 -d | --domain)592 domain="$2"593 shift 2594 ;;595 -x | --xui-domain)596 xui_domain="$2"597 shift 2598 ;;599 -s | --substore-domain)600 substore_domain="$2"601 shift 2602 ;;603 -p | --port-xui)604 port_xui="$2"605 shift 2606 ;;607 -h | --help)608 show_command_help "nginx"609 exit 0610 ;;611 *)612 panic "未知选项: $1"613 ;;614 esac615 done616
617 [[ -z "$domain" ]] && panic "必须指定主域名"618 [[ -z "$xui_domain" ]] && panic "必须指定X-UI域名"619 [[ -z "$substore_domain" ]] && panic "必须指定Sub-Store域名"620 [[ -z "$port_xui" ]] && panic "必须指定X-UI访问端口"621
622 log_info "开始配置Nginx分流..."623
624 # 安装Nginx625 log_info "安装Nginx..."626 apt install libnginx-mod-stream nginx -y627
628 # 配置Nginx629 log_info "配置Nginx..."630
631 # 修改主配置文件 - 检查是否已经存在 include 语句632 if ! grep -q "include /etc/nginx/vps.conf;" /etc/nginx/nginx.conf; then633 log_info "添加 vps.conf 包含语句到 nginx.conf"634 sudo sed -i '$a\ include /etc/nginx/vps.conf;' /etc/nginx/nginx.conf635 else636 log_info "vps.conf 包含语句已存在,跳过添加"637 fi638
639 # 创建分流配置640 cat > /etc/nginx/vps.conf << EOF641# /etc/nginx/vps.conf642
643stream {644 # 定义一个映射,将 SNI 中的服务器名映射到后端标识符645 map \$ssl_preread_server_name \$backend {646 hostnames;647 $substore_domain sub;648 $xui_domain xui;649 default hysteria; # 默认后端650 }651
652 # 定义各个后端的上游服务器653 upstream sub {654 server 127.0.0.1:8444; # $substore_domain 对应的后端,对接的是 nginx server655 }656
657 upstream xui {658 server 127.0.0.1:$port_xui; # $xui_domain 对应的后端659 }660
661 upstream hysteria {662 server 127.0.0.1:$port_hysteria; # 默认后端663 }664
665 # 定义一个服务器块,监听指定端口并根据 SNI 分发流量666 server {667 listen 443;668 listen [::]:443;669 proxy_pass \${backend};670 ssl_preread on;671 }672}673EOF674
675 # 创建Sub-Store服务器配置676 cat > /etc/nginx/sites-enabled/vps.conf << EOF677server {678 listen 8444 ssl http2;679 listen [::]:8444 ssl http2;680 server_name $substore_domain;681
682 ssl_certificate /home/$(id -un $userid)/$domain.cer;683 ssl_certificate_key /home/$(id -un $userid)/$domain.key;684
685 location / {686 proxy_pass http://127.0.0.1:3001;687 proxy_set_header Host \$host;688 proxy_set_header X-Real-IP \$remote_addr;689 proxy_set_header X-Forwarded-For \$proxy_add_x_forwarded_for;690 }691}692EOF693
694 # 移除默认配置695 rm -f /etc/nginx/sites-enabled/default696
697 # 测试配置698 log_info "测试Nginx配置..."699 nginx -t700
701 # 重启Nginx702 log_info "重启Nginx..."703 systemctl restart nginx704
705 log_success "Nginx分流配置完成"706}707
708##############################################709# 主逻辑 #710##############################################711
712main() {713 [[ $# -eq 0 ]] || [[ "$1" == "--help" ]] && show_help && exit 0714
715 local cmd="$1"716 shift717
718 [[ -n "${COMMAND_MAP[$cmd]}" ]] || panic "未知命令: $cmd"719
720 # 同样地,这里也要避免直接 IFS="::" 分割721 # 先用 '|' 替换 "::" ,再做一次分割即可722 local info="${COMMAND_MAP[$cmd]}"723 info="${info//::/|}"724
725 local desc handler options_str726 IFS="|" read -r desc handler options_str <<<"$info"727
728 # 调用对应的处理函数729 $handler "$@"730}731
732if [ "$EUID" -ne 0 ]; then733 log_warning "请使用 root 用户运行此脚本" >&2734 exit 1735fi736
737main "$@"
1#!/bin/bash2
3#==================================================================4# ██╗ ██╗ ██╗███╗ ██╗██████╗ ██████╗ █████╗5# ██║ ╚██╗ ██╔╝████╗ ██║██╔══██╗██╔══██╗██╔══██╗6# ██║ ╚████╔╝ ██╔██╗ ██║██║ ██║██████╔╝███████║7# ██║ ╚██╔╝ ██║╚██╗██║██║ ██║██╔══██╗██╔══██║8# ███████╗██║ ██║ ╚████║██████╔╝██║ ██║██║ ██║9# ╚══════╝╚═╝ ╚═╝ ╚═══╝╚═════╝ ╚═╝ ╚═╝╚═╝ ╚═╝10#==================================================================11#12# 文件名称: run.sh13# 文件描述: VPS构建脚本14# 运行环境:Debian 系 Linux 系统,Root 用户运行。15# 注意事项:44 collapsed lines
16# 1. 运行前,请运行 build-all.sh --help 查看脚本中的命令含义,以及每个指令的参数含义。17# 2. 尽可能的先修改 build-all.sh 中的配置端口,保证安全(119-141行)。18# 3. 通过Cloudflare申请DNS时,需要确认Cloudflare的api令牌,是否允许了新 vps 的ipv4和ipv6地址。19# 4. 尽可能的使用二级域名,CF的代理功能中,二级域名边缘证书是免费的,但三级域名需要开会员才能用。三级域名签发证书,同时使用代理功能,会导致SSL握手失败。20# 5. XUI提供备份和恢复功能,但是需要注意其SSL证书路径也会被备份,如果新旧机器的证书不一致,将导致无法网页访问,此时需要命令行修改XUI的SSL证书路径。本脚本会自动复制证书到xui的证书路径。21# 6. 对于 xui 上启用的各种协议所需要的端口请手动放行防火墙。22# 7. sub-store 建议开启github的glist备份,网上有很多教程,很简单。新机器可以直接完美同步。23# 作者: Lyndra <lyndra.hyst@gmail.com>24# 版本: 1.0.025# 创建日期: 2025-05-2926# 最后修改: 2025-05-2927# 使用许可: GPLv2 or other licenses28# Copyright (c) 2025 Lyndra29#30#==================================================================31
32echo "运行前请先修改 *build-all.sh* 和 *本脚本* 中的配置信息,确保配置信息正确。"33
34echo "输入 y/Y 确认上述操作已完成,输入 n/N 退出"35read -p "请输入: " confirm36
37if [ "$confirm" != "y" ] && [ "$confirm" != "Y" ]; then38 echo "退出脚本"39 exit 040fi41
42# 创建新用户,请根据实际情况修改用户名和密码43# 密码需要足够复杂,否则创建用户时会失败。44./build-all.sh setup -u username -p password45
46# 申请证书,请根据实际情况修改域名、邮箱、cloudflare的api令牌、cloudflare zone id、cloudflare account id。47# 请确认cloudflare的api令牌,是否允许了新 vps 的ipv4和ipv6地址。48./build-all.sh cert -d 二级域名 -e 邮箱 -t api_token -z zone_id -a account_id49
50# 安装 hysteria2,请根据实际情况修改域名、用户名、密码。51./build-all.sh hysteria -d 二级域名 -u 用户名 -w 密码52
53# 安装 xui,安装过程中请自行配置xui,并记录xui的访问端口54./build-all.sh xui55
56# 安装 sub-store,请修改token,否则可能会被盗取后端信息。57./build-all.sh substore -a custom_token58
59./build-all.sh nginx -d 二级域名 -x xui-域名 -s sub-store-域名 -p x-ui-访问端口