#!/bin/bash # 导入依赖脚本文件 BASE_DIR="$(cd "$(dirname "$0")" && pwd)" for f in "$BASE_DIR"/bin/utils/*.sh; do [ -f "$f" ] && source "$f" done for f in "$BASE_DIR"/bin/*.sh; do [ -f "$f" ] && source "$f" done install(){ if ! command -v curl >/dev/null 2>&1; then install_package curl fi if ! command -v wget >/dev/null 2>&1; then install_package wget fi if ! command -v openssl >/dev/null 2>&1; then install_package openssl fi if ! command -v jq >/dev/null 2>&1; then install_package jq fi if ! command -v docker >/dev/null 2>&1; then echo 安装docker... sleep 1 curl -fsSL https://get.docker.com | bash -s docker fi } # 查询运行状态 check_container_status(){ local compose_file="./docker-compose.yml" local GREEN='\033[0;32m' local RED='\033[0;31m' local RESET='\033[0m' local status status=$(docker compose -f "$compose_file" ps --status running --quiet 2>/dev/null) if [ -n "$status" ]; then echo -e "${GREEN}运行中${RESET}" else echo -e "${RED}未运行${RESET}" fi } # 修改域名 ask_update_domain(){ local CONFIG_FILE="${1}" # 检查jq是否安装 check_jq # 获取旧的domain local OLD_DOMAIN=$(jq -r ".inbounds[0].tls.server_name" "$CONFIG_FILE") # 输入新的domain local DOMAIN read -p "请输入域名[当前域名: $OLD_DOMAIN]: " DOMAIN # 如果输入为空,退出脚本 if [[ -z "$DOMAIN" ]]; then echo "输入域名为空,退出脚本" exit 1 fi # 修改server_name update_server_name "$CONFIG_FILE" "$DOMAIN" # 是否存在acme域名, 存在则修改 if is_config_use_acme "$CONFIG_FILE"; then update_acme_domain "$CONFIG_FILE" "$DOMAIN" fi echo "修改域名成功" } # 检查配置文件 check_config_file(){ local CONFIG_FILE="${1}" # 配置文件 # 检查配置文件是否存在 if [ ! -e "$CONFIG_FILE" ]; then echo "配置文件不存在, 请先生成配置文件." exit 1 fi # 检查配置文件是否为有效的JSON格式 if ! jq '.' "$CONFIG_FILE" >/dev/null 2>&1; then echo "配置文件不是有效的JSON格式, 请重新生成配置文件." exit 1 fi } # 创建配置文件 create_config(){ local SCRIPT_DIR="$(cd "$(dirname "${BASH_SOURCE[0]}")" && pwd)/bin" # 脚本文件夹绝对路径 local CONFIG_FILE="$SCRIPT_DIR/../config/config.json" # 如果配置文件已存在,提示用户是否重新生成 if [ -e "$CONFIG_FILE" ]; then local REGENERATE read -p "检测到配置已存在,是否重新生成配置?(y/n): " REGENERATE if [ "$REGENERATE" != "y" ] && [ "$REGENERATE" != "Y" ]; then echo "取消重新生成配置." return fi fi echo "请选择配置类型:" echo "1. Tuic" echo "2. Hysteria" local CHOICE read -p "输入您的选择: " CHOICE case $CHOICE in 1) create_tuic_config ;; 2) create_hysteria_config ;; *) echo "无效的选择, 请重新选择." ;; esac } enable_kernel_bbr(){ if [ "$(id -u)" -ne 0 ]; then echo "请使用 root 权限运行该操作" return 1 fi # 检测容器环境 local virt_type="" if command -v systemd-detect-virt >/dev/null 2>&1; then virt_type=$(systemd-detect-virt 2>/dev/null) fi case "$virt_type" in lxc|openvz|docker|podman|container-other) echo "检测到当前运行于容器环境: $virt_type" echo "请在宿主机开启 BBR" return 1 ;; esac if [ "$(sysctl -n net.ipv4.tcp_congestion_control 2>/dev/null)" = "bbr" ]; then echo "BBR加速 已经开启,无需重复操作" return 0 fi # 尝试加载 bbr 模块(新内核可能已内建) if command -v modprobe >/dev/null 2>&1; then modprobe tcp_bbr 2>/dev/null || true fi # 检查内核是否支持 BBR if ! sysctl net.ipv4.tcp_available_congestion_control 2>/dev/null | grep -qw bbr; then echo "当前系统内核不支持 BBR" return 1 fi set_sysctl_conf(){ local key="$1" local value="$2" local file="/etc/sysctl.conf" touch "$file" # 转义 key,避免 . 被 grep/sed 当作正则 local escaped_key escaped_key=$(printf '%s\n' "$key" | sed 's/[.[\*^$()+?{|]/\\&/g') if grep -qE "^[[:space:]]*#?[[:space:]]*$escaped_key[[:space:]]*=" "$file"; then sed -i "s|^[[:space:]]*#\?[[:space:]]*$escaped_key[[:space:]]*=.*|$key = $value|" "$file" else echo "$key = $value" >> "$file" fi } # 写入配置 set_sysctl_conf "net.core.default_qdisc" "fq" set_sysctl_conf "net.ipv4.tcp_congestion_control" "bbr" # 立即生效 sysctl -w net.core.default_qdisc=fq >/dev/null 2>&1 sysctl -w net.ipv4.tcp_congestion_control=bbr >/dev/null 2>&1 # 验证是否成功 if [ "$(sysctl -n net.ipv4.tcp_congestion_control 2>/dev/null)" = "bbr" ]; then echo "BBR加速 已开启" else echo "BBR开启失败" return 1 fi } main(){ local SCRIPT_DIR="$(cd "$(dirname "${BASH_SOURCE[0]}")" && pwd)/bin" # 脚本文件夹绝对路径 local CONFIG_FILE="$SCRIPT_DIR/../config/config.json" local container_status=$(check_container_status) # 显示菜单 echo "" echo 运行状态: $container_status echo "==============================" echo "请选择一个操作:" echo "1. 一键部署" echo "2. 生成配置 / 重置配置" echo "3. 查看分享链接" echo "4. 启动" echo "5. 停止" echo "6. 修改域名" echo "7. 修改端口" echo "8. 更新镜像" echo "9. 更新脚本" echo "10. 开启BBR加速" # 读取用户选择 local choice read -p "输入您的选择: " choice # 根据用户选择执行相应的操作 case $choice in 1) # 一键部署 install create_config port_manage allow $(get_listen_port "$CONFIG_FILE") # 开放端口 run print_share_link "$CONFIG_FILE" ;; 2) # 生成配置 / 重置配置 create_config ;; 3) # 查看分享链接 check_config_file "$CONFIG_FILE" print_share_link "$CONFIG_FILE" ;; 4) # 启动 check_config_file "$CONFIG_FILE" port_manage allow $(get_listen_port "$CONFIG_FILE") # 开放端口 run print_share_link "$CONFIG_FILE" ;; 5) # 停止 if echo "$container_status" | grep -q "未运行"; then echo "程序已停止" return fi docker compose -f ./docker-compose.yml down ;; 6) # 修改域名 check_config_file "$CONFIG_FILE" ask_update_domain "$CONFIG_FILE" restart_docker ;; 7) # 修改端口 check_config_file "$CONFIG_FILE" ask_update_port "$CONFIG_FILE" port_manage allow $(get_listen_port "$CONFIG_FILE") # 开放端口 restart_docker ;; 8) # 更新镜像 update_docker_images restart_docker ;; 9) # 更新脚本 git pull ;; 10) # 开启BBR加速 enable_kernel_bbr ;; *) echo "无效的选择, 请重新选择." ;; esac } main