Compare commits
No commits in common. "master" and "v1.0" have entirely different histories.
2
.gitignore
vendored
2
.gitignore
vendored
@ -1,2 +0,0 @@
|
||||
config/config.json
|
||||
acme/
|
||||
113
README.md
113
README.md
@ -1,43 +1,114 @@
|
||||
# 使用说明
|
||||
|
||||
## 项目描述
|
||||
|
||||
基于 docker 容器的 hysteria2 服务器端节点搭建
|
||||
项目使用自有证书搭建, 无需要准备域名.
|
||||
默认使用`bing.com`域名作为伪装.
|
||||
|
||||
## 快速开始
|
||||
|
||||
提前安装下列软件
|
||||
|
||||
- wget
|
||||
### 部署服务器端
|
||||
确认安装好下列软件
|
||||
- docker
|
||||
- docker-compose
|
||||
- git
|
||||
- curl
|
||||
|
||||
下载项目代码
|
||||
|
||||
```bash
|
||||
git clone https://gitea.9001001.xyz/William/hysteria_docker.git
|
||||
git clone https://gittea.wingogo.top/William/hysteria_docker.git
|
||||
```
|
||||
|
||||
进入项目目录
|
||||
|
||||
```bash
|
||||
cd hysteria_docker
|
||||
```
|
||||
|
||||
运行安装脚本,选择选项 1(一键部署)
|
||||
|
||||
配置初始化, **第一次运行必须执行**
|
||||
```bash
|
||||
bash ./install.sh
|
||||
bash ./bin/init.sh
|
||||
```
|
||||
|
||||
### 电脑配置客户端
|
||||
启动项目
|
||||
```bash
|
||||
docker-compose up -d
|
||||
```
|
||||
|
||||
查看日志
|
||||
```bash
|
||||
docker-compose logs | head -n 50
|
||||
```
|
||||
|
||||
### 查看分享链接
|
||||
进入项目目录, 执行以下命令
|
||||
```bash
|
||||
bash ./bin/print_share_link.sh
|
||||
```
|
||||
|
||||
### 客户端配置
|
||||
客户端软件(选择其中一种)
|
||||
- [V2rayN](https://github.com/2dust/v2rayN/releases)
|
||||
- [Nekoray](https://github.com/MatsuriDayo/nekoray/releases)
|
||||
- [v2rayN](https://github.com/2dust/v2rayN/releases)
|
||||
- [nekoray](https://github.com/MatsuriDayo/nekoray/releases)
|
||||
|
||||
客户端配置
|
||||
|
||||
- (方法1)把分享链接直接粘贴到客户端
|
||||
|
||||
- (方法2)手工输入配置
|
||||
无域名,使用IP搭建,download-bandwidth 根据实际填写
|
||||
|
||||
```yaml
|
||||
地址: 服务器ip
|
||||
端口: 8443 # 服务器端端口
|
||||
密码: RhCLi%T&MFe5&de # 服务器端密码
|
||||
传输安全层: tls
|
||||
SNI: bing.com # 伪装域名
|
||||
跳过证书验证: true
|
||||
download-bandwidth=200
|
||||
```
|
||||
|
||||
## 服务器端,修改域名
|
||||
如果需要修改其他伪装域名, 进入项目目录, 执行以下命令
|
||||
```bash
|
||||
bash ./bin/set_domain.sh expedia.com
|
||||
```
|
||||
|
||||
## 服务器端,修改端口
|
||||
修改`config.json`配置文件
|
||||
```json
|
||||
{
|
||||
"listen": ":9999", // 改为其他端口
|
||||
// 省略其他代码...
|
||||
}
|
||||
```
|
||||
|
||||
## 服务器端, 升级镜像
|
||||
```bash
|
||||
bash ./bin/update_docker_images.sh
|
||||
```
|
||||
|
||||
## 文件解析
|
||||
### 文件`set_domain.sh`
|
||||
用来生成自签证书和设置伪装域名
|
||||
```bash
|
||||
# 生成自签名的 ECDSA 证书并设置有效期为 100 年
|
||||
|
||||
# 使用 OpenSSL 的证书请求工具
|
||||
openssl req \
|
||||
-x509 \ # 生成自签名的X.509证书
|
||||
-nodes \ # 不使用加密算法保护私钥
|
||||
-newkey ec:<(openssl ecparam -name prime256v1) \ # 生成 ECDSA 私钥和公钥,使用 prime256v1 曲线
|
||||
-keyout /etc/hysteria/server.key \ # 将生成的私钥保存到指定路径
|
||||
-out /etc/hysteria/server.crt \ # 将生成的自签名证书保存到指定路径
|
||||
-subj "/CN=bing.com" \ # 设置证书的主题字段,CN是 Common Name (CN)
|
||||
-days 36500 \ # 设置证书的有效期为 36500 天(约100年)
|
||||
```
|
||||
- `openssl`是一个开源的加密工具包,提供了一系列用于处理安全通信的命令和库。它支持多种加密算法、数字证书和相关的功能,包括生成和签名证书、创建和验证数字签名、加解密数据等。常见用途包括创建和管理SSL/TLS证书、进行加密通信以及执行与加密相关的各种操作。
|
||||
|
||||
- `-subj `参数用于在 OpenSSL 命令中设置证书主题字段,其中 "/CN=example.com" 指定了通用名称 (Common Name, CN),表示证书关联的主机名。
|
||||
|
||||
|
||||
### 文件`server.crt`和`server.key`是证书文件
|
||||
|
||||
### 文件`config.json`是服务器端配置文件
|
||||
|
||||
## 参考
|
||||
|
||||
- https://v2.hysteria.network/zh/docs/getting-started/Server/
|
||||
- https://v2rayssr.com/hysteria2.html
|
||||
- https://www.iiiam.in/articles/server/deploy-hysteria2
|
||||
- https://v2.hysteria.network/zh/docs/getting-started/Server/
|
||||
- https://v2rayssr.com/hysteria2.html
|
||||
- https://www.iiiam.in/articles/server/deploy-hysteria2
|
||||
|
||||
@ -1,110 +0,0 @@
|
||||
#!/bin/bash
|
||||
|
||||
|
||||
create_config_with_tls_cert() {
|
||||
local script_dir="$(cd "$(dirname "${BASH_SOURCE[0]}")" && pwd)"
|
||||
local config_dir="$script_dir/../config"
|
||||
local config_file="$config_dir/config.json"
|
||||
|
||||
cp "$config_dir/template/tls_cert_config.json" "$config_file"
|
||||
|
||||
# 设置端口
|
||||
change_port
|
||||
|
||||
# 设置密码
|
||||
update_password
|
||||
|
||||
# 设置混淆密码
|
||||
update_obfs_password
|
||||
|
||||
# 获取邮箱
|
||||
read -p "请输入你的邮箱(可留空): " user_email
|
||||
if [[ -z "$user_email" ]]; then
|
||||
user_email="example@example.com"
|
||||
fi
|
||||
|
||||
# 获取域名
|
||||
read -p "请输入你的域名 (例如: example.com): " user_domain
|
||||
while [[ -z "$user_domain" ]]; do
|
||||
echo "[错误] 域名不能为空"
|
||||
read -p "请输入你的域名: " user_domain
|
||||
done
|
||||
|
||||
# 获取 Cloudflare API Token
|
||||
read -p "请输入你的 Cloudflare API Token: " cloudflare_token
|
||||
while [[ -z "$cloudflare_token" ]]; do
|
||||
echo "[错误] Cloudflare API Token 不能为空"
|
||||
read -p "请输入你的 Cloudflare API Token: " cloudflare_token
|
||||
done
|
||||
|
||||
# 使用 sed 替换邮箱
|
||||
sed -i "s/你的邮箱/$user_email/g" "$config_file"
|
||||
|
||||
# 替换域名 (在 domains 数组和 masquerade url 中)
|
||||
sed -i "s/你的域名/$user_domain/g" "$config_file"
|
||||
|
||||
# 替换 Cloudflare API Token
|
||||
sed -i "s/你的cloudflare_api_token/$cloudflare_token/g" "$config_file"
|
||||
|
||||
green "创建配置成功"
|
||||
}
|
||||
|
||||
create_self_tls_config() {
|
||||
local script_dir="$(cd "$(dirname "${BASH_SOURCE[0]}")" && pwd)"
|
||||
local config_dir="$script_dir/../config"
|
||||
|
||||
cp "$config_dir/template/self_cert_config.json" "$config_dir/config.json"
|
||||
|
||||
# 设置端口
|
||||
change_port
|
||||
|
||||
# 设置密码
|
||||
update_password
|
||||
|
||||
# 设置混淆密码
|
||||
update_obfs_password
|
||||
|
||||
# 生成自签名证书和设置域名
|
||||
gen_self_tls "bing.com"
|
||||
|
||||
green "创建配置成功"
|
||||
}
|
||||
|
||||
create_config(){
|
||||
local script_dir="$(cd "$(dirname "${BASH_SOURCE[0]}")" && pwd)"
|
||||
local config_file="$script_dir/../config/config.json"
|
||||
|
||||
# 如果配置文件不存在, 创建空白配置文件
|
||||
if [ ! -e "$config_file" ]; then
|
||||
touch "$config_file"
|
||||
fi
|
||||
|
||||
local config_password=$(jq -r '.auth.password' "$config_file")
|
||||
if [ -s "$config_file" ] && [ "$config_password" != "你的密码" ]; then
|
||||
local regenerate
|
||||
read -p "检测到配置已存在,是否重新生成配置?(y/n): " regenerate
|
||||
if [ "$regenerate" != "y" ] && [ "$regenerate" != "Y" ]; then
|
||||
echo "取消重新生成配置."
|
||||
return
|
||||
fi
|
||||
fi
|
||||
|
||||
echo "请选择配置类型:"
|
||||
echo "1. 自签名证书配置"
|
||||
echo "2. tls证书配置"
|
||||
local choice
|
||||
read -p "输入您的选择: " choice
|
||||
case $choice in
|
||||
1)
|
||||
echo "重置为自签名证书配置..."
|
||||
create_self_tls_config
|
||||
;;
|
||||
2)
|
||||
echo "重置为tls证书配置..."
|
||||
create_config_with_tls_cert
|
||||
;;
|
||||
*)
|
||||
echo "无效的选择, 请重新选择."
|
||||
;;
|
||||
esac
|
||||
}
|
||||
@ -1,21 +0,0 @@
|
||||
#!/bin/bash
|
||||
|
||||
|
||||
# 生成自签名证书
|
||||
gen_self_tls() {
|
||||
local domain="${1:-bing.com}"
|
||||
local script_dir="$(cd "$(dirname "${BASH_SOURCE[0]}")" && pwd)"
|
||||
local key_dir="$script_dir/../tls/self-tls"
|
||||
|
||||
# 生成自签名证书
|
||||
mkdir -p "$key_dir"
|
||||
openssl req -x509 -nodes -newkey ec:<(openssl ecparam -name prime256v1) \
|
||||
-keyout "$key_dir/server.key" \
|
||||
-out "$key_dir/server.crt" \
|
||||
-subj "/CN=$domain" \
|
||||
-days 36500
|
||||
|
||||
# 更新config.json文件中的域名信息
|
||||
local config_file="$script_dir/../config/config.json"
|
||||
modify_json_file "$config_file" "masquerade.proxy.url" "https://$domain"
|
||||
}
|
||||
12
bin/init.sh
Normal file
12
bin/init.sh
Normal file
@ -0,0 +1,12 @@
|
||||
#!/bin/bash
|
||||
|
||||
script_dir=$(cd "$(dirname "$0")"; pwd) # 脚本绝对路径
|
||||
|
||||
# 更新密码
|
||||
bash "$script_dir/update_password.sh"
|
||||
|
||||
# 更新证书和设置域名
|
||||
bash "$script_dir/set_domain.sh" "bing.com"
|
||||
|
||||
# 打印分享链接
|
||||
bash "$script_dir/print_share_link.sh"
|
||||
@ -1,56 +1,32 @@
|
||||
#!/bin/bash
|
||||
|
||||
# 检查 jq 命令是否可用
|
||||
if ! command -v jq &> /dev/null
|
||||
then
|
||||
echo "jq 命令未安装,请先安装 jq。"
|
||||
exit 1
|
||||
fi
|
||||
|
||||
print_share_link() {
|
||||
local script_dir="$(cd "$(dirname "${BASH_SOURCE[0]}")" && pwd)"
|
||||
local config_dir=$(readlink -f "$script_dir/../config")
|
||||
local config_file="$config_dir/config.json"
|
||||
|
||||
# 检查jq是否安装
|
||||
check_jq
|
||||
|
||||
# 检查配置文件是否存在
|
||||
if [ ! -f "$config_file" ]; then
|
||||
red "error: 配置文件未生成, 查看配置失败"
|
||||
echo '请选择"生成配置 / 重置配置"'
|
||||
exit 1
|
||||
fi
|
||||
# 获取脚本所在目录的上级目录路径
|
||||
script_dir=$(cd "$(dirname "$0")"; pwd)
|
||||
|
||||
# 检查是否已启动过容器
|
||||
local password=$(jq -r '.auth.password' "$config_file")
|
||||
if [ "$password" = "你的密码" ]; then
|
||||
red "error: 容器未启动过, 查看配置失败"
|
||||
echo '请选择"启动容器"'
|
||||
exit 1
|
||||
fi
|
||||
# 读取 config.json 文件
|
||||
config=$(cat "$script_dir/../config.json")
|
||||
|
||||
# 检查是否使用ACME证书
|
||||
local allowInsecure=1 # 默认跳过证书验证
|
||||
if jq -e 'has("acme")' "$config_file" > /dev/null 2>&1; then
|
||||
allowInsecure=0 # 不跳过证书验证
|
||||
fi
|
||||
# 提取所需信息
|
||||
password=$(echo "$config" | jq -r '.auth.password')
|
||||
sni=$(echo "$config" | jq -r '.masquerade.proxy.url' | awk -F'/' '{print $3}')
|
||||
ipv4=$(curl -4 -sSL --connect-timeout 3 --retry 2 ip.sb || echo "null") # 本机IPV4地址
|
||||
port=$(echo "$config" | jq -r '.listen' | cut -d':' -f2) # 端口号
|
||||
|
||||
# 读取配置文件内容
|
||||
local config=$(cat "$config_file")
|
||||
|
||||
# 提取所需信息
|
||||
password=$(echo "$config" | jq -r '.auth.password')
|
||||
local sni=$(echo "$config" | jq -r '.masquerade.proxy.url' | awk -F'/' '{print $3}')
|
||||
local ipv4=$(curl -4 -sSL --connect-timeout 3 --retry 2 ip.sb || echo "null")
|
||||
local port=$(echo "$config" | jq -r '.listen' | cut -d':' -f2)
|
||||
local obfs_password=$(echo "$config" | jq -r '.obfs.salamander.password')
|
||||
|
||||
# 构建分享链接
|
||||
local share_link="hysteria2://${password}@${ipv4}:${port}/?sni=${sni}&insecure=1&obfs-password=${obfs_password}&allowInsecure=${allowInsecure}#Hysteria2节点"
|
||||
|
||||
# 输出分享链接
|
||||
echo -e "\033[32m"
|
||||
echo "IPV4: $ipv4"
|
||||
echo "port: $port"
|
||||
echo "password: $password"
|
||||
echo "sni: $sni"
|
||||
echo "混淆密码: $obfs_password"
|
||||
echo ""
|
||||
echo "分享链接: $share_link"
|
||||
echo -e "\033[0m"
|
||||
}
|
||||
# 构建分享链接
|
||||
share_link="hysteria2://${password}@${ipv4}:${port}/?sni=${sni}&insecure=1#${ipv4}"
|
||||
|
||||
# 输出分享链接
|
||||
echo -e "\033[32m"
|
||||
echo "IPV4: $ipv4"
|
||||
echo "port: $port"
|
||||
echo "password: $password"
|
||||
echo "sni: $sni"
|
||||
echo "分享链接: $share_link"
|
||||
echo -e "\033[0m"
|
||||
@ -1,3 +0,0 @@
|
||||
## 说明
|
||||
|
||||
这个文件夹的文件用于被其他主机(本地电脑)远程调用. 不要导入使用.
|
||||
@ -1,28 +0,0 @@
|
||||
#!/bin/bash
|
||||
|
||||
|
||||
update_docker_images(){
|
||||
local script_dir="$(cd "$(dirname "${BASH_SOURCE[0]}")" && pwd)/../" # 脚本文件绝对路径
|
||||
local docker_compose_file="$script_dir/../docker-compose.yml" # docker-compose.yml文件路径
|
||||
|
||||
# 检查是否存在 docker-compose.yml 文件
|
||||
if [ ! -f $docker_compose_file ]; then
|
||||
echo "Error: docker-compose.yml 文件不存在."
|
||||
exit 1
|
||||
fi
|
||||
|
||||
echo "正在关闭容器.."
|
||||
docker-compose -f $docker_compose_file down
|
||||
|
||||
echo "正在更新镜像.."
|
||||
docker-compose -f $docker_compose_file pull
|
||||
|
||||
echo "正在删除未使用的镜像..."
|
||||
docker image prune -f
|
||||
|
||||
echo "正在启动容器.."
|
||||
docker-compose -f $docker_compose_file up -d
|
||||
}
|
||||
|
||||
|
||||
update_docker_images
|
||||
16
bin/run.sh
16
bin/run.sh
@ -1,16 +0,0 @@
|
||||
#!/bin/bash
|
||||
|
||||
|
||||
run() {
|
||||
local script_dir="$(cd "$(dirname "${BASH_SOURCE[0]}")" && pwd)"
|
||||
local compose_file="$script_dir/../docker-compose.yml"
|
||||
|
||||
# 如果容器已经启动, 则先停止容器
|
||||
if docker-compose -f "$compose_file" ps | grep -q "Up"; then
|
||||
docker-compose -f "$compose_file" down
|
||||
fi
|
||||
|
||||
# 启动docker容器
|
||||
docker-compose -f "$compose_file" up -d
|
||||
|
||||
}
|
||||
27
bin/set_domain.sh
Normal file
27
bin/set_domain.sh
Normal file
@ -0,0 +1,27 @@
|
||||
#!/bin/bash
|
||||
|
||||
# 当前脚本所在目录的绝对路径
|
||||
script_dir="$(dirname "$(realpath "$0")")"
|
||||
|
||||
# 导入utils文件夹中的jq_util.sh脚本
|
||||
source "$script_dir/utils/jq_util.sh"
|
||||
|
||||
gen_cert() {
|
||||
local domain="$1"
|
||||
local key_dir="$script_dir/../key" # key目录绝对路径
|
||||
# 使用openssl生成自签名证书,设置密钥和有效期,并指定域名信息
|
||||
openssl req -x509 -nodes -newkey ec:<(openssl ecparam -name prime256v1) -keyout "$key_dir/server.key" -out "$key_dir/server.crt" -subj "/CN=$domain" -days 36500
|
||||
}
|
||||
|
||||
update_config() {
|
||||
local domain="$1"
|
||||
local config_file="$script_dir/../config.json" # config.json文件路径
|
||||
# 使用jq_util.sh脚本中的modify_json_file函数修改config.json文件中的域名信息
|
||||
modify_json_file $config_file "masquerade.proxy.url" "https://$domain"
|
||||
}
|
||||
|
||||
domain="${1:-bing.com}" # 域名, 默认为"bing.com"
|
||||
gen_cert "$domain" # 生成证书
|
||||
update_config "$domain" # 更新config.json文件
|
||||
|
||||
|
||||
@ -1,25 +1,19 @@
|
||||
#!/bin/bash
|
||||
|
||||
# 更新容器的函数
|
||||
update_docker_images() {
|
||||
local script_dir="$(cd "$(dirname "${BASH_SOURCE[0]}")" && pwd)"
|
||||
local docker_compose_file=$(readlink -f "$script_dir/../docker-compose.yml")
|
||||
|
||||
# 检查是否存在 docker-compose.yml 文件
|
||||
if [ ! -f "$docker_compose_file" ]; then
|
||||
echo "Error: docker-compose.yml 文件不存在."
|
||||
exit 1
|
||||
fi
|
||||
|
||||
echo "正在关闭容器.."
|
||||
docker-compose -f "$docker_compose_file" down
|
||||
|
||||
echo "正在更新镜像.."
|
||||
docker-compose -f "$docker_compose_file" pull
|
||||
|
||||
echo "正在删除未使用的镜像..."
|
||||
docker image prune -f
|
||||
|
||||
echo "正在启动容器.."
|
||||
docker-compose -f "$docker_compose_file" up -d
|
||||
}
|
||||
script_dir="$(dirname "$(realpath "$0")")" # 当前脚本所在目录的绝对路径
|
||||
docker_compose_file=$(readlink -f "$script_dir/../docker-compose.yml") # docker-compose.yaml文件路径
|
||||
|
||||
# 检查是否存在 docker-compose.yml 文件
|
||||
if [ ! -f $docker_compose_file ]; then
|
||||
echo "Error: docker-compose.yml 文件不存在."
|
||||
exit 1
|
||||
fi
|
||||
|
||||
echo "正在关闭容器.."
|
||||
docker-compose -f $docker_compose_file down
|
||||
|
||||
echo "正在更新镜像.."
|
||||
docker-compose -f $docker_compose_file pull
|
||||
|
||||
echo "正在启动容器.."
|
||||
docker-compose -f $docker_compose_file up -d
|
||||
@ -1,31 +0,0 @@
|
||||
#!/bin/bash
|
||||
|
||||
|
||||
# 修改域名
|
||||
update_domain(){
|
||||
local script_dir="$(cd "$(dirname "${BASH_SOURCE[0]}")" && pwd)" # 脚本文件夹绝对路径
|
||||
local config_file="$script_dir/../config/config.json"
|
||||
|
||||
# 检查jq是否安装
|
||||
check_jq
|
||||
|
||||
# 输入新的domain
|
||||
local domain
|
||||
read -p "请输入新的域名: " domain
|
||||
|
||||
# 如果输入为空,退出脚本
|
||||
if [[ -z "$domain" ]]; then
|
||||
echo "输入域名为空,退出脚本"
|
||||
exit 1
|
||||
fi
|
||||
|
||||
modify_json_file "$config_file" ".masquerade.proxy.url" "https://$domain"
|
||||
|
||||
# 是否存在acme域名, 存在则修改
|
||||
local acme_exists=$(jq -r 'has("acem")' "$config_file")
|
||||
if [[ "$acme_exists" == "true" ]]; then
|
||||
modify_json_file "$config_file" ".acme.domains[0]" "$domain"
|
||||
fi
|
||||
|
||||
echo "修改域名成功"
|
||||
}
|
||||
@ -1,18 +0,0 @@
|
||||
#!/bin/bash
|
||||
|
||||
# 更新密码的函数
|
||||
update_obfs_password() {
|
||||
local script_dir="$(cd "$(dirname "${BASH_SOURCE[0]}")" && pwd)"
|
||||
local config_file="$script_dir/../config/config.json"
|
||||
|
||||
# 检查jq是否安装
|
||||
check_jq
|
||||
|
||||
# 生成一个长度为16的随机密码
|
||||
local new_password=$(gen_password 16)
|
||||
|
||||
# 使用jq_util.sh中的modify_json_file函数修改config.json文件中的auth.password字段
|
||||
modify_json_file "$config_file" 'obfs.salamander.password' "$new_password"
|
||||
|
||||
echo "更新混淆密码成功"
|
||||
}
|
||||
@ -1,18 +1,36 @@
|
||||
#!/bin/bash
|
||||
|
||||
# 更新密码的函数
|
||||
update_password() {
|
||||
local script_dir="$(cd "$(dirname "${BASH_SOURCE[0]}")" && pwd)"
|
||||
local config_file="$script_dir/../config/config.json"
|
||||
|
||||
# 检查jq是否安装
|
||||
check_jq
|
||||
|
||||
# 生成一个长度为16的随机密码
|
||||
local new_password=$(gen_password 16)
|
||||
|
||||
# 使用jq_util.sh中的modify_json_file函数修改config.json文件中的auth.password字段
|
||||
modify_json_file "$config_file" 'auth.password' "$new_password"
|
||||
|
||||
echo "设置密码成功"
|
||||
# 检查是否安装了jq命令
|
||||
if ! command -v jq &> /dev/null; then
|
||||
echo "Error: jq command not found. Please install jq first."
|
||||
exit 1
|
||||
fi
|
||||
|
||||
# 当前脚本所在目录的绝对路径
|
||||
script_dir="$(dirname "$(realpath "$0")")"
|
||||
|
||||
# 加载jq_util.sh脚本
|
||||
source $script_dir/utils/jq_util.sh
|
||||
|
||||
# 函数生成随机密码
|
||||
gen_random_pass() {
|
||||
local pass_length=$1 # 密码长度作为第一个参数
|
||||
local chars='[:alnum:]' # 只允许出现字母和数字
|
||||
|
||||
local rand
|
||||
rand=$(< /dev/urandom tr -dc "$chars" | head -c "$pass_length")
|
||||
|
||||
echo "$rand"
|
||||
}
|
||||
|
||||
# 生成一个长度为16的随机密码
|
||||
new_password=$(gen_random_pass 16)
|
||||
|
||||
# 更新config.json文件中的auth.password字段
|
||||
config_file="$script_dir/../config.json"
|
||||
|
||||
# 使用jq_util.sh中的modify_json_file函数修改config.json文件中的auth.password字段
|
||||
modify_json_file "$config_file" '.auth.password' "$new_password"
|
||||
|
||||
echo "New password: $new_password"
|
||||
echo "config.json file updated with new password."
|
||||
@ -1,84 +0,0 @@
|
||||
#!/bin/bash
|
||||
|
||||
# 查找随机空闲端口
|
||||
# 用途:
|
||||
# 在指定端口范围内,随机选择一个当前未被监听(TCP/UDP)的端口
|
||||
# 参数:
|
||||
# $1: 起始端口(默认 10001)
|
||||
# $2: 结束端口(默认 65535)
|
||||
# $3: 最大随机尝试次数(默认 100)
|
||||
find_free_port() {
|
||||
local start="${1:-10001}"
|
||||
local max="${2:-65535}"
|
||||
local attempts="${3:-100}"
|
||||
|
||||
# ------------------------------------------------------------
|
||||
# 收集当前正在监听的端口(TCP + UDP)
|
||||
# 优先使用 ss,其次 netstat
|
||||
# ------------------------------------------------------------
|
||||
local used_ports raw
|
||||
if command -v ss >/dev/null 2>&1; then
|
||||
# ss 输出示例:
|
||||
# LISTEN 0 128 0.0.0.0:22
|
||||
raw=$(ss -lntu 2>/dev/null || true)
|
||||
used_ports=$(printf "%s\n" "$raw" \
|
||||
| awk '{print $5}' \
|
||||
| sed -E 's/.*[:]//g')
|
||||
elif command -v netstat >/dev/null 2>&1; then
|
||||
# netstat 输出示例:
|
||||
# tcp 0 0 0.0.0.0:22
|
||||
raw=$(netstat -lntu 2>/dev/null || true)
|
||||
used_ports=$(printf "%s\n" "$raw" \
|
||||
| awk '{print $4}' \
|
||||
| sed -E 's/.*[:]//g')
|
||||
else
|
||||
echo "Error: ss or netstat is required to check listening ports." >&2
|
||||
return 2
|
||||
fi
|
||||
|
||||
# ------------------------------------------------------------
|
||||
# 将已占用端口存入关联数组,便于 O(1) 判断
|
||||
# 需要 bash 4+
|
||||
# ------------------------------------------------------------
|
||||
declare -A used_map
|
||||
local p
|
||||
for p in $used_ports; do
|
||||
# 过滤非数字字段(如 *、:::)
|
||||
if [[ $p =~ ^[0-9]+$ ]]; then
|
||||
used_map["$p"]=1
|
||||
fi
|
||||
done
|
||||
|
||||
# ------------------------------------------------------------
|
||||
# 随机尝试若干次
|
||||
# 每次随机生成一个端口,只要未被监听就立即返回
|
||||
# ------------------------------------------------------------
|
||||
local port i
|
||||
for ((i=0; i<attempts; i++)); do
|
||||
# 在 [start, max] 范围内生成随机端口
|
||||
port=$(( RANDOM % (max - start + 1) + start ))
|
||||
|
||||
# 如果端口不在已监听表中,则认为可用
|
||||
if [[ -z "${used_map[$port]}" ]]; then
|
||||
echo "$port"
|
||||
return 0
|
||||
fi
|
||||
done
|
||||
|
||||
# ------------------------------------------------------------
|
||||
# 多次随机尝试后仍未找到可用端口
|
||||
# 通常意味着端口范围过小或已被大量占用
|
||||
# ------------------------------------------------------------
|
||||
echo "Error: no free port found after $attempts random attempts." >&2
|
||||
return 1
|
||||
}
|
||||
|
||||
change_port(){
|
||||
local script_dir="$(cd "$(dirname "${BASH_SOURCE[0]}")" && pwd)"
|
||||
local config_dir=$(readlink -f "$script_dir/../config")
|
||||
local config_file="$config_dir/config.json"
|
||||
|
||||
local port=$(find_free_port)
|
||||
modify_json_file "$config_file" ".listen" ":$port"
|
||||
echo "已分配新的空闲端口, 设置端口成功"
|
||||
}
|
||||
@ -1,105 +0,0 @@
|
||||
#!/bin/bash
|
||||
|
||||
red(){
|
||||
echo -e "\033[31m$1\033[0m"
|
||||
}
|
||||
|
||||
green(){
|
||||
echo -e "\033[32m$1\033[0m"
|
||||
}
|
||||
|
||||
# 获取系统包管理器
|
||||
get_package_manager(){
|
||||
if command -v apt-get &> /dev/null; then
|
||||
echo "apt-get"
|
||||
elif command -v yum &> /dev/null; then
|
||||
echo "yum"
|
||||
else
|
||||
echo "未知的系统包管理器"
|
||||
return 1 # 返回错误状态码
|
||||
fi
|
||||
}
|
||||
|
||||
# 检查 jq 是否已安装
|
||||
check_jq(){
|
||||
if command -v jq &> /dev/null; then
|
||||
return 0 # jq 已安装,返回成功
|
||||
fi
|
||||
|
||||
echo "jq 未安装,正在安装..."
|
||||
install_package jq
|
||||
}
|
||||
|
||||
|
||||
# 动态安装软件包
|
||||
install_package() {
|
||||
local package_name=$1
|
||||
if command -v "$package_name" &> /dev/null; then
|
||||
echo "$package_name 已安装, 跳过."
|
||||
return 0
|
||||
fi
|
||||
|
||||
echo "安装 $package_name..."
|
||||
package_manager=$(get_package_manager)
|
||||
if [ "$package_manager" == "apt-get" ]; then
|
||||
sudo apt-get update
|
||||
sudo apt-get install -y "$package_name"
|
||||
elif [ "$package_manager" == "yum" ]; then
|
||||
sudo yum install -y "$package_name"
|
||||
else
|
||||
echo "未知的包管理器, 请手动安装 $package_name."
|
||||
return 1
|
||||
fi
|
||||
}
|
||||
|
||||
|
||||
# 生成密码
|
||||
gen_password() {
|
||||
local pass_length=$1 # 密码长度作为第一个参数
|
||||
local chars='[:alnum:]' # 只允许出现字母和数字
|
||||
|
||||
local rand
|
||||
rand=$(< /dev/urandom tr -dc "$chars" | head -c "$pass_length")
|
||||
|
||||
echo "$rand"
|
||||
}
|
||||
|
||||
# 检查配置文件
|
||||
check_config_file(){
|
||||
local script_dir="$(cd "$(dirname "${BASH_SOURCE[0]}")" && pwd)/../" # 脚本文件夹绝对路径
|
||||
local config_file="$script_dir/../config/config.json"
|
||||
|
||||
# 检查配置文件是否存在
|
||||
if [ ! -e "$config_file" ]; then
|
||||
echo "配置文件不存在, 请先生成配置文件."
|
||||
exit 1
|
||||
fi
|
||||
|
||||
# 检查配置文件是否为有效的JSON格式
|
||||
if ! jq '.' "$config_file" >/dev/null 2>&1; then
|
||||
echo "配置文件不是有效的JSON格式, 请重新生成配置文件."
|
||||
exit 1
|
||||
fi
|
||||
}
|
||||
|
||||
restart_docker() {
|
||||
# 如果容器未运行,提示启动
|
||||
local running_count=$(docker-compose -f ./docker-compose.yml ps -q | wc -l)
|
||||
if [ "$running_count" -eq 0 ]; then
|
||||
read -p "容器未启动,是否启动容器?(y/n): " choice
|
||||
case "$choice" in
|
||||
Y|y)
|
||||
docker-compose -f ./docker-compose.yml up -d
|
||||
return
|
||||
;;
|
||||
*)
|
||||
echo "已取消启动"
|
||||
return
|
||||
;;
|
||||
esac
|
||||
fi
|
||||
|
||||
echo "正在重启容器..."
|
||||
docker-compose -f ./docker-compose.yml down
|
||||
docker-compose -f ./docker-compose.yml up -d
|
||||
}
|
||||
@ -7,11 +7,6 @@ function modify_json_file() {
|
||||
local key=$2 # 要修改的key
|
||||
local value=$3 # 要修改的value
|
||||
|
||||
#如果key的值是.开头, 则去掉.号
|
||||
if [[ ${key} == "."* ]]; then
|
||||
key=${key:1}
|
||||
fi
|
||||
|
||||
jq ".${key} = \"${value}\"" ${json_file} > ${json_file}.tmp
|
||||
mv ${json_file}.tmp ${json_file}
|
||||
}
|
||||
|
||||
18
config.json
Normal file
18
config.json
Normal file
@ -0,0 +1,18 @@
|
||||
{
|
||||
"listen": ":8443",
|
||||
"tls": {
|
||||
"cert": "/etc/hysteria/server.crt",
|
||||
"key": "/etc/hysteria/server.key"
|
||||
},
|
||||
"auth": {
|
||||
"type": "password",
|
||||
"password": "La4AdWOoE57OdtwY"
|
||||
},
|
||||
"masquerade": {
|
||||
"type": "proxy",
|
||||
"proxy": {
|
||||
"url": "https://bing.com",
|
||||
"rewriteHost": true
|
||||
}
|
||||
}
|
||||
}
|
||||
@ -1,28 +0,0 @@
|
||||
{
|
||||
"listen": ":8004",
|
||||
"tls": {
|
||||
"cert": "/tls/self-tls/server.crt",
|
||||
"key": "/tls/self-tls/server.key"
|
||||
},
|
||||
"auth": {
|
||||
"type": "password",
|
||||
"password": "你的密码"
|
||||
},
|
||||
"obfs": {
|
||||
"type": "salamander",
|
||||
"salamander": {
|
||||
"password": "你的混淆密码"
|
||||
}
|
||||
},
|
||||
"masquerade": {
|
||||
"type": "proxy",
|
||||
"proxy": {
|
||||
"url": "https://你的域名",
|
||||
"rewriteHost": true
|
||||
}
|
||||
},
|
||||
"bandwidth": {
|
||||
"up": "50 mbps",
|
||||
"down": "100 mbps"
|
||||
}
|
||||
}
|
||||
@ -1,38 +0,0 @@
|
||||
{
|
||||
"listen": ":8445",
|
||||
"acme": {
|
||||
"domains": [
|
||||
"你的域名"
|
||||
],
|
||||
"email": "你的邮箱",
|
||||
"dir":"/tls/acme",
|
||||
"type": "dns",
|
||||
"dns": {
|
||||
"name": "cloudflare",
|
||||
"config": {
|
||||
"cloudflare_api_token": "你的cloudflare_api_token"
|
||||
}
|
||||
}
|
||||
},
|
||||
"auth": {
|
||||
"type": "password",
|
||||
"password": "你的密码"
|
||||
},
|
||||
"obfs": {
|
||||
"type": "salamander",
|
||||
"salamander": {
|
||||
"password": "你的混淆密码"
|
||||
}
|
||||
},
|
||||
"masquerade": {
|
||||
"type": "proxy",
|
||||
"proxy": {
|
||||
"url": "https://你的域名",
|
||||
"rewriteHost": true
|
||||
}
|
||||
},
|
||||
"bandwidth": {
|
||||
"up": "50 mbps",
|
||||
"down": "100 mbps"
|
||||
}
|
||||
}
|
||||
@ -1,11 +1,17 @@
|
||||
version: "3.9"
|
||||
|
||||
services:
|
||||
hysteria:
|
||||
image: tobyxdd/hysteria:latest
|
||||
container_name: "${COMPOSE_PROJECT_NAME}" # 容器名为文件夹名称
|
||||
container_name: hysteria
|
||||
restart: always
|
||||
network_mode: "host"
|
||||
volumes:
|
||||
- ./tls:/tls
|
||||
- ./config/config.json:/etc/hysteria/config.json
|
||||
- acme:/acme
|
||||
- ./config.json:/etc/hysteria/config.json
|
||||
- ./key/server.crt:/etc/hysteria/server.crt
|
||||
- ./key/server.key:/etc/hysteria/server.key
|
||||
command: ["server", "-c", "/etc/hysteria/config.json"]
|
||||
|
||||
|
||||
volumes:
|
||||
acme:
|
||||
|
||||
101
install.sh
101
install.sh
@ -1,101 +0,0 @@
|
||||
#!/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 jq >/dev/null 2>&1; then
|
||||
install_package jq
|
||||
fi
|
||||
|
||||
if ! command -v docker >/dev/null 2>&1; then
|
||||
echo 安装docker...
|
||||
curl -fsSL https://get.docker.com | bash -s docker
|
||||
fi
|
||||
|
||||
if ! command -v docker-compose >/dev/null 2>&1; then
|
||||
echo 安装docker-compose...
|
||||
wget -O /usr/local/bin/docker-compose https://github.com/docker/compose/releases/download/v2.29.0/docker-compose-linux-x86_64
|
||||
chmod +x /usr/local/bin/docker-compose
|
||||
fi
|
||||
}
|
||||
|
||||
main(){
|
||||
# 显示菜单
|
||||
echo "请选择一个操作:"
|
||||
echo "1. 一键部署"
|
||||
echo "2. 生成配置 / 重置配置"
|
||||
echo "3. 查看分享链接"
|
||||
echo "4. 启动容器"
|
||||
echo "5. 停止容器"
|
||||
echo "6. 更新镜像"
|
||||
echo "7. 修改域名"
|
||||
echo "8. 修改端口"
|
||||
|
||||
# 读取用户选择
|
||||
read -p "输入您的选择: " choice
|
||||
|
||||
# 根据用户选择执行相应的操作
|
||||
case $choice in
|
||||
1)
|
||||
# 一键部署
|
||||
install
|
||||
create_config
|
||||
run
|
||||
print_share_link
|
||||
;;
|
||||
2)
|
||||
# 生成配置
|
||||
create_config
|
||||
;;
|
||||
3)
|
||||
# 查看分享链接
|
||||
check_config_file
|
||||
print_share_link
|
||||
;;
|
||||
4)
|
||||
# 启动容器
|
||||
run
|
||||
print_share_link
|
||||
;;
|
||||
5)
|
||||
# 停止容器
|
||||
docker-compose -f ./docker-compose.yml down
|
||||
;;
|
||||
6)
|
||||
# 更新镜像
|
||||
update_docker_images
|
||||
;;
|
||||
7)
|
||||
# 修改域名
|
||||
check_config_file
|
||||
update_domain
|
||||
restart_docker
|
||||
;;
|
||||
8)
|
||||
# 修改端口
|
||||
check_config_file
|
||||
change_port
|
||||
restart_docker
|
||||
;;
|
||||
*)
|
||||
echo "无效的选择, 请重新选择."
|
||||
;;
|
||||
esac
|
||||
}
|
||||
|
||||
main
|
||||
11
key/server.crt
Normal file
11
key/server.crt
Normal file
@ -0,0 +1,11 @@
|
||||
-----BEGIN CERTIFICATE-----
|
||||
MIIBfTCCASOgAwIBAgIUR65F9ix0BBWiw284NXIW5RoGvgwwCgYIKoZIzj0EAwIw
|
||||
EzERMA8GA1UEAwwIYmluZy5jb20wIBcNMjQwMTMwMDQwNTIwWhgPMjEyNDAxMDYw
|
||||
NDA1MjBaMBMxETAPBgNVBAMMCGJpbmcuY29tMFkwEwYHKoZIzj0CAQYIKoZIzj0D
|
||||
AQcDQgAEwRtxXqEGibaVkK5eVWjzag7UaCG4z48wRb6Kg8N/HQo2hxU/EivPmCB3
|
||||
+hcj2dlZNFSGojOdr21mhI6Oqe/s0aNTMFEwHQYDVR0OBBYEFCkfq4KFllbH2zEO
|
||||
GeCeBXOOJccXMB8GA1UdIwQYMBaAFCkfq4KFllbH2zEOGeCeBXOOJccXMA8GA1Ud
|
||||
EwEB/wQFMAMBAf8wCgYIKoZIzj0EAwIDSAAwRQIgbQoaD89WuimuPuVZJDX17kJc
|
||||
br9bR0nl91eLuTrWfAYCIQC2OyHg4BWcw6W+lvRw/wH1OpIqqC7+Mk8zOgor4d0C
|
||||
tg==
|
||||
-----END CERTIFICATE-----
|
||||
5
key/server.key
Normal file
5
key/server.key
Normal file
@ -0,0 +1,5 @@
|
||||
-----BEGIN PRIVATE KEY-----
|
||||
MIGHAgEAMBMGByqGSM49AgEGCCqGSM49AwEHBG0wawIBAQQgukBlJTuRZPhgqQA9
|
||||
ruBWkS9onZJCJ/NzyMDARwXOC8ShRANCAATBG3FeoQaJtpWQrl5VaPNqDtRoIbjP
|
||||
jzBFvoqDw38dCjaHFT8SK8+YIHf6FyPZ2Vk0VIaiM52vbWaEjo6p7+zR
|
||||
-----END PRIVATE KEY-----
|
||||
Loading…
Reference in New Issue
Block a user