Files
tuic_docker/install.sh
T
2026-05-28 15:30:41 +08:00

300 lines
7.7 KiB
Bash

#!/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
;;
2)
# 生成配置 / 重置配置
create_config
;;
3)
# 查看分享链接
check_config_file "$CONFIG_FILE"
print_share_link
;;
4)
# 启动
check_config_file "$CONFIG_FILE"
port_manage allow $(get_listen_port "$CONFIG_FILE") # 开放端口
run
print_share_link
;;
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
port_manage allow $(get_listen_port) # 开放端口
restart_docker
;;
8)
# 更新镜像
update_docker_images
restart_docker
;;
9)
# 更新脚本
git pull
;;
10)
# 开启BBR加速
enable_kernel_bbr
;;
*)
echo "无效的选择, 请重新选择."
;;
esac
}
main