2023-07-29 12:09:39 +08:00
|
|
|
|
#!/bin/bash
|
|
|
|
|
|
|
|
|
|
# 定义颜色变量
|
|
|
|
|
RED='\033[0;31m'
|
|
|
|
|
CYAN='\033[0;36m'
|
|
|
|
|
NC='\033[0m' # No Color
|
|
|
|
|
|
|
|
|
|
# 根据系统版本自动安装依赖
|
|
|
|
|
function install_dependencies() {
|
2023-07-27 18:18:35 +08:00
|
|
|
|
local os_version
|
|
|
|
|
os_version=$(lsb_release -si 2>/dev/null)
|
|
|
|
|
|
|
|
|
|
local dependencies
|
|
|
|
|
local common_dependencies="wget tar socat jq git openssl"
|
|
|
|
|
|
|
|
|
|
case "$os_version" in
|
|
|
|
|
Debian|Ubuntu)
|
|
|
|
|
dependencies="$common_dependencies uuid-runtime build-essential zlib1g-dev libssl-dev libevent-dev"
|
|
|
|
|
;;
|
|
|
|
|
CentOS)
|
|
|
|
|
dependencies="$common_dependencies util-linux gcc-c++ zlib-devel openssl-devel libevent-devel"
|
|
|
|
|
;;
|
|
|
|
|
*)
|
2023-07-29 12:09:39 +08:00
|
|
|
|
echo -e "${RED}不支持的操作系统: $os_version${NC}"
|
2023-07-27 18:18:35 +08:00
|
|
|
|
exit 1
|
|
|
|
|
;;
|
|
|
|
|
esac
|
|
|
|
|
|
|
|
|
|
if ! command -v apt-get &> /dev/null && ! command -v dnf &> /dev/null && ! command -v yum &> /dev/null; then
|
2023-07-29 12:09:39 +08:00
|
|
|
|
echo -e "${RED}不支持的包管理器,无法继续安装依赖。${NC}"
|
2023-07-27 18:18:35 +08:00
|
|
|
|
exit 1
|
|
|
|
|
fi
|
|
|
|
|
|
|
|
|
|
echo "更新软件包列表..."
|
|
|
|
|
if command -v apt-get &> /dev/null; then
|
|
|
|
|
apt-get update
|
|
|
|
|
elif command -v dnf &> /dev/null; then
|
|
|
|
|
dnf makecache
|
|
|
|
|
elif command -v yum &> /dev/null; then
|
|
|
|
|
yum makecache
|
|
|
|
|
fi
|
|
|
|
|
|
|
|
|
|
echo "下载并安装依赖..."
|
|
|
|
|
if command -v apt-get &> /dev/null; then
|
|
|
|
|
apt-get install -y $dependencies
|
|
|
|
|
elif command -v dnf &> /dev/null; then
|
|
|
|
|
dnf install -y $dependencies
|
|
|
|
|
elif command -v yum &> /dev/null; then
|
|
|
|
|
yum install -y $dependencies
|
|
|
|
|
fi
|
|
|
|
|
|
|
|
|
|
echo "依赖已安装。"
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
# 检查防火墙配置
|
|
|
|
|
function check_firewall_configuration() {
|
|
|
|
|
local os_name=$(uname -s)
|
|
|
|
|
local firewall
|
|
|
|
|
|
|
|
|
|
if [[ $os_name == "Linux" ]]; then
|
|
|
|
|
if command -v ufw >/dev/null 2>&1 && ufw status | grep -q "Status: active"; then
|
|
|
|
|
firewall="ufw"
|
|
|
|
|
elif command -v iptables >/dev/null 2>&1 && iptables -S | grep -q "INPUT -j DROP"; then
|
|
|
|
|
firewall="iptables"
|
|
|
|
|
elif command -v firewalld >/dev/null 2>&1 && firewall-cmd --state | grep -q "running"; then
|
|
|
|
|
firewall="firewalld"
|
|
|
|
|
fi
|
|
|
|
|
fi
|
|
|
|
|
|
|
|
|
|
if [[ -z $firewall ]]; then
|
|
|
|
|
echo "未检测到防火墙配置或防火墙未启用,跳过配置防火墙。"
|
|
|
|
|
return
|
|
|
|
|
fi
|
|
|
|
|
|
|
|
|
|
echo "检查防火墙配置..."
|
|
|
|
|
case $firewall in
|
|
|
|
|
ufw)
|
|
|
|
|
if ! ufw status | grep -q "Status: active"; then
|
|
|
|
|
ufw enable
|
|
|
|
|
fi
|
|
|
|
|
|
|
|
|
|
if ! ufw status | grep -q " $listen_port"; then
|
|
|
|
|
ufw allow "$listen_port"
|
|
|
|
|
fi
|
|
|
|
|
|
|
|
|
|
if ! ufw status | grep -q " $override_port"; then
|
|
|
|
|
ufw allow "$override_port"
|
|
|
|
|
fi
|
|
|
|
|
|
|
|
|
|
if ! ufw status | grep -q " 80"; then
|
|
|
|
|
ufw allow 80
|
|
|
|
|
fi
|
|
|
|
|
|
|
|
|
|
echo "防火墙配置已更新。"
|
|
|
|
|
;;
|
|
|
|
|
iptables)
|
|
|
|
|
if ! iptables -C INPUT -p tcp --dport "$listen_port" -j ACCEPT >/dev/null 2>&1; then
|
|
|
|
|
iptables -A INPUT -p tcp --dport "$listen_port" -j ACCEPT
|
|
|
|
|
fi
|
|
|
|
|
|
|
|
|
|
if ! iptables -C INPUT -p udp --dport "$listen_port" -j ACCEPT >/dev/null 2>&1; then
|
|
|
|
|
iptables -A INPUT -p udp --dport "$listen_port" -j ACCEPT
|
|
|
|
|
fi
|
|
|
|
|
|
|
|
|
|
if ! iptables -C INPUT -p tcp --dport "$override_port" -j ACCEPT >/dev/null 2>&1; then
|
|
|
|
|
iptables -A INPUT -p tcp --dport "$override_port" -j ACCEPT
|
|
|
|
|
fi
|
|
|
|
|
|
|
|
|
|
if ! iptables -C INPUT -p udp --dport "$override_port" -j ACCEPT >/dev/null 2>&1; then
|
|
|
|
|
iptables -A INPUT -p udp --dport "$override_port" -j ACCEPT
|
|
|
|
|
fi
|
|
|
|
|
|
|
|
|
|
if ! iptables -C INPUT -p tcp --dport 80 -j ACCEPT >/dev/null 2>&1; then
|
|
|
|
|
iptables -A INPUT -p tcp --dport 80 -j ACCEPT
|
|
|
|
|
fi
|
|
|
|
|
|
|
|
|
|
if ! iptables -C INPUT -p udp --dport 80 -j ACCEPT >/dev/null 2>&1; then
|
|
|
|
|
iptables -A INPUT -p udp --dport 80 -j ACCEPT
|
|
|
|
|
fi
|
|
|
|
|
|
|
|
|
|
iptables-save > /etc/sysconfig/iptables
|
|
|
|
|
|
|
|
|
|
echo "iptables防火墙配置已更新。"
|
|
|
|
|
;;
|
|
|
|
|
firewalld)
|
|
|
|
|
if ! firewall-cmd --zone=public --list-ports | grep -q "$listen_port/tcp"; then
|
|
|
|
|
firewall-cmd --zone=public --add-port="$listen_port/tcp" --permanent
|
|
|
|
|
fi
|
|
|
|
|
|
|
|
|
|
if ! firewall-cmd --zone=public --list-ports | grep -q "$listen_port/udp"; then
|
|
|
|
|
firewall-cmd --zone=public --add-port="$listen_port/udp" --permanent
|
|
|
|
|
fi
|
|
|
|
|
|
|
|
|
|
if ! firewall-cmd --zone=public --list-ports | grep -q "$override_port/tcp"; then
|
|
|
|
|
firewall-cmd --zone=public --add-port="$override_port/tcp" --permanent
|
|
|
|
|
fi
|
|
|
|
|
|
|
|
|
|
if ! firewall-cmd --zone=public --list-ports | grep -q "$override_port/udp"; then
|
|
|
|
|
firewall-cmd --zone=public --add-port="$override_port/udp" --permanent
|
|
|
|
|
fi
|
|
|
|
|
|
|
|
|
|
if ! firewall-cmd --zone=public --list-ports | grep -q "80/tcp"; then
|
|
|
|
|
firewall-cmd --zone=public --add-port=80/tcp --permanent
|
|
|
|
|
fi
|
|
|
|
|
|
|
|
|
|
if ! firewall-cmd --zone=public --list-ports | grep -q "80/udp"; then
|
|
|
|
|
firewall-cmd --zone=public --add-port=80/udp --permanent
|
|
|
|
|
fi
|
|
|
|
|
|
|
|
|
|
firewall-cmd --reload
|
|
|
|
|
|
|
|
|
|
echo "firewalld防火墙配置已更新。"
|
|
|
|
|
;;
|
|
|
|
|
esac
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
# 检查 sing-box 文件夹是否存在,如果不存在则创建
|
|
|
|
|
function check_sing_box_folder() {
|
|
|
|
|
local folder="/usr/local/etc/sing-box"
|
|
|
|
|
if [[ ! -d "$folder" ]]; then
|
|
|
|
|
mkdir -p "$folder"
|
|
|
|
|
fi
|
|
|
|
|
}
|
|
|
|
|
|
2023-07-29 12:09:39 +08:00
|
|
|
|
# 检查 caddy 文件夹是否存在,如果不存在则创建
|
|
|
|
|
function check_caddy_folder() {
|
|
|
|
|
local folder="/usr/local/etc/caddy"
|
|
|
|
|
if [[ ! -d "$folder" ]]; then
|
|
|
|
|
mkdir -p "$folder"
|
|
|
|
|
fi
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
# 创建文件目录
|
|
|
|
|
function create_tuic_directory() {
|
|
|
|
|
local tuic_directory="/usr/local/etc/tuic"
|
|
|
|
|
local ssl_directory="/etc/ssl/private"
|
|
|
|
|
|
|
|
|
|
if [[ ! -d "$tuic_directory" ]]; then
|
|
|
|
|
mkdir -p "$tuic_directory"
|
|
|
|
|
fi
|
|
|
|
|
|
|
|
|
|
if [[ ! -d "$ssl_directory" ]]; then
|
|
|
|
|
mkdir -p "$ssl_directory"
|
|
|
|
|
fi
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
# 开启 BBR
|
2023-07-27 18:18:35 +08:00
|
|
|
|
enable_bbr() {
|
|
|
|
|
if ! grep -q "net.core.default_qdisc=fq" /etc/sysctl.conf; then
|
|
|
|
|
echo "开启 BBR..."
|
|
|
|
|
echo "net.core.default_qdisc=fq" >> /etc/sysctl.conf
|
|
|
|
|
echo "net.ipv4.tcp_congestion_control=bbr" >> /etc/sysctl.conf
|
|
|
|
|
sysctl -p
|
|
|
|
|
echo "BBR 已开启"
|
|
|
|
|
else
|
|
|
|
|
echo "BBR 已经开启,跳过配置。"
|
|
|
|
|
fi
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
# 选择安装方式
|
|
|
|
|
function select_sing_box_install_option() {
|
|
|
|
|
while true; do
|
|
|
|
|
echo "请选择 sing-box 的安装方式:"
|
|
|
|
|
echo " [1]. 编译安装sing-box(支持全部功能)"
|
|
|
|
|
echo " [2]. 下载安装sing-box(支持部分功能)"
|
|
|
|
|
|
|
|
|
|
local install_option
|
|
|
|
|
read -p "请选择 [1-2]: " install_option
|
|
|
|
|
|
|
|
|
|
case $install_option in
|
|
|
|
|
1)
|
|
|
|
|
install_go
|
|
|
|
|
compile_install_sing_box
|
|
|
|
|
break
|
|
|
|
|
;;
|
|
|
|
|
2)
|
|
|
|
|
install_latest_sing_box
|
|
|
|
|
break
|
|
|
|
|
;;
|
|
|
|
|
*)
|
2023-07-29 12:09:39 +08:00
|
|
|
|
echo -e "${RED}无效的选择,请重新输入。${NC}"
|
2023-07-27 18:18:35 +08:00
|
|
|
|
;;
|
|
|
|
|
esac
|
|
|
|
|
done
|
|
|
|
|
}
|
|
|
|
|
|
2023-07-29 12:09:39 +08:00
|
|
|
|
# 检查并安装 Go
|
2023-07-27 18:18:35 +08:00
|
|
|
|
install_go() {
|
|
|
|
|
if ! command -v go &> /dev/null; then
|
|
|
|
|
echo "下载并安装 Go..."
|
|
|
|
|
local go_arch
|
|
|
|
|
case $(uname -m) in
|
|
|
|
|
x86_64)
|
|
|
|
|
go_arch="amd64"
|
|
|
|
|
;;
|
|
|
|
|
i686)
|
|
|
|
|
go_arch="386"
|
|
|
|
|
;;
|
|
|
|
|
aarch64)
|
|
|
|
|
go_arch="arm64"
|
|
|
|
|
;;
|
|
|
|
|
armv6l)
|
|
|
|
|
go_arch="armv6l"
|
|
|
|
|
;;
|
|
|
|
|
*)
|
2023-07-29 12:09:39 +08:00
|
|
|
|
echo -e "${RED}不支持的架构: $(uname -m)${NC}"
|
2023-07-27 18:18:35 +08:00
|
|
|
|
exit 1
|
|
|
|
|
;;
|
|
|
|
|
esac
|
|
|
|
|
|
|
|
|
|
# 获取最新版本的 Go 下载链接
|
|
|
|
|
local go_version
|
|
|
|
|
go_version=$(curl -sL "https://golang.org/VERSION?m=text")
|
|
|
|
|
local go_download_url="https://go.dev/dl/$go_version.linux-$go_arch.tar.gz"
|
|
|
|
|
|
|
|
|
|
wget -c "$go_download_url" -O - | tar -xz -C /usr/local
|
|
|
|
|
echo 'export PATH=$PATH:/usr/local/go/bin' | tee -a /etc/profile
|
|
|
|
|
source /etc/profile
|
|
|
|
|
go version
|
|
|
|
|
|
|
|
|
|
echo "Go 已安装"
|
|
|
|
|
else
|
|
|
|
|
echo "Go 已经安装,跳过安装步骤。"
|
|
|
|
|
fi
|
|
|
|
|
}
|
|
|
|
|
|
2023-07-29 12:09:39 +08:00
|
|
|
|
# 编译安装sing-box
|
2023-07-27 18:18:35 +08:00
|
|
|
|
function compile_install_sing_box() {
|
|
|
|
|
local go_install_command="go install -v -tags \
|
|
|
|
|
with_quic,\
|
|
|
|
|
with_grpc,\
|
|
|
|
|
with_dhcp,\
|
|
|
|
|
with_wireguard,\
|
|
|
|
|
with_shadowsocksr,\
|
|
|
|
|
with_ech,\
|
|
|
|
|
with_utls,\
|
|
|
|
|
with_reality_server,\
|
|
|
|
|
with_acme,\
|
|
|
|
|
with_clash_api,\
|
|
|
|
|
with_v2ray_api,\
|
|
|
|
|
with_gvisor,\
|
|
|
|
|
with_lwip \
|
|
|
|
|
github.com/sagernet/sing-box/cmd/sing-box@latest"
|
|
|
|
|
|
|
|
|
|
echo "正在编译安装 sing-box,请稍候..."
|
|
|
|
|
$go_install_command
|
|
|
|
|
|
|
|
|
|
if [[ $? -eq 0 ]]; then
|
|
|
|
|
mv ~/go/bin/sing-box /usr/local/bin/
|
|
|
|
|
chmod +x /usr/local/bin/sing-box
|
|
|
|
|
echo "sing-box 编译安装成功"
|
|
|
|
|
else
|
2023-07-29 12:09:39 +08:00
|
|
|
|
echo -e "${RED}sing-box 编译安装失败${NC}"
|
2023-07-27 18:18:35 +08:00
|
|
|
|
exit 1
|
|
|
|
|
fi
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
# 下载并安装最新的 Sing-Box 版本
|
|
|
|
|
function install_latest_sing_box() {
|
|
|
|
|
local arch=$(uname -m)
|
|
|
|
|
local url="https://api.github.com/repos/SagerNet/sing-box/releases/latest"
|
|
|
|
|
local download_url
|
|
|
|
|
|
|
|
|
|
# 根据 VPS 架构确定合适的下载 URL
|
|
|
|
|
case $arch in
|
|
|
|
|
x86_64)
|
|
|
|
|
download_url=$(curl -s $url | grep -o "https://github.com[^\"']*linux-amd64.tar.gz")
|
|
|
|
|
;;
|
|
|
|
|
armv7l)
|
|
|
|
|
download_url=$(curl -s $url | grep -o "https://github.com[^\"']*linux-armv7.tar.gz")
|
|
|
|
|
;;
|
|
|
|
|
aarch64)
|
|
|
|
|
download_url=$(curl -s $url | grep -o "https://github.com[^\"']*linux-arm64.tar.gz")
|
|
|
|
|
;;
|
|
|
|
|
amd64v3)
|
|
|
|
|
download_url=$(curl -s $url | grep -o "https://github.com[^\"']*linux-amd64v3.tar.gz")
|
|
|
|
|
;;
|
|
|
|
|
*)
|
|
|
|
|
echo -e "${RED}不支持的架构:$arch${NC}"
|
|
|
|
|
return 1
|
|
|
|
|
;;
|
|
|
|
|
esac
|
|
|
|
|
|
|
|
|
|
# 下载并安装 Sing-Box
|
|
|
|
|
if [ -n "$download_url" ]; then
|
|
|
|
|
echo "正在下载 Sing-Box..."
|
|
|
|
|
curl -L -o sing-box.tar.gz "$download_url"
|
|
|
|
|
tar -xzf sing-box.tar.gz -C /usr/local/bin --strip-components=1
|
|
|
|
|
rm sing-box.tar.gz
|
|
|
|
|
|
|
|
|
|
# 赋予可执行权限
|
|
|
|
|
chmod +x /usr/local/bin/sing-box
|
|
|
|
|
|
|
|
|
|
echo "Sing-Box 安装成功!"
|
|
|
|
|
else
|
|
|
|
|
echo -e "${RED}无法获取 Sing-Box 的下载 URL。${NC}"
|
|
|
|
|
return 1
|
|
|
|
|
fi
|
|
|
|
|
}
|
|
|
|
|
|
2023-07-29 12:09:39 +08:00
|
|
|
|
# 编译安装 Caddy
|
|
|
|
|
install_caddy() {
|
|
|
|
|
# 安装 xcaddy 工具
|
|
|
|
|
echo "安装 xcaddy..."
|
|
|
|
|
go install github.com/caddyserver/xcaddy/cmd/xcaddy@latest
|
|
|
|
|
|
|
|
|
|
# 编译安装 Caddy
|
|
|
|
|
~/go/bin/xcaddy build --with github.com/caddyserver/forwardproxy@caddy2=github.com/klzgrad/forwardproxy@naive
|
|
|
|
|
|
|
|
|
|
# 添加网络绑定权限
|
|
|
|
|
setcap cap_net_bind_service=+ep ./caddy
|
|
|
|
|
|
|
|
|
|
# 移动 Caddy 到 /usr/bin/
|
|
|
|
|
mv caddy /usr/bin/
|
|
|
|
|
|
|
|
|
|
echo "Caddy 安装完成。"
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
# 自动获取并下载最新版的 TUIC 程序
|
|
|
|
|
download_tuic() {
|
|
|
|
|
local repo="EAimTY/tuic"
|
|
|
|
|
local arch=$(uname -m)
|
|
|
|
|
|
|
|
|
|
case "$arch" in
|
|
|
|
|
x86_64)
|
|
|
|
|
arch="x86_64-unknown-linux-gnu"
|
|
|
|
|
;;
|
|
|
|
|
i686)
|
|
|
|
|
arch="i686-unknown-linux-gnu"
|
|
|
|
|
;;
|
|
|
|
|
aarch64)
|
|
|
|
|
arch="aarch64-unknown-linux-gnu"
|
|
|
|
|
;;
|
|
|
|
|
armv7l)
|
|
|
|
|
arch="armv7-unknown-linux-gnueabihf"
|
|
|
|
|
;;
|
|
|
|
|
*)
|
|
|
|
|
echo -e "${RED}不支持的架构: $arch${NC}"
|
|
|
|
|
exit 1
|
|
|
|
|
;;
|
|
|
|
|
esac
|
|
|
|
|
|
|
|
|
|
local releases_url="https://api.github.com/repos/$repo/releases/latest"
|
|
|
|
|
local download_url=$(curl -sL "$releases_url" | grep -Eo "https://github.com/[^[:space:]]+/releases/download/[^[:space:]]+$arch" | head -1)
|
|
|
|
|
|
|
|
|
|
if [ -z "$download_url" ]; then
|
|
|
|
|
echo -e "${RED}获取最新版 TUIC 程序下载链接失败。${NC}"
|
|
|
|
|
exit 1
|
|
|
|
|
fi
|
|
|
|
|
|
|
|
|
|
echo "正在下载最新版 TUIC 程序..."
|
|
|
|
|
wget -qO /usr/local/bin/tuic "$download_url"
|
|
|
|
|
|
|
|
|
|
if [ $? -ne 0 ]; then
|
|
|
|
|
echo -e "${RED}下载 TUIC 程序失败。${NC}"
|
|
|
|
|
exit 1
|
|
|
|
|
fi
|
|
|
|
|
|
|
|
|
|
# 赋予可执行权限
|
|
|
|
|
chmod +x /usr/local/bin/tuic
|
|
|
|
|
|
|
|
|
|
echo "TUIC 程序下载并安装完成。"
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
# 配置 sing-box 自启动服务
|
2023-07-27 18:18:35 +08:00
|
|
|
|
function configure_sing_box_service() {
|
|
|
|
|
echo "配置 sing-box 开机自启服务..."
|
|
|
|
|
local service_file="/etc/systemd/system/sing-box.service"
|
|
|
|
|
|
|
|
|
|
if [[ -f $service_file ]]; then
|
|
|
|
|
rm "$service_file"
|
|
|
|
|
fi
|
|
|
|
|
|
|
|
|
|
local service_config='[Unit]
|
|
|
|
|
Description=sing-box service
|
|
|
|
|
Documentation=https://sing-box.sagernet.org
|
|
|
|
|
After=network.target nss-lookup.target
|
|
|
|
|
|
|
|
|
|
[Service]
|
|
|
|
|
CapabilityBoundingSet=CAP_NET_ADMIN CAP_NET_BIND_SERVICE
|
|
|
|
|
AmbientCapabilities=CAP_NET_ADMIN CAP_NET_BIND_SERVICE
|
|
|
|
|
ExecStart=/usr/local/bin/sing-box run -c /usr/local/etc/sing-box/config.json
|
|
|
|
|
Restart=on-failure
|
|
|
|
|
RestartSec=1800s
|
|
|
|
|
LimitNOFILE=infinity
|
|
|
|
|
|
|
|
|
|
[Install]
|
|
|
|
|
WantedBy=multi-user.target'
|
|
|
|
|
|
|
|
|
|
echo "$service_config" >"$service_file"
|
|
|
|
|
echo "sing-box 开机自启动服务已配置。"
|
|
|
|
|
}
|
|
|
|
|
|
2023-07-29 12:09:39 +08:00
|
|
|
|
# 配置 Caddy 自启动服务
|
|
|
|
|
configure_caddy_service() {
|
|
|
|
|
echo "配置 Caddy 开机自启动服务..."
|
|
|
|
|
local service_file="/etc/systemd/system/caddy.service"
|
2023-07-28 11:28:46 +08:00
|
|
|
|
|
2023-07-29 12:09:39 +08:00
|
|
|
|
if [[ -f $service_file ]]; then
|
|
|
|
|
rm "$service_file"
|
|
|
|
|
fi
|
2023-07-27 18:18:35 +08:00
|
|
|
|
|
2023-07-29 12:09:39 +08:00
|
|
|
|
local service_config='[Unit]
|
|
|
|
|
Description=Caddy
|
|
|
|
|
Documentation=https://caddyserver.com/docs/
|
|
|
|
|
After=network.target network-online.target
|
|
|
|
|
Requires=network-online.target
|
2023-07-27 18:18:35 +08:00
|
|
|
|
|
2023-07-29 12:09:39 +08:00
|
|
|
|
[Service]
|
|
|
|
|
Type=notify
|
|
|
|
|
ExecStart=/usr/bin/caddy run --environ --config /usr/local/etc/caddy/caddy.json
|
|
|
|
|
ExecReload=/usr/bin/caddy reload --config /usr/local/etc/caddy/caddy.json
|
|
|
|
|
TimeoutStopSec=5s
|
|
|
|
|
LimitNOFILE=1048576
|
|
|
|
|
LimitNPROC=512
|
|
|
|
|
PrivateTmp=true
|
|
|
|
|
ProtectSystem=full
|
|
|
|
|
AmbientCapabilities=CAP_NET_BIND_SERVICE
|
2023-07-27 18:18:35 +08:00
|
|
|
|
|
2023-07-29 12:09:39 +08:00
|
|
|
|
[Install]
|
|
|
|
|
WantedBy=multi-user.target'
|
|
|
|
|
|
|
|
|
|
echo "$service_config" >"$service_file"
|
|
|
|
|
echo "Caddy 开机自启动服务已配置。"
|
2023-07-27 18:18:35 +08:00
|
|
|
|
}
|
|
|
|
|
|
2023-07-29 12:09:39 +08:00
|
|
|
|
# 配置 tuic 自启动服务
|
|
|
|
|
function configure_tuic_service() {
|
|
|
|
|
echo "配置TUIC开机自启服务..."
|
|
|
|
|
local service_file="/etc/systemd/system/tuic.service"
|
2023-07-27 18:18:35 +08:00
|
|
|
|
|
2023-07-29 12:09:39 +08:00
|
|
|
|
if [[ -f $service_file ]]; then
|
|
|
|
|
rm "$service_file"
|
2023-07-27 18:18:35 +08:00
|
|
|
|
fi
|
2023-07-29 12:09:39 +08:00
|
|
|
|
|
|
|
|
|
local service_config='[Unit]
|
|
|
|
|
Description=tuic service
|
|
|
|
|
Documentation=https://github.com/EAimTY/tuic
|
|
|
|
|
After=network.target nss-lookup.target
|
2023-07-28 11:28:46 +08:00
|
|
|
|
|
2023-07-29 12:09:39 +08:00
|
|
|
|
[Service]
|
|
|
|
|
User=root
|
|
|
|
|
WorkingDirectory=/usr/local/etc/tuic/
|
|
|
|
|
CapabilityBoundingSet=CAP_NET_ADMIN CAP_NET_BIND_SERVICE CAP_NET_RAW
|
|
|
|
|
AmbientCapabilities=CAP_NET_ADMIN CAP_NET_BIND_SERVICE CAP_NET_RAW
|
|
|
|
|
ExecStart=/usr/local/bin/tuic -c /usr/local/etc/tuic/config.json
|
|
|
|
|
Restart=on-failure
|
|
|
|
|
RestartSec=10
|
|
|
|
|
LimitNOFILE=infinity
|
2023-07-27 18:18:35 +08:00
|
|
|
|
|
2023-07-29 12:09:39 +08:00
|
|
|
|
[Install]
|
|
|
|
|
WantedBy=multi-user.target'
|
2023-07-27 18:18:35 +08:00
|
|
|
|
|
2023-07-29 12:09:39 +08:00
|
|
|
|
echo "$service_config" >"$service_file"
|
|
|
|
|
echo "TUIC 开机自启动服务已配置。"
|
|
|
|
|
}
|
2023-07-27 18:18:35 +08:00
|
|
|
|
|
2023-07-29 12:09:39 +08:00
|
|
|
|
# 设置监听端口
|
|
|
|
|
function set_listen_port() {
|
|
|
|
|
while true; do
|
|
|
|
|
read -p "请输入监听端口 (默认443): " listen_port
|
|
|
|
|
listen_port=${listen_port:-443}
|
2023-07-27 18:18:35 +08:00
|
|
|
|
|
2023-07-29 12:09:39 +08:00
|
|
|
|
if [[ $listen_port =~ ^[1-9][0-9]{0,4}$ && $listen_port -le 65535 ]]; then
|
|
|
|
|
echo "监听端口设置成功:$listen_port"
|
2023-07-27 18:18:35 +08:00
|
|
|
|
break
|
2023-07-29 12:09:39 +08:00
|
|
|
|
else
|
|
|
|
|
echo -e "${RED}错误:监听端口范围必须在1-65535之间,请重新输入。${NC}"
|
2023-07-27 18:18:35 +08:00
|
|
|
|
fi
|
|
|
|
|
done
|
2023-07-29 12:09:39 +08:00
|
|
|
|
}
|
2023-07-28 11:28:46 +08:00
|
|
|
|
|
2023-07-29 12:09:39 +08:00
|
|
|
|
# 设置目标地址
|
|
|
|
|
function Direct_override_address() {
|
|
|
|
|
local is_valid_address=false
|
|
|
|
|
|
|
|
|
|
while [[ "$is_valid_address" == "false" ]]; do
|
|
|
|
|
read -p "请输入目标地址: " override_address
|
|
|
|
|
|
|
|
|
|
# 检查是否为合法的 IPv4 地址
|
|
|
|
|
if [[ $override_address =~ ^([0-9]{1,3}\.){3}[0-9]{1,3}$ ]]; then
|
|
|
|
|
# 检查每个字段是否在 0 到 255 之间
|
|
|
|
|
IFS='.' read -r -a address_fields <<< "$override_address"
|
|
|
|
|
is_valid_ip=true
|
|
|
|
|
for field in "${address_fields[@]}"; do
|
|
|
|
|
if [[ "$field" -lt 0 || "$field" -gt 255 ]]; then
|
|
|
|
|
is_valid_ip=false
|
|
|
|
|
break
|
|
|
|
|
fi
|
|
|
|
|
done
|
|
|
|
|
|
|
|
|
|
if [[ "$is_valid_ip" == "true" ]]; then
|
|
|
|
|
is_valid_address=true
|
|
|
|
|
else
|
|
|
|
|
echo -e "${RED}错误:IP地址字段必须在0到255之间,请重新输入。${NC}"
|
|
|
|
|
fi
|
|
|
|
|
else
|
|
|
|
|
echo -e "${RED}错误:请输入合法的IPv4地址,格式为 0.0.0.0${NC}"
|
|
|
|
|
fi
|
|
|
|
|
done
|
2023-07-27 18:18:35 +08:00
|
|
|
|
}
|
|
|
|
|
|
2023-07-29 12:09:39 +08:00
|
|
|
|
# 设置目标端口
|
|
|
|
|
function Direct_override_port() {
|
2023-07-27 18:18:35 +08:00
|
|
|
|
while true; do
|
2023-07-29 12:09:39 +08:00
|
|
|
|
read -p "请输入目标端口 (默认443): " override_port
|
|
|
|
|
override_port=${override_port:-443}
|
2023-07-27 18:18:35 +08:00
|
|
|
|
|
2023-07-29 12:09:39 +08:00
|
|
|
|
if [[ $override_port =~ ^[1-9][0-9]{0,4}$ && $override_port -le 65535 ]]; then
|
2023-07-27 18:18:35 +08:00
|
|
|
|
break
|
|
|
|
|
else
|
2023-07-29 12:09:39 +08:00
|
|
|
|
echo -e "${RED}错误:目标端口范围必须在1-65535之间,请重新输入。"
|
2023-07-27 18:18:35 +08:00
|
|
|
|
fi
|
|
|
|
|
done
|
2023-07-28 11:28:46 +08:00
|
|
|
|
}
|
|
|
|
|
|
2023-07-29 12:09:39 +08:00
|
|
|
|
# 函数:写入配置文件
|
|
|
|
|
function Direct_write_config_file() {
|
|
|
|
|
local config_file="/usr/local/etc/sing-box/config.json"
|
2023-07-28 11:28:46 +08:00
|
|
|
|
|
2023-07-29 12:09:39 +08:00
|
|
|
|
echo "{
|
|
|
|
|
\"log\": {
|
|
|
|
|
\"disabled\": false,
|
|
|
|
|
\"level\": \"info\",
|
|
|
|
|
\"timestamp\": true
|
|
|
|
|
},
|
|
|
|
|
\"inbounds\": [
|
|
|
|
|
{
|
|
|
|
|
\"type\": \"direct\",
|
|
|
|
|
\"tag\": \"direct-in\",
|
|
|
|
|
\"listen\": \"0.0.0.0\",
|
|
|
|
|
\"listen_port\": $listen_port,
|
|
|
|
|
\"sniff\": true,
|
|
|
|
|
\"sniff_override_destination\": true,
|
|
|
|
|
\"sniff_timeout\": \"300ms\",
|
|
|
|
|
\"proxy_protocol\": false,
|
|
|
|
|
\"network\": \"tcp\",
|
|
|
|
|
\"override_address\": \"$override_address\",
|
|
|
|
|
\"override_port\": $override_port
|
|
|
|
|
}
|
|
|
|
|
],
|
|
|
|
|
\"outbounds\": [
|
|
|
|
|
{
|
|
|
|
|
\"type\": \"direct\",
|
|
|
|
|
\"tag\": \"direct\"
|
|
|
|
|
},
|
|
|
|
|
{
|
|
|
|
|
\"type\": \"block\",
|
|
|
|
|
\"tag\": \"block\"
|
|
|
|
|
}
|
|
|
|
|
]
|
|
|
|
|
}" > "$config_file"
|
2023-07-28 11:28:46 +08:00
|
|
|
|
|
2023-07-29 12:09:39 +08:00
|
|
|
|
echo "配置文件 $config_file 写入成功。"
|
2023-07-27 18:18:35 +08:00
|
|
|
|
}
|
2023-07-28 11:28:46 +08:00
|
|
|
|
|
2023-07-29 12:09:39 +08:00
|
|
|
|
# 函数:读取加密方式
|
|
|
|
|
function ss_encryption_method() {
|
|
|
|
|
while true; do
|
|
|
|
|
read -p "请选择加密方式:
|
|
|
|
|
[1]. 2022-blake3-aes-128-gcm
|
|
|
|
|
[2]. 2022-blake3-aes-256-gcm
|
|
|
|
|
[3]. 2022-blake3-chacha20-poly1305
|
|
|
|
|
请输入对应的数字 (默认3): " encryption_choice
|
|
|
|
|
encryption_choice=${encryption_choice:-3}
|
|
|
|
|
|
|
|
|
|
case $encryption_choice in
|
|
|
|
|
1)
|
|
|
|
|
ss_method="2022-blake3-aes-128-gcm"
|
|
|
|
|
ss_password=$(sing-box generate rand --base64 16)
|
|
|
|
|
echo "随机生成的密码:$ss_password"
|
|
|
|
|
break
|
|
|
|
|
;;
|
|
|
|
|
2)
|
|
|
|
|
ss_method="2022-blake3-aes-256-gcm"
|
|
|
|
|
ss_password=$(sing-box generate rand --base64 32)
|
|
|
|
|
echo "随机生成的密码:$ss_password"
|
|
|
|
|
break
|
|
|
|
|
;;
|
|
|
|
|
3)
|
|
|
|
|
ss_method="2022-blake3-chacha20-poly1305"
|
|
|
|
|
ss_password=$(sing-box generate rand --base64 32)
|
|
|
|
|
echo "随机生成的密码:$ss_password"
|
|
|
|
|
break
|
|
|
|
|
;;
|
|
|
|
|
*)
|
|
|
|
|
echo "错误:无效的选择,请重新输入。"
|
|
|
|
|
;;
|
|
|
|
|
esac
|
|
|
|
|
done
|
|
|
|
|
}
|
2023-07-28 11:28:46 +08:00
|
|
|
|
|
2023-07-29 12:09:39 +08:00
|
|
|
|
# 函数:写入sing-box配置文件
|
|
|
|
|
function ss_write_sing_box_config() {
|
|
|
|
|
local config_file="/usr/local/etc/sing-box/config.json"
|
2023-07-28 11:28:46 +08:00
|
|
|
|
|
|
|
|
|
echo "{
|
|
|
|
|
\"log\": {
|
|
|
|
|
\"disabled\": false,
|
|
|
|
|
\"level\": \"info\",
|
|
|
|
|
\"timestamp\": true
|
|
|
|
|
},
|
|
|
|
|
\"inbounds\": [
|
|
|
|
|
{
|
2023-07-29 12:09:39 +08:00
|
|
|
|
\"type\": \"shadowsocks\",
|
|
|
|
|
\"tag\": \"ss-in\",
|
2023-07-28 11:28:46 +08:00
|
|
|
|
\"listen\": \"::\",
|
|
|
|
|
\"listen_port\": $listen_port,
|
2023-07-29 12:09:39 +08:00
|
|
|
|
\"method\": \"$ss_method\",
|
|
|
|
|
\"password\": \"$ss_password\"
|
2023-07-28 11:28:46 +08:00
|
|
|
|
}
|
|
|
|
|
],
|
|
|
|
|
\"outbounds\": [
|
|
|
|
|
{
|
|
|
|
|
\"type\": \"direct\",
|
|
|
|
|
\"tag\": \"direct\"
|
|
|
|
|
},
|
|
|
|
|
{
|
|
|
|
|
\"type\": \"block\",
|
|
|
|
|
\"tag\": \"block\"
|
|
|
|
|
}
|
|
|
|
|
]
|
|
|
|
|
}" > "$config_file"
|
|
|
|
|
|
|
|
|
|
echo "配置文件 $config_file 创建成功。"
|
|
|
|
|
}
|
|
|
|
|
|
2023-07-29 12:09:39 +08:00
|
|
|
|
# 函数:生成随机用户名
|
|
|
|
|
generate_caddy_auth_user() {
|
|
|
|
|
read -p "请输入用户名(默认自动生成): " user_input
|
|
|
|
|
|
|
|
|
|
if [[ -z $user_input ]]; then
|
|
|
|
|
auth_user=$(head /dev/urandom | tr -dc A-Za-z0-9 | head -c 8)
|
|
|
|
|
else
|
|
|
|
|
auth_user=$user_input
|
|
|
|
|
fi
|
|
|
|
|
|
|
|
|
|
echo "用户名: $auth_user"
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
# 函数:生成随机密码
|
|
|
|
|
generate_caddy_auth_pass() {
|
|
|
|
|
read -p "请输入密码(默认自动生成): " pass_input
|
|
|
|
|
|
|
|
|
|
if [[ -z $pass_input ]]; then
|
|
|
|
|
auth_pass=$(head /dev/urandom | tr -dc A-Za-z0-9 | head -c 16)
|
|
|
|
|
else
|
|
|
|
|
auth_pass=$pass_input
|
|
|
|
|
fi
|
|
|
|
|
|
|
|
|
|
echo "密码: $auth_pass"
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
# 函数:获取用户输入的伪装网址
|
|
|
|
|
get_caddy_fake_site() {
|
|
|
|
|
while true; do
|
|
|
|
|
read -p "请输入伪装网址(默认: www.fan-2000.com): " fake_site
|
|
|
|
|
fake_site=${fake_site:-"www.fan-2000.com"}
|
|
|
|
|
|
|
|
|
|
# Validate the fake site URL
|
|
|
|
|
if curl --output /dev/null --silent --head --fail "$fake_site"; then
|
|
|
|
|
echo "伪装网址: $fake_site"
|
|
|
|
|
break
|
|
|
|
|
else
|
|
|
|
|
echo "伪装网址无效或不可用,请重新输入。"
|
|
|
|
|
fi
|
|
|
|
|
done
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
# 函数:获取用户输入的域名,如果域名未绑定本机 IP,则要求重新输入
|
|
|
|
|
get_caddy_domain() {
|
|
|
|
|
read -p "请输入域名(用于自动申请证书): " domain
|
|
|
|
|
while true; do
|
|
|
|
|
if [[ -z $domain ]]; then
|
|
|
|
|
echo "域名不能为空,请重新输入。"
|
|
|
|
|
else
|
|
|
|
|
if ping -c 1 $domain >/dev/null 2>&1; then
|
|
|
|
|
break
|
|
|
|
|
else
|
|
|
|
|
echo "域名未绑定本机 IP,请重新输入。"
|
|
|
|
|
fi
|
|
|
|
|
fi
|
|
|
|
|
read -p "请输入域名(用于自动申请证书): " domain
|
|
|
|
|
done
|
|
|
|
|
|
|
|
|
|
echo "域名: $domain"
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
# 函数:创建 Caddy 配置文件
|
|
|
|
|
create_caddy_config() {
|
|
|
|
|
local config_file="/usr/local/etc/caddy/caddy.json"
|
|
|
|
|
|
|
|
|
|
echo "{
|
|
|
|
|
\"apps\": {
|
|
|
|
|
\"http\": {
|
|
|
|
|
\"servers\": {
|
|
|
|
|
\"https\": {
|
|
|
|
|
\"listen\": [\":$listen_port\"],
|
|
|
|
|
\"routes\": [
|
|
|
|
|
{
|
|
|
|
|
\"handle\": [
|
|
|
|
|
{
|
|
|
|
|
\"handler\": \"forward_proxy\",
|
|
|
|
|
\"auth_user_deprecated\": \"$auth_user\",
|
|
|
|
|
\"auth_pass_deprecated\": \"$auth_pass\",
|
|
|
|
|
\"hide_ip\": true,
|
|
|
|
|
\"hide_via\": true,
|
|
|
|
|
\"probe_resistance\": {}
|
|
|
|
|
}
|
|
|
|
|
]
|
|
|
|
|
},
|
|
|
|
|
{
|
|
|
|
|
\"handle\": [
|
|
|
|
|
{
|
|
|
|
|
\"handler\": \"headers\",
|
|
|
|
|
\"response\": {
|
|
|
|
|
\"set\": {
|
|
|
|
|
\"Strict-Transport-Security\": [\"max-age=31536000; includeSubDomains; preload\"]
|
|
|
|
|
}
|
|
|
|
|
}
|
|
|
|
|
},
|
|
|
|
|
{
|
|
|
|
|
\"handler\": \"reverse_proxy\",
|
|
|
|
|
\"headers\": {
|
|
|
|
|
\"request\": {
|
|
|
|
|
\"set\": {
|
|
|
|
|
\"Host\": [
|
|
|
|
|
\"{http.reverse_proxy.upstream.hostport}\"
|
|
|
|
|
],
|
|
|
|
|
\"X-Forwarded-Host\": [\"{http.request.host}\"]
|
|
|
|
|
}
|
|
|
|
|
}
|
|
|
|
|
},
|
|
|
|
|
\"transport\": {
|
|
|
|
|
\"protocol\": \"http\",
|
|
|
|
|
\"tls\": {}
|
|
|
|
|
},
|
|
|
|
|
\"upstreams\": [
|
|
|
|
|
{\"dial\": \"$fake_site:443\"}
|
|
|
|
|
]
|
|
|
|
|
}
|
|
|
|
|
]
|
|
|
|
|
}
|
|
|
|
|
],
|
|
|
|
|
\"tls_connection_policies\": [
|
|
|
|
|
{
|
|
|
|
|
\"match\": {
|
|
|
|
|
\"sni\": [\"$domain\"]
|
|
|
|
|
},
|
|
|
|
|
\"protocol_min\": \"tls1.2\",
|
|
|
|
|
\"protocol_max\": \"tls1.2\",
|
|
|
|
|
\"cipher_suites\": [\"TLS_ECDHE_ECDSA_WITH_CHACHA20_POLY1305_SHA256\"],
|
|
|
|
|
\"curves\": [\"secp521r1\",\"secp384r1\",\"secp256r1\"]
|
|
|
|
|
}
|
|
|
|
|
],
|
|
|
|
|
\"protocols\": [\"h1\",\"h2\"]
|
|
|
|
|
}
|
|
|
|
|
}
|
|
|
|
|
},
|
|
|
|
|
\"tls\": {
|
|
|
|
|
\"certificates\": {
|
|
|
|
|
\"automate\": [\"$domain\"]
|
|
|
|
|
},
|
|
|
|
|
\"automation\": {
|
|
|
|
|
\"policies\": [
|
|
|
|
|
{
|
|
|
|
|
\"issuers\": [
|
|
|
|
|
{
|
|
|
|
|
\"module\": \"acme\"
|
|
|
|
|
}
|
|
|
|
|
]
|
|
|
|
|
}
|
|
|
|
|
]
|
|
|
|
|
}
|
|
|
|
|
}
|
|
|
|
|
}
|
|
|
|
|
}" > "$config_file"
|
|
|
|
|
|
|
|
|
|
echo "配置文件 $config_file 写入成功。"
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
#函数:测试 caddy 配置文件
|
|
|
|
|
test_caddy_config() {
|
|
|
|
|
echo "测试 Caddy 配置是否正确..."
|
|
|
|
|
local output
|
|
|
|
|
local caddy_pid
|
|
|
|
|
|
|
|
|
|
# 运行Caddy并捕获输出
|
|
|
|
|
output=$(timeout 15 /usr/bin/caddy run --environ --config /usr/local/etc/caddy/caddy.json 2>&1 &)
|
|
|
|
|
caddy_pid=$!
|
|
|
|
|
|
|
|
|
|
# 等待Caddy进程完成或超时
|
|
|
|
|
wait $caddy_pid 2>/dev/null
|
|
|
|
|
|
|
|
|
|
# 检查输出中是否包含错误提示
|
|
|
|
|
if echo "$output" | grep -i "error"; then
|
|
|
|
|
echo -e "${RED}Caddy 配置测试未通过,请检查配置文件${NC}"
|
|
|
|
|
echo "$output" | grep -i "error" --color=always # 输出包含错误的行,并以红色高亮显示
|
|
|
|
|
else
|
|
|
|
|
echo -e "${GREEN}Caddy 配置测试通过${NC}"
|
|
|
|
|
fi
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
# 自动生成UUID
|
|
|
|
|
function tuic_generate_uuid() {
|
|
|
|
|
if [[ -n $(command -v uuidgen) ]]; then
|
|
|
|
|
uuid=$(uuidgen)
|
|
|
|
|
elif [[ -n $(command -v uuid) ]]; then
|
|
|
|
|
uuid=$(uuid -v 4)
|
|
|
|
|
else
|
|
|
|
|
echo -e "${RED}错误:无法生成UUID,请手动设置。${NC}"
|
|
|
|
|
exit 1
|
|
|
|
|
fi
|
|
|
|
|
echo -e "${GREEN}生成的UUID为:$uuid${NC}"
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
# 设置密码
|
|
|
|
|
function tuic_set_password() {
|
|
|
|
|
read -p "请输入密码(默认随机生成): " password
|
|
|
|
|
|
|
|
|
|
# 如果密码为空,则随机生成一个密码
|
|
|
|
|
if [[ -z "$password" ]]; then
|
|
|
|
|
password=$(cat /dev/urandom | tr -dc 'a-z0-9' | fold -w 12 | head -n 1)
|
|
|
|
|
echo -e "${GREEN}生成的密码为:$password${NC}"
|
|
|
|
|
fi
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
# 添加多用户
|
|
|
|
|
function tuic_add_multiple_users() {
|
|
|
|
|
while true; do
|
|
|
|
|
read -p "是否继续添加用户?(Y/N): " add_multiple_users
|
|
|
|
|
|
|
|
|
|
if [[ "$add_multiple_users" == "Y" || "$add_multiple_users" == "y" ]]; then
|
|
|
|
|
# 自动生成UUID
|
|
|
|
|
tuic_generate_uuid
|
|
|
|
|
|
|
|
|
|
# 设置密码
|
|
|
|
|
tuic_set_password
|
|
|
|
|
|
|
|
|
|
# 将UUID和密码添加到用户列表中
|
|
|
|
|
users+=",\n\"$uuid\": \"$password\""
|
|
|
|
|
elif [[ "$add_multiple_users" == "N" || "$add_multiple_users" == "n" ]]; then
|
|
|
|
|
break
|
|
|
|
|
else
|
|
|
|
|
echo -e "${RED}错误:无效的选择,请重新输入。${NC}"
|
|
|
|
|
fi
|
|
|
|
|
done
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
# 设置证书和私钥路径
|
|
|
|
|
function set_certificate_and_private_key() {
|
|
|
|
|
while true; do
|
|
|
|
|
read -p "请输入证书路径 (默认/etc/ssl/private/cert.crt): " certificate_path
|
|
|
|
|
certificate_path=${certificate_path:-"/etc/ssl/private/cert.crt"}
|
|
|
|
|
|
|
|
|
|
if [[ "$certificate_path" != "/etc/ssl/private/cert.crt" && ! -f "$certificate_path" ]]; then
|
|
|
|
|
echo -e "${RED}错误:证书文件不存在,请重新输入。${NC}"
|
|
|
|
|
else
|
|
|
|
|
break
|
|
|
|
|
fi
|
|
|
|
|
done
|
|
|
|
|
|
|
|
|
|
while true; do
|
|
|
|
|
read -p "请输入私钥路径 (默认/etc/ssl/private/private.key): " private_key_path
|
|
|
|
|
private_key_path=${private_key_path:-"/etc/ssl/private/private.key"}
|
|
|
|
|
|
|
|
|
|
if [[ "$private_key_path" != "/etc/ssl/private/private.key" && ! -f "$private_key_path" ]]; then
|
|
|
|
|
echo -e "${RED}错误:私钥文件不存在,请重新输入。${NC}"
|
|
|
|
|
else
|
|
|
|
|
break
|
|
|
|
|
fi
|
|
|
|
|
done
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
# 设置拥塞控制算法
|
|
|
|
|
function set_congestion_control() {
|
|
|
|
|
local default_congestion_control="bbr"
|
|
|
|
|
|
|
|
|
|
while true; do
|
|
|
|
|
read -p "请选择拥塞控制算法 (默认$default_congestion_control):
|
|
|
|
|
[1]. bbr
|
|
|
|
|
[2]. cubic
|
|
|
|
|
[3]. new_reno
|
|
|
|
|
请输入对应的数字: " congestion_control
|
|
|
|
|
|
|
|
|
|
case $congestion_control in
|
|
|
|
|
1)
|
|
|
|
|
congestion_control="bbr"
|
|
|
|
|
break
|
|
|
|
|
;;
|
|
|
|
|
2)
|
|
|
|
|
congestion_control="cubic"
|
|
|
|
|
break
|
|
|
|
|
;;
|
|
|
|
|
3)
|
|
|
|
|
congestion_control="new_reno"
|
|
|
|
|
break
|
|
|
|
|
;;
|
|
|
|
|
"")
|
|
|
|
|
congestion_control=$default_congestion_control
|
|
|
|
|
break
|
|
|
|
|
;;
|
|
|
|
|
*)
|
|
|
|
|
echo -e "${RED}错误:无效的选择,请重新输入。${NC}"
|
|
|
|
|
;;
|
|
|
|
|
esac
|
|
|
|
|
done
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
# 生成tuic的JSON配置文件
|
|
|
|
|
function generate_tuic_config() {
|
|
|
|
|
local config_file="/usr/local/etc/tuic/config.json"
|
|
|
|
|
local users=""
|
|
|
|
|
local certificate=""
|
|
|
|
|
local private_key=""
|
|
|
|
|
|
|
|
|
|
echo "生成tuic的JSON配置文件..."
|
|
|
|
|
|
|
|
|
|
# 设置监听端口
|
|
|
|
|
set_listen_port
|
|
|
|
|
|
|
|
|
|
# 自动生成UUID
|
|
|
|
|
tuic_generate_uuid
|
|
|
|
|
|
|
|
|
|
# 设置密码
|
|
|
|
|
tuic_set_password
|
|
|
|
|
|
|
|
|
|
# 将UUID和密码添加到用户列表中
|
|
|
|
|
users="\"$uuid\": \"$password\""
|
|
|
|
|
|
|
|
|
|
# 添加多用户
|
|
|
|
|
tuic_add_multiple_users
|
|
|
|
|
|
|
|
|
|
# 格式化用户列表
|
|
|
|
|
users=$(echo -e "$users" | sed -e 's/^/ /')
|
|
|
|
|
|
|
|
|
|
# 配置证书和私钥路径
|
|
|
|
|
set_certificate_and_private_key
|
|
|
|
|
certificate_path="$certificate_path"
|
|
|
|
|
private_key_path="$private_key_path"
|
|
|
|
|
|
|
|
|
|
# 设置拥塞控制算法
|
|
|
|
|
set_congestion_control
|
|
|
|
|
|
|
|
|
|
# 生成tuic配置文件
|
|
|
|
|
echo "{
|
|
|
|
|
\"server\": \"[::]:$listen_port\",
|
|
|
|
|
\"users\": {
|
|
|
|
|
$users
|
|
|
|
|
},
|
|
|
|
|
\"certificate\": \"$certificate_path\",
|
|
|
|
|
\"private_key\": \"$private_key_path\",
|
|
|
|
|
\"congestion_control\": \"$congestion_control\",
|
|
|
|
|
\"alpn\": [\"h3\", \"spdy/3.1\"],
|
|
|
|
|
\"udp_relay_ipv6\": true,
|
|
|
|
|
\"zero_rtt_handshake\": false,
|
|
|
|
|
\"dual_stack\": true,
|
|
|
|
|
\"auth_timeout\": \"3s\",
|
|
|
|
|
\"task_negotiation_timeout\": \"3s\",
|
|
|
|
|
\"max_idle_time\": \"10s\",
|
|
|
|
|
\"max_external_packet_size\": 1500,
|
|
|
|
|
\"send_window\": 16777216,
|
|
|
|
|
\"receive_window\": 8388608,
|
|
|
|
|
\"gc_interval\": \"3s\",
|
|
|
|
|
\"gc_lifetime\": \"15s\",
|
|
|
|
|
\"log_level\": \"warn\"
|
|
|
|
|
}" > "$config_file"
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
# 询问证书来源选择
|
|
|
|
|
function ask_certificate_option() {
|
|
|
|
|
while true; do
|
|
|
|
|
read -p "请选择证书来源:
|
|
|
|
|
[1]. 自动申请证书
|
|
|
|
|
[2]. 自备证书
|
|
|
|
|
请输入对应的数字: " certificate_option
|
|
|
|
|
|
|
|
|
|
case $certificate_option in
|
|
|
|
|
1)
|
|
|
|
|
echo "已选择自动申请证书。"
|
|
|
|
|
tuic_apply_certificate
|
|
|
|
|
break
|
|
|
|
|
;;
|
|
|
|
|
2)
|
|
|
|
|
echo "已选择自备证书。"
|
|
|
|
|
break
|
|
|
|
|
;;
|
|
|
|
|
|
|
|
|
|
*)
|
|
|
|
|
echo -e "${RED}错误:无效的选择,请重新输入。${NC}"
|
|
|
|
|
;;
|
|
|
|
|
esac
|
|
|
|
|
done
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
# 申请证书
|
|
|
|
|
function tuic_apply_certificate() {
|
|
|
|
|
local domain
|
|
|
|
|
|
|
|
|
|
# 验证域名
|
|
|
|
|
while true; do
|
|
|
|
|
read -p "请输入您的域名: " domain
|
|
|
|
|
|
|
|
|
|
# 检查域名是否绑定本机IP
|
|
|
|
|
if ping -c 1 "$domain" &>/dev/null; then
|
|
|
|
|
break
|
|
|
|
|
else
|
|
|
|
|
echo -e "${RED}错误:域名未解析或输入错误,请重新输入。${NC}"
|
|
|
|
|
fi
|
|
|
|
|
done
|
|
|
|
|
|
|
|
|
|
# 安装 acme
|
|
|
|
|
echo "安装 acme..."
|
|
|
|
|
curl https://get.acme.sh | sh
|
|
|
|
|
alias acme.sh=~/.acme.sh/acme.sh
|
|
|
|
|
~/.acme.sh/acme.sh --set-default-ca --server letsencrypt
|
|
|
|
|
|
|
|
|
|
# 申请证书
|
|
|
|
|
echo "申请证书..."
|
|
|
|
|
~/.acme.sh/acme.sh --issue -d "$domain" --standalone -k ec-256 --webroot /home/wwwroot/html
|
|
|
|
|
|
|
|
|
|
# 安装证书
|
|
|
|
|
echo "安装证书..."
|
|
|
|
|
certificate_path=$(~/.acme.sh/acme.sh --install-cert -d "$domain" --ecc --key-file "$private_key_path" --fullchain-file "$certificate_path")
|
|
|
|
|
|
|
|
|
|
set_certificate_path="$certificate_path"
|
|
|
|
|
set_private_key_path="$private_key_path"
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
# 显示 tuic 配置信息
|
|
|
|
|
function display_tuic_config() {
|
|
|
|
|
local config_file="/usr/local/etc/tuic/config.json"
|
|
|
|
|
echo -e "${CYAN}TUIC节点配置信息:${NC}"
|
|
|
|
|
echo -e "${CYAN}==================================================================${NC}"
|
|
|
|
|
echo "监听端口: $(jq -r '.server' "$config_file" | sed 's/\[::\]://')"
|
|
|
|
|
echo -e "${CYAN}------------------------------------------------------------------${NC}"
|
|
|
|
|
echo "UUID和密码列表:"
|
|
|
|
|
jq -r '.users | to_entries[] | "UUID:\(.key)\t密码:\(.value)"' "$config_file"
|
|
|
|
|
echo -e "${CYAN}------------------------------------------------------------------${NC}"
|
|
|
|
|
echo "拥塞控制算法: $(jq -r '.congestion_control' "$config_file")"
|
|
|
|
|
echo -e "${CYAN}------------------------------------------------------------------${NC}"
|
|
|
|
|
echo "ALPN协议:$(jq -r '.alpn[] | select(. != "")' "$config_file" | sed ':a;N;$!ba;s/\n/, /g')"
|
|
|
|
|
echo -e "${CYAN}==================================================================${NC}"
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
# 函数:读取上行速度
|
|
|
|
|
function read_up_speed() {
|
|
|
|
|
while true; do
|
|
|
|
|
read -p "请输入上行速度 (默认50): " up_mbps
|
|
|
|
|
up_mbps=${up_mbps:-50}
|
|
|
|
|
|
|
|
|
|
if [[ $up_mbps =~ ^[0-9]+$ ]]; then
|
|
|
|
|
echo "上行速度设置成功:$up_mbps Mbps"
|
|
|
|
|
break
|
|
|
|
|
else
|
|
|
|
|
echo "错误:请输入数字作为上行速度。"
|
|
|
|
|
fi
|
|
|
|
|
done
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
# 函数:读取下行速度
|
|
|
|
|
function read_down_speed() {
|
|
|
|
|
while true; do
|
|
|
|
|
read -p "请输入下行速度 (默认100): " down_mbps
|
|
|
|
|
down_mbps=${down_mbps:-100}
|
|
|
|
|
|
|
|
|
|
if [[ $down_mbps =~ ^[0-9]+$ ]]; then
|
|
|
|
|
echo "下行速度设置成功:$down_mbps Mbps"
|
|
|
|
|
break
|
|
|
|
|
else
|
|
|
|
|
echo "错误:请输入数字作为下行速度。"
|
|
|
|
|
fi
|
|
|
|
|
done
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
# 函数:读取认证密码
|
|
|
|
|
function read_auth_password() {
|
|
|
|
|
read -p "请输入认证密码 (默认随机生成): " auth_password
|
|
|
|
|
auth_password=${auth_password:-$(cat /dev/urandom | tr -dc 'a-zA-Z0-9' | fold -w 12 | head -n 1)}
|
|
|
|
|
echo "认证密码设置成功:$auth_password"
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
# 函数:读取用户信息
|
|
|
|
|
function read_users() {
|
|
|
|
|
users="[
|
|
|
|
|
{
|
|
|
|
|
\"auth_str\": \"$auth_password\"
|
|
|
|
|
}"
|
|
|
|
|
|
|
|
|
|
while true; do
|
|
|
|
|
read -p "是否继续添加用户?(Y/N,默认N): " -e add_multiple_users
|
|
|
|
|
|
|
|
|
|
if [[ -z "$add_multiple_users" ]]; then
|
|
|
|
|
add_multiple_users="N"
|
|
|
|
|
fi
|
|
|
|
|
|
|
|
|
|
if [[ "$add_multiple_users" == "Y" || "$add_multiple_users" == "y" ]]; then
|
|
|
|
|
read_auth_password
|
|
|
|
|
users+=",
|
|
|
|
|
{
|
|
|
|
|
\"auth_str\": \"$auth_password\"
|
|
|
|
|
}"
|
|
|
|
|
elif [[ "$add_multiple_users" == "N" || "$add_multiple_users" == "n" ]]; then
|
|
|
|
|
break
|
|
|
|
|
else
|
|
|
|
|
echo "无效的输入,请重新输入。"
|
|
|
|
|
fi
|
|
|
|
|
done
|
|
|
|
|
|
|
|
|
|
users+=$'\n ]'
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
# 函数:验证域名解析
|
|
|
|
|
function validate_domain() {
|
|
|
|
|
while true; do
|
|
|
|
|
read -p "请输入您的域名: " domain
|
|
|
|
|
|
|
|
|
|
if ping -c 1 "$domain" &>/dev/null; then
|
|
|
|
|
break
|
|
|
|
|
else
|
|
|
|
|
echo "错误:域名未解析或输入错误,请重新输入。"
|
|
|
|
|
fi
|
|
|
|
|
done
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
function generate_Hysteria_config() {
|
|
|
|
|
local config_file="/usr/local/etc/sing-box/config.json"
|
|
|
|
|
local certificate=""
|
|
|
|
|
local private_key=""
|
|
|
|
|
|
|
|
|
|
echo "生成 Hysteria 配置文件..."
|
|
|
|
|
|
|
|
|
|
set_listen_port
|
|
|
|
|
read_up_speed
|
|
|
|
|
read_down_speed
|
|
|
|
|
read_auth_password
|
|
|
|
|
read_users
|
|
|
|
|
validate_domain
|
|
|
|
|
set_certificate_and_private_key
|
|
|
|
|
certificate_path="$certificate_path"
|
|
|
|
|
private_key_path="$private_key_path"
|
|
|
|
|
|
|
|
|
|
# 生成配置文件
|
|
|
|
|
echo "{
|
|
|
|
|
\"log\": {
|
|
|
|
|
\"disabled\": false,
|
|
|
|
|
\"level\": \"info\",
|
|
|
|
|
\"timestamp\": true
|
|
|
|
|
},
|
|
|
|
|
\"inbounds\": [
|
|
|
|
|
{
|
|
|
|
|
\"type\": \"hysteria\",
|
|
|
|
|
\"tag\": \"hysteria-in\",
|
|
|
|
|
\"listen\": \"::\",
|
|
|
|
|
\"listen_port\": $listen_port,
|
|
|
|
|
\"sniff\": true,
|
|
|
|
|
\"sniff_override_destination\": true,
|
|
|
|
|
\"up_mbps\": $up_mbps,
|
|
|
|
|
\"down_mbps\": $down_mbps,
|
|
|
|
|
\"users\": $users,
|
|
|
|
|
\"tls\": {
|
|
|
|
|
\"enabled\": true,
|
|
|
|
|
\"server_name\": \"$domain\",
|
|
|
|
|
\"alpn\": [
|
|
|
|
|
\"h3\"
|
|
|
|
|
],
|
|
|
|
|
\"min_version\": \"1.2\",
|
|
|
|
|
\"max_version\": \"1.3\",
|
|
|
|
|
\"certificate_path\": \"$certificate_path\",
|
|
|
|
|
\"key_path\": \"$private_key_path\"
|
|
|
|
|
}
|
|
|
|
|
}
|
|
|
|
|
],
|
|
|
|
|
\"outbounds\": [
|
|
|
|
|
{
|
|
|
|
|
\"type\": \"direct\",
|
|
|
|
|
\"tag\": \"direct\"
|
|
|
|
|
},
|
|
|
|
|
{
|
|
|
|
|
\"type\": \"block\",
|
|
|
|
|
\"tag\": \"block\"
|
|
|
|
|
}
|
|
|
|
|
]
|
|
|
|
|
}" > "$config_file"
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
# 函数:显示配置信息
|
|
|
|
|
function display_Hysteria_config_info() {
|
|
|
|
|
echo -e "配置信息如下:"
|
|
|
|
|
echo "域名:$domain"
|
|
|
|
|
echo "监听端口:$listen_port"
|
|
|
|
|
echo "上行速度:${up_mbps}Mbps"
|
|
|
|
|
echo "下行速度:${down_mbps}Mbps"
|
|
|
|
|
echo "用户密码:"
|
|
|
|
|
|
|
|
|
|
# 提取并显示每个用户的密码
|
|
|
|
|
local user_count=$(echo "$users" | jq length)
|
|
|
|
|
for ((i = 0; i < user_count; i++)); do
|
|
|
|
|
local auth_str=$(echo "$users" | jq -r ".[$i].auth_str")
|
|
|
|
|
echo "用户$i: $auth_str"
|
|
|
|
|
done
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
# 设置用户名
|
|
|
|
|
function set_shadowtls_username() {
|
|
|
|
|
read -p "$(echo -e "${CYAN}请输入用户名 (默认随机生成): ${NC}")" new_username
|
|
|
|
|
username=${new_username:-$(generate_shadowtls_random_username)}
|
|
|
|
|
echo -e "${GREEN}用户名: $username${NC}"
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
# 生成随机用户名
|
|
|
|
|
function generate_shadowtls_random_username() {
|
|
|
|
|
local username=$(cat /dev/urandom | tr -dc 'a-zA-Z0-9' | fold -w 8 | head -n 1)
|
|
|
|
|
echo "$username"
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
# 生成 ShadowTLS 密码
|
|
|
|
|
function generate_shadowtls_password() {
|
|
|
|
|
read -p "$(echo -e "${CYAN}请选择 Shadowsocks 加密方式:
|
|
|
|
|
1. 2022-blake3-chacha20-poly1305
|
|
|
|
|
2. 2022-blake3-aes-256-gcm
|
|
|
|
|
3. 2022-blake3-aes-128-gcm
|
|
|
|
|
请输入对应的数字 (默认1): ${NC}")" encryption_choice
|
|
|
|
|
encryption_choice=${encryption_choice:-1}
|
|
|
|
|
|
|
|
|
|
case $encryption_choice in
|
|
|
|
|
1)
|
|
|
|
|
ss_method="2022-blake3-chacha20-poly1305"
|
|
|
|
|
shadowtls_password=$(openssl rand -base64 32)
|
|
|
|
|
ss_password=$(openssl rand -base64 32)
|
|
|
|
|
;;
|
|
|
|
|
2)
|
|
|
|
|
ss_method="2022-blake3-aes-256-gcm"
|
|
|
|
|
shadowtls_password=$(openssl rand -base64 32)
|
|
|
|
|
ss_password=$(openssl rand -base64 32)
|
|
|
|
|
;;
|
|
|
|
|
3)
|
|
|
|
|
ss_method="2022-blake3-aes-128-gcm"
|
|
|
|
|
shadowtls_password=$(openssl rand -base64 16)
|
|
|
|
|
ss_password=$(openssl rand -base64 16)
|
|
|
|
|
;;
|
|
|
|
|
*)
|
|
|
|
|
echo -e "${RED}无效的选择,使用默认加密方式。${NC}"
|
|
|
|
|
ss_method="2022-blake3-chacha20-poly1305"
|
|
|
|
|
shadowtls_password=$(openssl rand -base64 32)
|
|
|
|
|
ss_password=$(openssl rand -base64 32)
|
|
|
|
|
;;
|
|
|
|
|
esac
|
|
|
|
|
|
|
|
|
|
echo -e "${GREEN}加密方式: $ss_method${NC}"
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
# 添加用户
|
|
|
|
|
function add_shadowtls_user() {
|
|
|
|
|
local user_password=""
|
|
|
|
|
if [[ $encryption_choice == 1 || $encryption_choice == 2 ]]; then
|
|
|
|
|
user_password=$(openssl rand -base64 32)
|
|
|
|
|
elif [[ $encryption_choice == 3 ]]; then
|
|
|
|
|
user_password=$(openssl rand -base64 16)
|
|
|
|
|
fi
|
|
|
|
|
|
|
|
|
|
read -p "$(echo -e "${CYAN}请输入用户名 (默认随机生成): ${NC}")" new_username
|
|
|
|
|
local new_user=${new_username:-$(generate_shadowtls_random_username)}
|
|
|
|
|
|
|
|
|
|
users+=",{
|
|
|
|
|
\"name\": \"$new_user\",
|
|
|
|
|
\"password\": \"$user_password\"
|
|
|
|
|
}"
|
|
|
|
|
|
|
|
|
|
echo -e "${GREEN}用户名: $new_user${NC}"
|
|
|
|
|
echo -e "${GREEN}ShadowTLS 密码: $user_password${NC}"
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
# 设置握手服务器地址
|
|
|
|
|
function set_shadowtls_handshake_server() {
|
|
|
|
|
local handshake_server=""
|
|
|
|
|
local openssl_output=""
|
|
|
|
|
|
|
|
|
|
read -p "$(echo -e "${CYAN}请输入握手服务器地址 (默认www.apple.com): ${NC}")" handshake_server
|
|
|
|
|
handshake_server=${handshake_server:-www.apple.com}
|
|
|
|
|
|
|
|
|
|
# 验证握手服务器是否支持TLS 1.3
|
|
|
|
|
echo "正在验证握手服务器支持的TLS版本..."
|
|
|
|
|
|
|
|
|
|
local is_supported="false"
|
|
|
|
|
|
|
|
|
|
if command -v openssl >/dev/null 2>&1; then
|
|
|
|
|
local openssl_version=$(openssl version)
|
|
|
|
|
|
|
|
|
|
if [[ $openssl_version == *"OpenSSL"* ]]; then
|
|
|
|
|
while true; do
|
|
|
|
|
openssl_output=$(timeout 90s openssl s_client -connect "$handshake_server:443" -tls1_3 2>&1)
|
|
|
|
|
|
|
|
|
|
if [[ $openssl_output == *"Protocol : TLSv1.3"* ]]; then
|
|
|
|
|
is_supported="true"
|
|
|
|
|
echo -e "${GREEN}握手服务器支持TLS 1.3。${NC}"
|
|
|
|
|
break
|
|
|
|
|
else
|
|
|
|
|
echo -e "${RED}错误:握手服务器不支持TLS 1.3,请重新输入握手服务器地址。${NC}"
|
|
|
|
|
read -p "$(echo -e "${CYAN}请输入握手服务器地址 (默认www.apple.com): ${NC}")" handshake_server
|
|
|
|
|
handshake_server=${handshake_server:-www.apple.com}
|
|
|
|
|
echo "正在验证握手服务器支持的TLS版本..."
|
|
|
|
|
fi
|
|
|
|
|
done
|
|
|
|
|
fi
|
|
|
|
|
fi
|
|
|
|
|
|
|
|
|
|
if [[ $is_supported == "false" ]]; then
|
|
|
|
|
echo -e "${YELLOW}警告:无法验证握手服务器支持的TLS版本。请确保握手服务器支持TLS 1.3。${NC}"
|
|
|
|
|
fi
|
|
|
|
|
handshake_server_global=$handshake_server
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
# 配置 sing-box 配置文件
|
|
|
|
|
function configure_shadowtls_config_file() {
|
|
|
|
|
local config_file="/usr/local/etc/sing-box/config.json"
|
|
|
|
|
|
|
|
|
|
set_listen_port
|
|
|
|
|
set_shadowtls_username
|
|
|
|
|
generate_shadowtls_password
|
|
|
|
|
|
|
|
|
|
local users="{
|
|
|
|
|
\"name\": \"$username\",
|
|
|
|
|
\"password\": \"$shadowtls_password\"
|
|
|
|
|
}"
|
|
|
|
|
|
|
|
|
|
local add_multiple_users="Y"
|
|
|
|
|
|
|
|
|
|
while [[ $add_multiple_users == [Yy] ]]; do
|
|
|
|
|
read -p "$(echo -e "${CYAN}是否添加多用户?(Y/N,默认为N): ${NC}")" add_multiple_users
|
|
|
|
|
|
|
|
|
|
if [[ $add_multiple_users == [Yy] ]]; then
|
|
|
|
|
add_shadowtls_user
|
|
|
|
|
fi
|
|
|
|
|
done
|
|
|
|
|
|
|
|
|
|
set_shadowtls_handshake_server
|
|
|
|
|
|
|
|
|
|
# 写入配置文件
|
|
|
|
|
echo "{
|
|
|
|
|
\"inbounds\": [
|
|
|
|
|
{
|
|
|
|
|
\"type\": \"shadowtls\",
|
|
|
|
|
\"tag\": \"st-in\",
|
|
|
|
|
\"listen\": \"::\",
|
|
|
|
|
\"listen_port\": $listen_port,
|
|
|
|
|
\"version\": 3,
|
|
|
|
|
\"users\": [
|
|
|
|
|
$users
|
|
|
|
|
],
|
|
|
|
|
\"handshake\": {
|
|
|
|
|
\"server\": \"$handshake_server_global\",
|
|
|
|
|
\"server_port\": 443
|
|
|
|
|
},
|
|
|
|
|
\"strict_mode\": true,
|
|
|
|
|
\"detour\": \"ss-in\"
|
|
|
|
|
},
|
|
|
|
|
{
|
|
|
|
|
\"type\": \"shadowsocks\",
|
|
|
|
|
\"tag\": \"ss-in\",
|
|
|
|
|
\"listen\": \"127.0.0.1\",
|
|
|
|
|
\"network\": \"tcp\",
|
|
|
|
|
\"method\": \"$ss_method\",
|
|
|
|
|
\"password\": \"$ss_password\"
|
|
|
|
|
}
|
|
|
|
|
],
|
|
|
|
|
\"outbounds\": [
|
|
|
|
|
{
|
|
|
|
|
\"type\": \"direct\",
|
|
|
|
|
\"tag\": \"direct\"
|
|
|
|
|
},
|
|
|
|
|
{
|
|
|
|
|
\"type\": \"block\",
|
|
|
|
|
\"tag\": \"block\"
|
|
|
|
|
}
|
|
|
|
|
]
|
|
|
|
|
}" | jq '.' > "$config_file"
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
# 显示 sing-box 配置信息
|
|
|
|
|
function display_shadowtls_config() {
|
|
|
|
|
local config_file="/usr/local/etc/sing-box/config.json"
|
|
|
|
|
echo "================================================================"
|
|
|
|
|
echo -e "${CYAN}ShadowTLS 节点配置信息:${NC}"
|
|
|
|
|
echo "----------------------------------------------------------------"
|
|
|
|
|
echo -e "${GREEN}监听端口: $listen_port${NC}"
|
|
|
|
|
echo "----------------------------------------------------------------"
|
|
|
|
|
jq -r '.inbounds[0].users[] | "ShadowTLS 密码: \(.password)"' "$config_file" | while IFS= read -r line; do
|
|
|
|
|
echo -e "${GREEN}$line${NC}"
|
|
|
|
|
done
|
|
|
|
|
echo "----------------------------------------------------------------"
|
|
|
|
|
echo -e "${GREEN}Shadowsocks 密码: $ss_password${NC}"
|
|
|
|
|
echo "================================================================"
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
# 生成随机 UUID
|
|
|
|
|
function reality_generate_uuid() {
|
|
|
|
|
local uuid=$(uuidgen)
|
|
|
|
|
echo "$uuid"
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
# 生成随机 ShortId
|
|
|
|
|
function generate_short_id() {
|
|
|
|
|
local length=$1
|
|
|
|
|
local short_id=$(openssl rand -hex "$length")
|
|
|
|
|
echo "$short_id"
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
# 选择流控类型
|
|
|
|
|
function select_flow_type() {
|
|
|
|
|
local flow_type="xtls-rprx-vision"
|
|
|
|
|
|
|
|
|
|
while true; do
|
|
|
|
|
read -p "请选择流控类型:
|
|
|
|
|
[1]. xtls-rprx-vision(vless+vision+reality)
|
|
|
|
|
[2]. 留空(vless+h2/grpc+reality)
|
|
|
|
|
请输入选项 (默认为 xtls-rprx-vision): " flow_option
|
|
|
|
|
|
|
|
|
|
case $flow_option in
|
|
|
|
|
"" | 1)
|
|
|
|
|
flow_type="xtls-rprx-vision"
|
|
|
|
|
break
|
|
|
|
|
;;
|
|
|
|
|
2)
|
|
|
|
|
flow_type=""
|
|
|
|
|
break
|
|
|
|
|
;;
|
|
|
|
|
*)
|
|
|
|
|
echo -e "${RED}错误的选项,请重新输入!${NC}" >&2
|
|
|
|
|
;;
|
|
|
|
|
esac
|
|
|
|
|
done
|
|
|
|
|
|
|
|
|
|
echo "$flow_type"
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
# 监听端口配置
|
|
|
|
|
function generate_listen_port() {
|
|
|
|
|
local listen_port
|
|
|
|
|
|
|
|
|
|
while true; do
|
|
|
|
|
read -p "请输入监听端口 (默认为 443): " listen_port
|
|
|
|
|
listen_port=${listen_port:-443}
|
|
|
|
|
|
|
|
|
|
if ! [[ "$listen_port" =~ ^[1-9][0-9]{0,4}$ || "$listen_port" == "443" ]]; then
|
|
|
|
|
echo -e "${RED}错误:端口范围1-65535,请重新输入!${NC}" >&2
|
|
|
|
|
else
|
|
|
|
|
break
|
|
|
|
|
fi
|
|
|
|
|
done
|
|
|
|
|
|
|
|
|
|
echo "$listen_port"
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
# 验证服务器是否支持TLS 1.3
|
|
|
|
|
function validate_tls13_support() {
|
|
|
|
|
local server="$1"
|
|
|
|
|
local tls13_supported="false"
|
|
|
|
|
|
|
|
|
|
if command -v openssl >/dev/null 2>&1; then
|
|
|
|
|
local openssl_output=$(timeout 90s openssl s_client -connect "$server:443" -tls1_3 2>&1)
|
|
|
|
|
if [[ $openssl_output == *"Protocol : TLSv1.3"* ]]; then
|
|
|
|
|
tls13_supported="true"
|
|
|
|
|
fi
|
|
|
|
|
fi
|
|
|
|
|
|
|
|
|
|
echo "$tls13_supported"
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
# ServerName 配置
|
|
|
|
|
function generate_server_name_config() {
|
|
|
|
|
local server_name="www.gov.hk"
|
|
|
|
|
|
|
|
|
|
read -p "请输入可用的 serverName 列表 (默认为 www.gov.hk): " user_input
|
|
|
|
|
|
|
|
|
|
# 验证服务器是否支持TLS 1.3
|
|
|
|
|
echo "正在验证服务器支持的TLS版本..." >&2
|
|
|
|
|
|
|
|
|
|
if [[ -n "$user_input" ]]; then
|
|
|
|
|
server_name="$user_input"
|
|
|
|
|
local tls13_support=$(validate_tls13_support "$server_name")
|
|
|
|
|
|
|
|
|
|
if [[ "$tls13_support" == "false" ]]; then
|
|
|
|
|
echo -e "${RED}该网址不支持 TLS 1.3,请重新输入!${NC}" >&2
|
|
|
|
|
generate_server_name_config
|
|
|
|
|
return
|
|
|
|
|
fi
|
|
|
|
|
fi
|
|
|
|
|
|
|
|
|
|
echo "$server_name"
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
# 目标网站配置
|
|
|
|
|
function generate_target_server_config() {
|
|
|
|
|
local target_server="www.gov.hk"
|
|
|
|
|
|
|
|
|
|
read -p "请输入目标网站地址(默认为 www.gov.hk): " user_input
|
|
|
|
|
|
|
|
|
|
# 验证目标服务器是否支持TLS 1.3
|
|
|
|
|
echo "正在验证服务器支持的TLS版本..." >&2
|
|
|
|
|
|
|
|
|
|
if [[ -n "$user_input" ]]; then
|
|
|
|
|
target_server="$user_input"
|
|
|
|
|
local tls13_support=$(validate_tls13_support "$target_server")
|
|
|
|
|
|
|
|
|
|
if [[ "$tls13_support" == "false" ]]; then
|
|
|
|
|
echo -e "${RED}该目标网站地址不支持 TLS 1.3,请重新输入!${NC}" >&2
|
|
|
|
|
generate_target_server_config
|
|
|
|
|
return
|
|
|
|
|
fi
|
|
|
|
|
fi
|
|
|
|
|
|
|
|
|
|
echo "$target_server"
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
# 私钥配置
|
|
|
|
|
function generate_private_key_config() {
|
|
|
|
|
local private_key
|
|
|
|
|
|
|
|
|
|
while true; do
|
|
|
|
|
read -p "请输入私钥 (默认随机生成私钥): " private_key
|
|
|
|
|
|
|
|
|
|
if [[ -z "$private_key" ]]; then
|
|
|
|
|
local keypair_output=$(sing-box generate reality-keypair)
|
|
|
|
|
private_key=$(echo "$keypair_output" | awk -F: '/PrivateKey/{gsub(/ /, "", $2); print $2}')
|
|
|
|
|
echo "$keypair_output" | awk -F: '/PublicKey/{gsub(/ /, "", $2); print $2}' > /tmp/public_key_temp.txt
|
|
|
|
|
break
|
|
|
|
|
fi
|
|
|
|
|
|
|
|
|
|
# 验证私钥格式是否正确
|
|
|
|
|
if openssl pkey -inform PEM -noout -text -in <(echo "$private_key") >/dev/null 2>&1; then
|
|
|
|
|
break
|
|
|
|
|
else
|
|
|
|
|
echo -e "${RED}无效的私钥,请重新输入!${NC}" >&2
|
|
|
|
|
fi
|
|
|
|
|
done
|
|
|
|
|
|
|
|
|
|
echo "$private_key"
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
# ShortIds 配置
|
|
|
|
|
function generate_short_ids_config() {
|
|
|
|
|
local short_ids=()
|
|
|
|
|
local add_more_short_ids="y"
|
|
|
|
|
local length=8
|
|
|
|
|
|
|
|
|
|
while [[ "$add_more_short_ids" == "y" ]]; do
|
|
|
|
|
if [[ ${#short_ids[@]} -eq 8 ]]; then
|
|
|
|
|
echo -e "${YELLOW}已达到最大 shortId 数量限制!${NC}" >&2
|
|
|
|
|
break
|
|
|
|
|
fi
|
|
|
|
|
|
|
|
|
|
local short_id=$(generate_short_id "$length")
|
|
|
|
|
short_ids+=("$short_id")
|
|
|
|
|
|
|
|
|
|
while true; do
|
|
|
|
|
read -p "是否继续添加 shortId?(y/n,默认为 n): " add_more_short_ids
|
|
|
|
|
add_more_short_ids=${add_more_short_ids:-n}
|
|
|
|
|
case $add_more_short_ids in
|
|
|
|
|
[yY])
|
|
|
|
|
add_more_short_ids="y"
|
|
|
|
|
break
|
|
|
|
|
;;
|
|
|
|
|
[nN])
|
|
|
|
|
add_more_short_ids="n"
|
|
|
|
|
break
|
|
|
|
|
;;
|
|
|
|
|
*)
|
|
|
|
|
echo -e "${RED}错误的选项,请重新输入!${NC}" >&2
|
|
|
|
|
;;
|
|
|
|
|
esac
|
|
|
|
|
done
|
|
|
|
|
|
|
|
|
|
if [[ "$add_more_short_ids" == "y" ]]; then
|
|
|
|
|
length=$((length - 1))
|
|
|
|
|
fi
|
|
|
|
|
done
|
|
|
|
|
|
|
|
|
|
local short_ids_config=$(printf ' "%s",\n' "${short_ids[@]}")
|
|
|
|
|
short_ids_config=${short_ids_config%,}
|
|
|
|
|
|
|
|
|
|
echo "$short_ids_config"
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
# 流控配置
|
|
|
|
|
function generate_flow_config() {
|
|
|
|
|
local flow_type="$1"
|
|
|
|
|
local transport_config=""
|
|
|
|
|
|
|
|
|
|
if [[ "$flow_type" != "" ]]; then
|
|
|
|
|
return
|
|
|
|
|
fi
|
|
|
|
|
|
|
|
|
|
local transport_type=""
|
|
|
|
|
|
|
|
|
|
while true; do
|
|
|
|
|
read -p "请选择传输层协议:
|
|
|
|
|
[1]. http
|
|
|
|
|
[2]. grpc
|
|
|
|
|
请输入选项 (默认为 http): " transport_option
|
|
|
|
|
|
|
|
|
|
case $transport_option in
|
|
|
|
|
1)
|
|
|
|
|
transport_type="http"
|
|
|
|
|
break
|
|
|
|
|
;;
|
|
|
|
|
2)
|
|
|
|
|
transport_type="grpc"
|
|
|
|
|
break
|
|
|
|
|
;;
|
|
|
|
|
"")
|
|
|
|
|
transport_type="http"
|
|
|
|
|
break
|
|
|
|
|
;;
|
|
|
|
|
*)
|
|
|
|
|
echo -e "${RED}错误的选项,请重新输入!${NC}" >&2
|
|
|
|
|
;;
|
|
|
|
|
esac
|
|
|
|
|
done
|
|
|
|
|
|
|
|
|
|
transport_config='
|
|
|
|
|
"transport": {
|
|
|
|
|
"type": "'"$transport_type"'"
|
|
|
|
|
},'
|
|
|
|
|
|
|
|
|
|
echo "$transport_config"
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
# 用户配置
|
|
|
|
|
function generate_user_config() {
|
|
|
|
|
local flow_type="$1"
|
|
|
|
|
local users=()
|
|
|
|
|
local add_more_users="y"
|
|
|
|
|
|
|
|
|
|
while [[ "$add_more_users" == "y" ]]; do
|
|
|
|
|
local user_uuid
|
|
|
|
|
|
|
|
|
|
while true; do
|
|
|
|
|
read -p "请输入用户 UUID (默认随机生成 UUID): " user_uuid
|
|
|
|
|
|
|
|
|
|
if [[ -z "$user_uuid" ]]; then
|
|
|
|
|
user_uuid=$(reality_generate_uuid)
|
|
|
|
|
break
|
|
|
|
|
fi
|
|
|
|
|
|
|
|
|
|
if [[ $user_uuid =~ ^[0-9a-fA-F]{8}-([0-9a-fA-F]{4}-){3}[0-9a-fA-F]{12}$ ]]; then
|
|
|
|
|
break
|
|
|
|
|
else
|
|
|
|
|
echo -e "${RED}无效的 UUID,请重新输入!${NC}" >&2
|
|
|
|
|
fi
|
|
|
|
|
done
|
|
|
|
|
|
|
|
|
|
users+=('
|
|
|
|
|
{
|
|
|
|
|
"uuid": "'"$user_uuid"'",
|
|
|
|
|
"flow": "'"$flow_type"'"
|
|
|
|
|
},')
|
|
|
|
|
|
|
|
|
|
while true; do
|
|
|
|
|
read -p "是否继续添加用户?(y/n,默认为 n): " add_more_users
|
|
|
|
|
add_more_users=${add_more_users:-n}
|
|
|
|
|
case $add_more_users in
|
|
|
|
|
[yY])
|
|
|
|
|
add_more_users="y"
|
|
|
|
|
break
|
|
|
|
|
;;
|
|
|
|
|
[nN])
|
|
|
|
|
add_more_users="n"
|
|
|
|
|
break
|
|
|
|
|
;;
|
|
|
|
|
*)
|
|
|
|
|
echo -e "${RED}错误的选项,请重新输入!${NC}" >&2
|
|
|
|
|
;;
|
|
|
|
|
esac
|
|
|
|
|
done
|
|
|
|
|
done
|
|
|
|
|
|
|
|
|
|
# 去除最后一个用户配置的末尾逗号
|
|
|
|
|
users[-1]=${users[-1]%,}
|
|
|
|
|
|
|
|
|
|
echo "${users[*]}"
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
# 生成 Sing-Box 配置文件
|
|
|
|
|
function generate_reality_config() {
|
|
|
|
|
local config_file="/usr/local/etc/sing-box/config.json"
|
|
|
|
|
|
|
|
|
|
local listen_port=$(generate_listen_port)
|
|
|
|
|
local flow_type=$(select_flow_type)
|
|
|
|
|
|
|
|
|
|
transport_config=$(generate_flow_config "$flow_type")
|
|
|
|
|
|
|
|
|
|
users=$(generate_user_config "$flow_type")
|
|
|
|
|
|
|
|
|
|
local server_name=$(generate_server_name_config)
|
|
|
|
|
local target_server=$(generate_target_server_config)
|
|
|
|
|
local private_key=$(generate_private_key_config)
|
|
|
|
|
local short_ids=$(generate_short_ids_config)
|
|
|
|
|
|
|
|
|
|
# 生成 Sing-Box 配置文件
|
|
|
|
|
local config_content='{
|
|
|
|
|
"log": {
|
|
|
|
|
"disabled": false,
|
|
|
|
|
"level": "info",
|
|
|
|
|
"timestamp": true
|
|
|
|
|
},
|
|
|
|
|
"inbounds": [
|
|
|
|
|
{
|
|
|
|
|
"type": "vless",
|
|
|
|
|
"tag": "vless-in",
|
|
|
|
|
"listen": "::",
|
|
|
|
|
"listen_port": '$listen_port',
|
|
|
|
|
"users": ['"$users"'
|
|
|
|
|
],'"$transport_config"'
|
|
|
|
|
"tls": {
|
|
|
|
|
"enabled": true,
|
|
|
|
|
"server_name": "'"$server_name"'",
|
|
|
|
|
"reality": {
|
|
|
|
|
"enabled": true,
|
|
|
|
|
"handshake": {
|
|
|
|
|
"server": "'"$target_server"'",
|
|
|
|
|
"server_port": 443
|
|
|
|
|
},
|
|
|
|
|
"private_key": "'"$private_key"'",
|
|
|
|
|
"short_id": [
|
|
|
|
|
'"$short_ids"'
|
|
|
|
|
]
|
|
|
|
|
}
|
|
|
|
|
}
|
|
|
|
|
}
|
|
|
|
|
],
|
|
|
|
|
"outbounds": [
|
|
|
|
|
{
|
|
|
|
|
"type": "direct",
|
|
|
|
|
"tag": "direct"
|
|
|
|
|
},
|
|
|
|
|
{
|
|
|
|
|
"type": "block",
|
|
|
|
|
"tag": "block"
|
|
|
|
|
}
|
|
|
|
|
]
|
|
|
|
|
}'
|
|
|
|
|
|
|
|
|
|
echo "$config_content" > "$config_file"
|
|
|
|
|
|
|
|
|
|
echo "Sing-Box 配置文件已生成并保存至 $config_file"
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
# 提取配置文件信息
|
|
|
|
|
function display_reality_config() {
|
|
|
|
|
local config_file="/usr/local/etc/sing-box/config.json"
|
|
|
|
|
|
|
|
|
|
local listen_port=$(jq -r '.inbounds[0].listen_port' "$config_file")
|
|
|
|
|
local users=$(jq -r '.inbounds[0].users[].uuid' "$config_file")
|
|
|
|
|
local flow_type=$(jq -r '.inbounds[0].users[].flow' "$config_file")
|
|
|
|
|
local transport_type=$(jq -r '.inbounds[0].transport.type' "$config_file")
|
|
|
|
|
local server_name=$(jq -r '.inbounds[0].tls.server_name' "$config_file")
|
|
|
|
|
local target_server=$(jq -r '.inbounds[0].tls.reality.handshake.server' "$config_file")
|
|
|
|
|
local short_ids=$(jq -r '.inbounds[0].tls.reality.short_id[]' "$config_file")
|
|
|
|
|
local public_key=$(cat /tmp/public_key_temp.txt)
|
|
|
|
|
|
|
|
|
|
echo -e "${GREEN}节点配置信息:${NC}"
|
|
|
|
|
echo -e "${CYAN}==================================================================${NC}"
|
|
|
|
|
echo -e "${GREEN}监听端口: $listen_port${NC}"
|
|
|
|
|
echo -e "${CYAN}------------------------------------------------------------------${NC}"
|
|
|
|
|
echo -e "${GREEN}用户 UUID:${NC}"
|
|
|
|
|
echo -e "${GREEN}$users${NC}"
|
|
|
|
|
echo -e "${CYAN}------------------------------------------------------------------${NC}"
|
|
|
|
|
echo -e "${GREEN}流控类型: $flow_type${NC}"
|
|
|
|
|
echo -e "${CYAN}------------------------------------------------------------------${NC}"
|
|
|
|
|
echo -e "${GREEN}传输层协议: $transport_type${NC}"
|
|
|
|
|
echo -e "${CYAN}------------------------------------------------------------------${NC}"
|
|
|
|
|
echo -e "${GREEN}ServerName: $server_name${NC}"
|
|
|
|
|
echo -e "${CYAN}------------------------------------------------------------------${NC}"
|
|
|
|
|
echo -e "${GREEN}目标网站地址: $target_server${NC}"
|
|
|
|
|
echo -e "${CYAN}------------------------------------------------------------------${NC}"
|
|
|
|
|
echo -e "${GREEN}Short ID:${NC}"
|
|
|
|
|
echo -e "${GREEN}$short_ids${NC}"
|
|
|
|
|
echo -e "${CYAN}------------------------------------------------------------------${NC}"
|
|
|
|
|
echo -e "${GREEN}PublicKey: $public_key${NC}"
|
|
|
|
|
echo -e "${CYAN}==================================================================${NC}"
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
# 重启 sing-box 服务
|
|
|
|
|
function restart_sing_box_service() {
|
|
|
|
|
echo "重启 sing-box 服务..."
|
|
|
|
|
systemctl restart sing-box
|
|
|
|
|
|
|
|
|
|
if [[ $? -eq 0 ]]; then
|
|
|
|
|
echo "sing-box 服务已重启。"
|
|
|
|
|
else
|
|
|
|
|
echo -e "${RED}重启 sing-box 服务失败。${NC}"
|
|
|
|
|
fi
|
|
|
|
|
|
|
|
|
|
systemctl status sing-box
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
# 重启 naiveproxy 服务
|
|
|
|
|
function restart_naiveproxy_service() {
|
|
|
|
|
echo "重启 naiveproxy 服务..."
|
|
|
|
|
systemctl reload caddy
|
|
|
|
|
|
|
|
|
|
if [[ $? -eq 0 ]]; then
|
|
|
|
|
echo "naiveproxy 服务已重启。"
|
|
|
|
|
else
|
|
|
|
|
echo -e "${RED}重启 sing-box 服务失败。${NC}"
|
|
|
|
|
fi
|
|
|
|
|
|
|
|
|
|
systemctl status caddy
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
# 重启 TUIC
|
|
|
|
|
function restart_tuic() {
|
|
|
|
|
echo "重启 TUIC 服务..."
|
|
|
|
|
systemctl restart tuic.service
|
|
|
|
|
echo -e "${GREEN}TUIC 已重启...${NC}"
|
|
|
|
|
systemctl status tuic.service
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
# 卸载 sing-box
|
|
|
|
|
function uninstall_sing_box() {
|
|
|
|
|
echo "开始卸载 sing-box..."
|
|
|
|
|
|
|
|
|
|
systemctl stop sing-box
|
|
|
|
|
|
|
|
|
|
# 删除文件和文件夹
|
|
|
|
|
echo "删除文件和文件夹..."
|
|
|
|
|
rm -rf /usr/local/bin/sing-box
|
|
|
|
|
rm -rf /usr/local/etc/sing-box
|
|
|
|
|
rm -rf /etc/systemd/system/sing-box.service
|
|
|
|
|
systemctl daemon-reload
|
|
|
|
|
|
|
|
|
|
echo "sing-box 卸载完成。"
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
# 函数:卸载 NaiveProxy
|
|
|
|
|
function uninstall_naiveproxy() {
|
|
|
|
|
echo "开始卸载 NaiveProxy..."
|
|
|
|
|
systemctl stop caddy
|
|
|
|
|
systemctl disable caddy
|
|
|
|
|
rm /etc/systemd/system/caddy.service
|
|
|
|
|
rm /usr/local/etc/caddy/caddy.json
|
|
|
|
|
rm /usr/bin/caddy
|
|
|
|
|
systemctl daemon-reload
|
|
|
|
|
echo "NaiveProxy 卸载完成。"
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
# 卸载 TUIC
|
|
|
|
|
function uninstall_tuic() {
|
|
|
|
|
echo "卸载 TUIC 服务..."
|
|
|
|
|
systemctl stop tuic.service
|
|
|
|
|
systemctl disable tuic.service
|
|
|
|
|
rm /etc/systemd/system/tuic.service
|
|
|
|
|
rm /usr/local/etc/tuic/config.json
|
|
|
|
|
rm /usr/local/bin/tuic
|
|
|
|
|
echo -e "${GREEN}TUIC 服务已卸载...${NC}"
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
function Direct_extract_config_info() {
|
|
|
|
|
local local_ip
|
|
|
|
|
local_ip=$(curl -s http://ifconfig.me)
|
|
|
|
|
|
|
|
|
|
echo "========= 安装完成 ========="
|
|
|
|
|
echo "本机 IP 地址: $local_ip"
|
|
|
|
|
echo "监听端口: $listen_port"
|
|
|
|
|
echo "目标地址: $override_address"
|
|
|
|
|
echo "目标端口: $override_port"
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
function Shadowsocks_extract_config_info() {
|
|
|
|
|
local local_ip
|
|
|
|
|
local_ip=$(curl -s http://ifconfig.me)
|
|
|
|
|
|
|
|
|
|
echo "========= 配置完成 ========="
|
|
|
|
|
echo "本机 IP 地址: $local_ip"
|
|
|
|
|
echo "监听端口: $listen_port"
|
|
|
|
|
echo "加密方式: $ss_method"
|
|
|
|
|
echo "密码: $ss_password"
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
function NaiveProxy_extract_config_info() {
|
|
|
|
|
|
|
|
|
|
echo -e "${GREEN}NaiveProxy节点配置信息:${NC}"
|
|
|
|
|
echo -e "监听端口: ${GREEN}$listen_port${NC}"
|
|
|
|
|
echo -e "用 户 名: ${GREEN}$auth_user${NC}"
|
|
|
|
|
echo -e "密 码: ${GREEN}$auth_pass${NC}"
|
|
|
|
|
echo -e "域 名: ${GREEN}$domain${NC}"
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
function Direct_install() {
|
|
|
|
|
install_dependencies
|
|
|
|
|
enable_bbr
|
|
|
|
|
select_sing_box_install_option
|
|
|
|
|
configure_sing_box_service
|
|
|
|
|
check_sing_box_folder
|
|
|
|
|
set_listen_port
|
|
|
|
|
Direct_override_address
|
|
|
|
|
Direct_override_port
|
|
|
|
|
Direct_write_config_file
|
|
|
|
|
check_firewall_configuration
|
|
|
|
|
systemctl enable sing-box
|
|
|
|
|
systemctl start sing-box
|
|
|
|
|
Direct_extract_config_info
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
function Shadowsocks_install() {
|
|
|
|
|
install_dependencies
|
|
|
|
|
enable_bbr
|
|
|
|
|
select_sing_box_install_option
|
|
|
|
|
configure_sing_box_service
|
|
|
|
|
check_sing_box_folder
|
|
|
|
|
set_listen_port
|
|
|
|
|
ss_encryption_method
|
|
|
|
|
ss_write_sing_box_config
|
|
|
|
|
check_firewall_configuration
|
|
|
|
|
systemctl enable sing-box
|
|
|
|
|
systemctl start sing-box
|
|
|
|
|
Shadowsocks_extract_config_info
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
function NaiveProxy_install() {
|
|
|
|
|
install_dependencies
|
|
|
|
|
enable_bbr
|
|
|
|
|
install_go
|
|
|
|
|
install_caddy
|
|
|
|
|
check_caddy_folder
|
|
|
|
|
set_listen_port
|
|
|
|
|
generate_caddy_auth_user
|
|
|
|
|
generate_caddy_auth_pass
|
|
|
|
|
get_caddy_fake_site
|
|
|
|
|
get_caddy_domain
|
|
|
|
|
create_caddy_config
|
|
|
|
|
check_firewall_configuration
|
|
|
|
|
test_caddy_config
|
|
|
|
|
configure_caddy_service
|
|
|
|
|
systemctl daemon-reload
|
|
|
|
|
systemctl enable caddy
|
|
|
|
|
systemctl start caddy
|
|
|
|
|
systemctl reload caddy
|
|
|
|
|
NaiveProxy_extract_config_info
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
function tuic_install() {
|
|
|
|
|
install_dependencies
|
|
|
|
|
enable_bbr
|
|
|
|
|
create_tuic_directory
|
|
|
|
|
download_tuic
|
|
|
|
|
generate_tuic_config
|
|
|
|
|
check_firewall_configuration
|
|
|
|
|
ask_certificate_option
|
|
|
|
|
configure_tuic_service
|
|
|
|
|
systemctl daemon-reload
|
|
|
|
|
systemctl enable tuic.service
|
|
|
|
|
systemctl start tuic.service
|
|
|
|
|
systemctl restart tuic.service
|
|
|
|
|
display_tuic_config
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
function Hysteria_install() {
|
|
|
|
|
install_dependencies
|
|
|
|
|
enable_bbr
|
|
|
|
|
select_sing_box_install_option
|
|
|
|
|
check_sing_box_folder
|
|
|
|
|
generate_Hysteria_config
|
|
|
|
|
check_firewall_configuration
|
|
|
|
|
ask_certificate_option
|
|
|
|
|
configure_sing_box_service
|
|
|
|
|
systemctl daemon-reload
|
|
|
|
|
systemctl enable sing-box
|
|
|
|
|
systemctl start sing-box
|
|
|
|
|
display_Hysteria_config_info
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
function shadowtls_install() {
|
|
|
|
|
install_dependencies
|
|
|
|
|
enable_bbr
|
|
|
|
|
select_sing_box_install_option
|
|
|
|
|
check_sing_box_folder
|
|
|
|
|
configure_shadowtls_config_file
|
|
|
|
|
check_firewall_configuration
|
|
|
|
|
configure_sing_box_service
|
|
|
|
|
systemctl daemon-reload
|
|
|
|
|
systemctl enable sing-box
|
|
|
|
|
systemctl start sing-box
|
|
|
|
|
display_shadowtls_config
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
function reality_install() {
|
|
|
|
|
install_dependencies
|
|
|
|
|
enable_bbr
|
|
|
|
|
select_sing_box_install_option
|
|
|
|
|
check_sing_box_folder
|
|
|
|
|
generate_reality_config
|
|
|
|
|
check_firewall_configuration
|
|
|
|
|
configure_sing_box_service
|
|
|
|
|
systemctl daemon-reload
|
|
|
|
|
systemctl enable sing-box
|
|
|
|
|
systemctl start sing-box
|
|
|
|
|
display_reality_config
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
# 主菜单
|
|
|
|
|
function main_menu() {
|
|
|
|
|
echo -e "${GREEN} ------------------------------------------------------------------------------------ ${NC}"
|
|
|
|
|
echo -e "${GREEN} | 欢迎使用 Reality 安装程序 |${NC}"
|
|
|
|
|
echo -e "${GREEN} | 项目地址:https://github.com/TinrLin |${NC}"
|
|
|
|
|
echo -e "${GREEN} ------------------------------------------------------------------------------------${NC}"
|
|
|
|
|
echo -e "${CYAN}请选择要执行的操作:${NC}"
|
|
|
|
|
echo -e " ${CYAN}[01]. TUIC${NC}"
|
|
|
|
|
echo -e " ${CYAN}[02]. Vless${NC}"
|
|
|
|
|
echo -e " ${CYAN}[03]. Direct${NC}"
|
|
|
|
|
echo -e " ${CYAN}[04]. Hysteria${NC}"
|
|
|
|
|
echo -e " ${CYAN}[05]. ShadowTLS${NC}"
|
|
|
|
|
echo -e " ${CYAN}[06]. NaiveProxy${NC}"
|
|
|
|
|
echo -e " ${CYAN}[07]. Shadowsocks${NC}"
|
|
|
|
|
echo -e " ${CYAN}[08]. 重启 TUIC 服务${NC}"
|
|
|
|
|
echo -e " ${CYAN}[09]. 重启 Caddy 服务${NC}"
|
|
|
|
|
echo -e " ${CYAN}[10]. 重启 sing-box 服务${NC}"
|
|
|
|
|
echo -e " ${CYAN}[11]. 卸载 TUIC 服务${NC}"
|
|
|
|
|
echo -e " ${CYAN}[12]. 卸载 Caddy 服务${NC}"
|
|
|
|
|
echo -e " ${CYAN}[13]. 卸载 sing-box 服务${NC}"
|
|
|
|
|
echo -e " ${CYAN}[00]. 退出脚本${NC}"
|
|
|
|
|
|
|
|
|
|
local choice
|
|
|
|
|
read -p "请选择 [0-15]: " choice
|
|
|
|
|
|
|
|
|
|
case $choice in
|
|
|
|
|
1)
|
|
|
|
|
tuic_install
|
|
|
|
|
;;
|
|
|
|
|
2)
|
|
|
|
|
reality_install
|
|
|
|
|
;;
|
|
|
|
|
3)
|
|
|
|
|
Direct_install
|
|
|
|
|
;;
|
|
|
|
|
4)
|
|
|
|
|
Hysteria_install
|
|
|
|
|
;;
|
|
|
|
|
5)
|
|
|
|
|
shadowtls_install
|
|
|
|
|
;;
|
|
|
|
|
6)
|
|
|
|
|
NaiveProxy_install
|
|
|
|
|
;;
|
|
|
|
|
7)
|
|
|
|
|
Shadowsocks_install
|
|
|
|
|
;;
|
|
|
|
|
8)
|
|
|
|
|
restart_tuic
|
|
|
|
|
;;
|
|
|
|
|
|
|
|
|
|
9)
|
|
|
|
|
restart_naiveproxy_service
|
|
|
|
|
;;
|
|
|
|
|
10)
|
|
|
|
|
restart_sing_box_service
|
|
|
|
|
;;
|
|
|
|
|
11)
|
|
|
|
|
uninstall_tuic
|
|
|
|
|
;;
|
|
|
|
|
12)
|
|
|
|
|
uninstall_naiveproxy
|
|
|
|
|
;;
|
|
|
|
|
13)
|
|
|
|
|
uninstall_sing_box
|
|
|
|
|
;;
|
|
|
|
|
0)
|
|
|
|
|
echo -e "${GREEN}感谢使用 Reality 安装脚本!再见!${NC}"
|
|
|
|
|
exit 0
|
|
|
|
|
;;
|
|
|
|
|
*)
|
|
|
|
|
echo -e "${RED}无效的选择,请重新输入。${NC}"
|
|
|
|
|
main_menu
|
|
|
|
|
;;
|
|
|
|
|
esac
|
2023-07-28 11:28:46 +08:00
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
|
2023-07-29 12:09:39 +08:00
|
|
|
|
main_menu
|