feat: add bootstrap one-click deploy and update deployment docs

Co-authored-by: Cursor <cursoragent@cursor.com>
This commit is contained in:
dekun
2026-07-11 13:49:20 +08:00
parent 46728e12f7
commit 1f36a76ce0
11 changed files with 525 additions and 223 deletions
+1 -2
View File
@@ -1,5 +1,4 @@
# 部署生成的客户端配置与运行时数据 # 运行时数据
client/generated/
data/ data/
panel/venv/ panel/venv/
__pycache__/ __pycache__/
+31 -30
View File
@@ -16,7 +16,7 @@
| 文档 | 说明 | | 文档 | 说明 |
|------|------| |------|------|
| **[docs/DEPLOY.md](docs/DEPLOY.md)** | 部署指南(安全组、安装、升级、验证 | | **[docs/DEPLOY.md](docs/DEPLOY.md)** | 部署指南(**前期准备、端口、一键安装** |
| **[docs/GUIDE.md](docs/GUIDE.md)** | 使用说明(面板、节点、客户端、维护) | | **[docs/GUIDE.md](docs/GUIDE.md)** | 使用说明(面板、节点、客户端、维护) |
| **[docs/client-import.md](docs/client-import.md)** | 客户端导入 Hy2 链接 | | **[docs/client-import.md](docs/client-import.md)** | 客户端导入 Hy2 链接 |
| **[docs/troubleshooting.md](docs/troubleshooting.md)** | 故障排查 | | **[docs/troubleshooting.md](docs/troubleshooting.md)** | 故障排查 |
@@ -25,21 +25,36 @@
--- ---
## 部署前准备
| # | 项目 | 要求 |
|---|------|------|
| 1 | VPS | Ubuntu 22.04 / 24.04root 权限 |
| 2 | 域名 | A 记录指向 VPS 公网 IP |
| 3 | 安全组 | 放行下方端口 |
### 需要开放的端口
| 端口 | 协议 | 用途 |
|------|------|------|
| 22 | TCP | SSH |
| 80 | TCP | ACME 证书验证 |
| 443 | TCP | HTTPS 管理面板 |
| **84438499** | **UDP** | Hysteria2 代理(多节点递增) |
> Hy2 走 **UDP**,安全组必须放行 **84438499/UDP 整段**。详细说明见 **[docs/DEPLOY.md](docs/DEPLOY.md)**。
---
## 快速部署 ## 快速部署
```bash SSH 登录新 VPS 后,一条命令完成部署(自动 clone,交互输入域名/邮箱/账号):
ssh root@YOUR_VPS_IP
apt update && apt install -y git ```bash
git clone https://git.bz121.com/dekun/jiedian.git /opt/jiedian curl -fsSL https://git.bz121.com/dekun/jiedian/raw/main/scripts/bootstrap.sh | bash
cd /opt/jiedian
cp .env.example .env # 填写 VPS_IP、DOMAIN、ACME_EMAIL
bash scripts/install.sh
``` ```
安装完成后浏览器打开面板 → 登录 → **添加节点** → 复制 **Hy2 链接** 到 v2rayN / v2rayNG。 安装完成后会输出面板地址、用户名和密码。浏览器打开 → 登录 → **添加节点** → 复制 **Hy2 链接** 到 v2rayN / v2rayNG。
详细步骤见 **[docs/DEPLOY.md](docs/DEPLOY.md)**。
--- ---
@@ -62,19 +77,6 @@ bash scripts/install.sh
--- ---
## 端口与防火墙
| 端口 | 协议 | 用途 |
|------|------|------|
| 22 | TCP | SSH |
| 80 | TCP | HTTPACME 证书验证 + 跳转 HTTPS |
| 443 | TCP | **HTTPS 管理面板** |
| 84438499 | UDP | Hysteria2(每节点递增) |
云厂商安全组需放行 **443/TCP****84438499/UDP**
---
## 常用命令 ## 常用命令
```bash ```bash
@@ -89,8 +91,8 @@ cd /opt/jiedian && git pull
python3 scripts/render-server.py python3 scripts/render-server.py
systemctl restart sing-box jiedian-panel systemctl restart sing-box jiedian-panel
# 从旧版(含 VLESS)迁移 # 重置面板密码
bash scripts/remove-vless.sh bash scripts/generate-keys.sh
``` ```
--- ---
@@ -103,11 +105,10 @@ bash scripts/remove-vless.sh
├── data/nodes.db # 节点数据库 ├── data/nodes.db # 节点数据库
├── panel/ # Flask 管理面板 ├── panel/ # Flask 管理面板
├── scripts/ ├── scripts/
│ ├── install.sh # 一键部署 │ ├── bootstrap.sh # 一键部署入口(自动 clone + 交互配置)
│ ├── install.sh # 核心安装逻辑
│ ├── uninstall.sh # 卸载 │ ├── uninstall.sh # 卸载
│ ├── remove-vless.sh # 旧版停用 VLESS │ ├── generate-keys.sh # 重置面板密码
│ ├── enable-panel-https.sh # 启用 HTTPS 面板
│ ├── generate-keys.sh # 生成/重置面板密码
│ └── render-server.py # 生成 sing-box 配置 │ └── render-server.py # 生成 sing-box 配置
└── docs/ # 文档 └── docs/ # 文档
``` ```
-85
View File
@@ -1,85 +0,0 @@
{
"log": {
"level": "info"
},
"dns": {
"servers": [
{
"tag": "remote",
"address": "tls://8.8.8.8",
"detour": "proxy"
},
{
"tag": "local",
"address": "223.5.5.5",
"detour": "direct"
}
],
"rules": [
{
"outbound": "any",
"server": "local"
}
],
"final": "remote"
},
"inbounds": [
{
"type": "mixed",
"tag": "mixed-in",
"listen": "127.0.0.1",
"listen_port": 7890
},
{
"type": "tun",
"tag": "tun-in",
"interface_name": "sing-tun",
"address": ["172.19.0.1/30"],
"mtu": 9000,
"auto_route": true,
"strict_route": true,
"stack": "mixed"
}
],
"outbounds": [
{
"type": "selector",
"tag": "proxy",
"outbounds": ["hysteria2", "direct"]
},
{
"type": "hysteria2",
"tag": "hysteria2",
"server": "${DOMAIN}",
"server_port": 8443,
"password": "${HY2_PASSWORD}",
"tls": {
"enabled": true,
"server_name": "${DOMAIN}",
"alpn": ["h3"]
}
},
{
"type": "direct",
"tag": "direct"
},
{
"type": "dns",
"tag": "dns-out"
}
],
"route": {
"rules": [
{
"protocol": "dns",
"outbound": "dns-out"
},
{
"ip_is_private": true,
"outbound": "direct"
}
],
"final": "proxy",
"auto_detect_interface": true
}
}
+135 -59
View File
@@ -12,68 +12,143 @@
--- ---
## 一、部署前准备 ## 一、部署前准备(必读)
### 1. 购买 VPS 并获取 root 登录 部署前请逐项完成以下准备。**端口未放行或 DNS 未解析会导致安装失败或客户端连不上。**
建议使用境外 VPS,带宽 ≥ 30Mbps。记录: ### 准备清单
- 公网 IP(写入 `.env``VPS_IP` | # | 项目 | 要求 |
|---|------|------|
| 1 | VPS | Ubuntu 22.04 / 24.04root 或 sudo,建议带宽 ≥ 30Mbps |
| 2 | 域名 | 已注册,可添加 DNS 记录 |
| 3 | DNS | 域名 **A 记录** 指向 VPS 公网 IP |
| 4 | 安全组 | 云厂商控制台放行下方端口(见下表) |
| 5 | 系统防火墙 | 安装脚本会自动配置 UFW,无需手动操作 |
### 需要开放的端口
**云厂商安全组**与 **VPS 防火墙**均需放行(安装脚本会配置 UFW,但安全组必须在控制台手动开)。
| 端口 | 协议 | 方向 | 用途 | 必须 |
|------|------|------|------|------|
| **22** | TCP | 入站 | SSH 远程登录 | 是 |
| **80** | TCP | 入站 | ACME 证书验证(Let's Encrypt | 是 |
| **443** | TCP | 入站 | **HTTPS 管理面板** | 是 |
| **84438499** | **UDP** | 入站 | **Hysteria2 代理**(多节点递增) | 是 |
> **重要**
>
> - Hy2 使用 **UDP**,不是 TCP。安全组必须放行 **84438499/UDP 整段**,不能只开 8443。
> - 每增加一个节点,Hy2 端口 +1(8443、8444、8445…)。预留 84438499 可支持约 57 个节点。
> - 面板走 **443/TCP**,客户端代理走 **8443+/UDP**,两者都需要。
### 各组件端口对照
| 组件 | 端口 | 协议 | 说明 |
|------|------|------|------|
| SSH | 22 | TCP | 部署与运维 |
| Nginx | 80 | TCP | 证书申请 + HTTP 跳转 HTTPS |
| Nginx | 443 | TCP | 管理面板 HTTPS |
| sing-box | 8443 | UDP | 第 1 个节点 Hy2 |
| sing-box | 8444 | UDP | 第 2 个节点 Hy2 |
| sing-box | 8445… | UDP | 后续节点依次 +1 |
### 1. 购买 VPS
记录:
- 公网 IP(一键部署会自动检测并写入 `.env`
- SSH 登录方式(密码或密钥) - SSH 登录方式(密码或密钥)
### 2. 域名与 DNS ### 2. 域名与 DNS
将域名 **A 记录** 解析到 VPS 公网 IP(用于 Hy2 TLS 证书与面板访问) 将域名 **A 记录** 解析到 VPS 公网 IP
``` ```
your.domain.com → YOUR_VPS_IP your.domain.com → YOUR_VPS_IP
``` ```
验证: 验证(在本地或 VPS 上执行)
```bash ```bash
dig +short A your.domain.com dig +short A your.domain.com
# 应返回 VPS IP # 应返回 VPS 公网 IP
``` ```
### 3. 云厂商安全组 DNS 未生效时,证书申请会失败。一键部署脚本会检测并提示。
在阿里云 / 腾讯云等控制台放行: ### 3. 云厂商安全组配置示例
| 端口 | 协议 | 用途 | 必须 | **阿里云 / 腾讯云 / AWS 等**:进入 VPS 实例 → 安全组 → 入站规则,添加上表中的端口。
|------|------|------|------|
| 22 | TCP | SSH | 是 |
| 80 | TCP | ACME 证书验证 | 是 |
| 443 | TCP | **HTTPS 管理面板** | 是 |
| 84438499 | UDP | Hysteria2(多节点递增) | 是 |
> **重要**:每增加一个节点,Hy2 端口 +1(8443、8444、8445…)。安全组必须放行 **84438499/UDP** 整段,不能只开 8443。 常见错误:
### 4. 填写 `.env` | 错误 | 后果 |
|------|------|
| 只开 8443/UDP,未开 84448499 | 第 2 个节点起客户端连不上 |
| Hy2 端口写成 TCP | 客户端延迟 `-1` 或无法连接 |
| 未开 80/TCP | Let's Encrypt 证书申请失败 |
| 未开 443/TCP | 管理面板无法 HTTPS 访问 |
```bash ### 4. 部署时需要的信息
git clone https://git.bz121.com/dekun/jiedian.git /opt/jiedian
cd /opt/jiedian
cp .env.example .env
nano .env
```
| 变量 | 必填 | 说明 | 一键部署时会交互询问(或命令行传入):
| 项目 | 必填 | 说明 |
|------|------|------| |------|------|------|
| `VPS_IP` | 是 | VPS 公网 IP | | 域名 | 是 | 已解析到 VPS 的域名 |
| `DOMAIN` | 是 | 已解析到 VPS 的域名 | | 证书邮箱 | 是 | Let's Encrypt 申请用 |
| `ACME_EMAIL` | | Let's Encrypt 申请证书邮箱 | | 面板用户名 | | 默认 `admin` |
| `PANEL_USERNAME` | 否 | 面板登录用户名,默认 `admin` | | 面板密码 | 否 | 留空则自动生成 |
| `PANEL_PASSWORD` | 否 | 面板密码;留空则安装时自动生成 |
| `PANEL_PATH` | 否 | 面板 URL 路径;留空则自动生成如 `jiedian-a1b2c3d4` |
| `PANEL_ALLOW_IP` | 否 | 仅允许指定 IP 访问面板(可选) |
`CLASH_API_SECRET``install.sh` 自动生成,供面板读取连接统计,无需手动填写 以下由脚本自动处理,**无需手动填写**
| 项目 | 说明 |
|------|------|
| `VPS_IP` | 自动检测公网 IP |
| `PANEL_PATH` | 自动生成随机路径(如 `jiedian-a1b2c3d4` |
| `CLASH_API_SECRET` | 自动生成,供面板读取连接统计 |
### 5. 手动配置(可选)
若不用一键部署、需自定义 `.env`,见 [手动安装](#手动安装备选)。
--- ---
## 二、一键安装(新机器) ## 二、一键安装(新机器)
SSH 登录 VPS 后执行(**无需先 clone**,脚本会自动 clone 到 `/opt/jiedian`):
```bash
curl -fsSL https://git.bz121.com/dekun/jiedian/raw/main/scripts/bootstrap.sh | bash
```
按提示输入域名、证书邮箱、面板用户名和密码即可。
脚本会自动:
1. 检测公网 IP,校验 DNS
2. clone 仓库到 `/opt/jiedian`
3. 写入 `.env`,调用 `install.sh`
4. 安装 sing-box、nginx、Python 面板
5. 配置 UFW22/80/443 TCP + 84438499 UDP
6. 申请 TLS 证书,启动服务
7. 输出面板地址、用户名、密码
**非交互模式**(适合脚本化):
```bash
curl -fsSL https://git.bz121.com/dekun/jiedian/raw/main/scripts/bootstrap.sh | bash -s -- \
--domain your.domain.com \
--email you@example.com \
--username admin \
--password 'your-password' \
--yes
```
### 手动安装(备选)
```bash ```bash
ssh root@YOUR_VPS_IP ssh root@YOUR_VPS_IP
@@ -85,24 +160,28 @@ cp .env.example .env
bash scripts/install.sh bash scripts/install.sh
``` ```
安装脚本会自动完成: | 变量 | 必填 | 说明 |
|------|------|------|
1. 安装 sing-box、nginx、Python 面板依赖 | `VPS_IP` | 是 | VPS 公网 IP |
2. 配置 UFW 防火墙(22/80/443 TCP84438499 UDP | `DOMAIN` | 是 | 已解析到 VPS 的域名 |
3. 通过 acme.sh 为 `DOMAIN` 申请 TLS 证书 | `ACME_EMAIL` | 是 | Let's Encrypt 申请证书邮箱 |
4. 初始化 SQLite 节点库与默认管理员 | `PANEL_USERNAME` | 否 | 面板登录用户名,默认 `admin` |
5. 生成 sing-box 配置、启用 **HTTPS 面板**并启动服务 | `PANEL_PASSWORD` | 否 | 面板密码;留空则安装时自动生成 |
| `PANEL_PATH` | 否 | 面板 URL 路径;留空则自动生成 |
| `PANEL_ALLOW_IP` | 否 | 仅允许指定 IP 访问面板(可选) |
安装结束输出示例: 安装结束输出示例:
``` ```
========================================== ╔══════════════════════════════════════════════════════╗
管理面板: https://66.hyf2.cc/jiedian-xxxx/ ║ 部署完成 ║
HTTP 会自动跳转到 HTTPS ╠══════════════════════════════════════════════════════╣
面板路径: jiedian-xxxx 面板地址: https://66.hyf2.cc/jiedian-xxxx/
用户名: dekun 用户名: admin
密码: xxxxx 密码: xxxxxxxxx
========================================== ╠══════════════════════════════════════════════════════╣
║ 凭证已保存: /root/jiedian-credentials.txt
╚══════════════════════════════════════════════════════╝
``` ```
浏览器打开面板地址 → 登录 → **添加节点** → 复制 **Hysteria2** 链接到客户端。 浏览器打开面板地址 → 登录 → **添加节点** → 复制 **Hysteria2** 链接到客户端。
@@ -123,6 +202,9 @@ sing-box check -c /etc/sing-box/config.json
# Hy2 端口监听(默认 8443,多节点还有 8444…) # Hy2 端口监听(默认 8443,多节点还有 8444…)
ss -ulnp | grep 8443 ss -ulnp | grep 8443
# UFW 规则(确认 UDP 8443-8499 已放行)
ufw status
# 面板 HTTPS 可访问(应返回 200/302 # 面板 HTTPS 可访问(应返回 200/302
PANEL_PATH=$(grep ^PANEL_PATH= /opt/jiedian/.env | cut -d= -f2) PANEL_PATH=$(grep ^PANEL_PATH= /opt/jiedian/.env | cut -d= -f2)
curl -Ik "https://$(grep ^DOMAIN= /opt/jiedian/.env | cut -d= -f2)/${PANEL_PATH}/login" curl -Ik "https://$(grep ^DOMAIN= /opt/jiedian/.env | cut -d= -f2)/${PANEL_PATH}/login"
@@ -141,9 +223,13 @@ python3 scripts/render-server.py
systemctl restart sing-box jiedian-panel systemctl restart sing-box jiedian-panel
``` ```
### 从旧版(含 VLESS/Xray)升级到仅 Hy2 仅更新面板前端/代码、未改 sing-box 配置时:
若你之前部署过带 VLESS Reality 的版本: ```bash
cd /opt/jiedian && git pull && systemctl restart jiedian-panel
```
### 从旧版(含 VLESS/Xray)升级到仅 Hy2
```bash ```bash
cd /opt/jiedian cd /opt/jiedian
@@ -151,15 +237,6 @@ git pull
sudo bash scripts/remove-vless.sh sudo bash scripts/remove-vless.sh
``` ```
该脚本会:
- 停止并禁用 Xray
- 重载 sing-box 配置
- **启用 HTTPS 管理面板(443**
- 重启面板
完成后客户端 **删除所有 VLESS 节点**,从面板复制 `hy2://` 链接,并用 **HTTPS** 登录面板。
### 已有 VPS 仅升级 HTTPS 面板 ### 已有 VPS 仅升级 HTTPS 面板
```bash ```bash
@@ -187,8 +264,7 @@ systemctl restart sing-box
```bash ```bash
cd /opt/jiedian cd /opt/jiedian
bash scripts/uninstall.sh bash scripts/uninstall.sh
# 保留 .env 与代码,清理 data/ 与 venv bash scripts/bootstrap.sh # 或 bash scripts/install.sh
bash scripts/install.sh
``` ```
--- ---
+9 -3
View File
@@ -2,7 +2,7 @@
| 文档 | 适用对象 | 内容 | | 文档 | 适用对象 | 内容 |
|------|----------|------| |------|----------|------|
| **[DEPLOY.md](DEPLOY.md)** | 运维 / 首次部署 | VPS 安装、安全组、`.env`、升级、验证 | | **[DEPLOY.md](DEPLOY.md)** | 运维 / 首次部署 | **前期准备、端口放行、一键安装**、升级、验证 |
| **[GUIDE.md](GUIDE.md)** | 日常使用 | 面板操作、节点管理、Hy2 说明、安全建议 | | **[GUIDE.md](GUIDE.md)** | 日常使用 | 面板操作、节点管理、Hy2 说明、安全建议 |
| **[client-import.md](client-import.md)** | 客户端用户 | Windows / Android / iOS 导入 Hy2 链接 | | **[client-import.md](client-import.md)** | 客户端用户 | Windows / Android / iOS 导入 Hy2 链接 |
| **[troubleshooting.md](troubleshooting.md)** | 排错 | 连不上、面板打不开、迁移 | | **[troubleshooting.md](troubleshooting.md)** | 排错 | 连不上、面板打不开、迁移 |
@@ -12,6 +12,12 @@
- 仓库:https://git.bz121.com/dekun/jiedian.git - 仓库:https://git.bz121.com/dekun/jiedian.git
- 部署目录:`/opt/jiedian` - 部署目录:`/opt/jiedian`
- 一键安装:`bash scripts/install.sh`(自动 HTTPS 面板) - **一键部署**`curl -fsSL https://git.bz121.com/dekun/jiedian/raw/main/scripts/bootstrap.sh | bash`
- 旧版去 VLESS`bash scripts/remove-vless.sh` - 旧版去 VLESS`bash scripts/remove-vless.sh`
- 单独启用 HTTPS`bash scripts/enable-panel-https.sh`
## 部署前必做
1. 域名 A 记录 → VPS 公网 IP
2. 安全组放行:**22/TCP、80/TCP、443/TCP、84438499/UDP**
详见 **[DEPLOY.md](DEPLOY.md)**。
+18 -6
View File
@@ -5,16 +5,21 @@
| 组件 | 用途 | | 组件 | 用途 |
|------|------| |------|------|
| **sing-box** | Hysteria2 服务端、Clash API 统计、多 inbound 按节点分端口 | | **sing-box** | Hysteria2 服务端、Clash API 统计、多 inbound 按节点分端口 |
| **Nginx** | ACME 验证、管理面板反代HTTP 80 | | **Nginx** | ACME 验证、HTTPS 管理面板反代 |
| **Flask 面板** | 添加/删除节点、复制 Hy2 链接、在线与流量统计 | | **Flask 面板** | 添加/删除节点、复制 Hy2 链接、在线与流量统计 |
## 端口 ## 端口
| 端口 | 协议 | 进程 | 说明 | 部署前需在云厂商安全组放行以下端口(安装脚本会同步配置 UFW):
|------|------|------|------|
| 80 | TCP | Nginx | ACME 验证 + 跳转 HTTPS | | 端口 | 协议 | 进程 | 方向 | 说明 |
| 443 | TCP | Nginx | **HTTPS 管理面板** | |------|------|------|------|------|
| 84438499 | UDP | sing-box | Hy2,每节点 +1 | | 22 | TCP | sshd | 入站 | SSH 运维 |
| 80 | TCP | Nginx | 入站 | ACME 证书验证 + 跳转 HTTPS |
| 443 | TCP | Nginx | 入站 | **HTTPS 管理面板** |
| 84438499 | **UDP** | sing-box | 入站 | **Hy2 代理**,每节点端口 +1 |
> Hy2 使用 UDP。安全组必须放行 **84438499/UDP 整段**,不能只开 8443。
## 配置生成 ## 配置生成
@@ -23,3 +28,10 @@
| `render-server.py` | `/etc/sing-box/config.json` | | `render-server.py` | `/etc/sing-box/config.json` |
增删节点后运行 `render-server.py``systemctl restart sing-box` 增删节点后运行 `render-server.py``systemctl restart sing-box`
## 部署入口
| 脚本 | 用途 |
|------|------|
| `bootstrap.sh` | 一键部署(自动 clone、交互配置、调用 install.sh |
| `install.sh` | 核心安装(sing-box / nginx / 证书 / 面板) |
+326
View File
@@ -0,0 +1,326 @@
#!/usr/bin/env bash
# jiedian 一键部署入口:自动 clone、交互配置、调用 install.sh
# 用法:
# curl -fsSL https://git.bz121.com/dekun/jiedian/raw/main/scripts/bootstrap.sh | bash
# bash scripts/bootstrap.sh
# 非交互:
# bash scripts/bootstrap.sh --domain example.com --email you@example.com --yes
set -euo pipefail
INSTALL_DIR="/opt/jiedian"
REPO_URL="https://git.bz121.com/dekun/jiedian.git"
REPO_BRANCH="main"
CREDS_FILE="/root/jiedian-credentials.txt"
RED='\033[0;31m'
GREEN='\033[0;32m'
CYAN='\033[0;36m'
YELLOW='\033[1;33m'
BOLD='\033[1m'
NC='\033[0m'
log() { echo -e "${GREEN}[+]${NC} $*"; }
warn() { echo -e "${YELLOW}[!]${NC} $*"; }
err() { echo -e "${RED}[!]${NC} $*" >&2; exit 1; }
usage() {
cat <<'EOF'
用法:
curl -fsSL https://git.bz121.com/dekun/jiedian/raw/main/scripts/bootstrap.sh | bash
bash scripts/bootstrap.sh [选项]
选项:
--domain DOMAIN 域名(Hy2 + 面板 HTTPS
--email EMAIL Let's Encrypt 证书邮箱
--username USER 面板登录用户名(默认 admin)
--password PASS 面板登录密码(留空则随机生成)
--yes, -y 跳过确认
-h, --help 显示帮助
EOF
}
ensure_repo() {
if [[ -d "$INSTALL_DIR/.git" ]] && [[ -f "$INSTALL_DIR/scripts/install.sh" ]]; then
return 0
fi
log "安装 git ..."
export DEBIAN_FRONTEND=noninteractive
apt-get update -qq
apt-get install -y -qq git ca-certificates curl
if [[ -d "$INSTALL_DIR" ]] && [[ ! -d "$INSTALL_DIR/.git" ]]; then
warn "目录 $INSTALL_DIR 已存在但不是 git 仓库,将备份为 ${INSTALL_DIR}.bak"
mv "$INSTALL_DIR" "${INSTALL_DIR}.bak.$(date +%s)"
fi
log "克隆仓库到 $INSTALL_DIR ..."
git clone --depth 1 -b "$REPO_BRANCH" "$REPO_URL" "$INSTALL_DIR"
}
reexec_from_repo() {
[[ "${JIEDIAN_BOOTSTRAP_FROM_REPO:-}" == "1" ]] && return 0
local repo_bootstrap="$INSTALL_DIR/scripts/bootstrap.sh"
[[ -f "$repo_bootstrap" ]] || return 0
local src="${BASH_SOURCE[0]:-}"
case "$src" in
"$repo_bootstrap"|*/jiedian/scripts/bootstrap.sh) return 0 ;;
esac
export JIEDIAN_BOOTSTRAP_FROM_REPO=1
log "使用仓库内 bootstrap 继续 ..."
exec bash "$repo_bootstrap" "$@"
}
check_root() {
[[ $EUID -eq 0 ]] || err "请使用 root 运行(或 sudo bash bootstrap.sh"
}
check_os() {
[[ -f /etc/os-release ]] || err "无法识别操作系统"
# shellcheck disable=SC1091
source /etc/os-release
[[ "${ID:-}" == "ubuntu" ]] || err "仅支持 Ubuntu,当前: ${ID:-unknown}"
case "${VERSION_ID:-}" in
22.04|24.04) ;;
*) err "仅支持 Ubuntu 22.04 / 24.04,当前: ${VERSION_ID:-unknown}" ;;
esac
}
detect_public_ip() {
curl -4 -fsSL --connect-timeout 5 ifconfig.me 2>/dev/null \
|| curl -4 -fsSL --connect-timeout 5 ip.sb 2>/dev/null \
|| curl -4 -fsSL --connect-timeout 5 icanhazip.com 2>/dev/null \
|| err "无法检测公网 IP,请检查网络"
}
resolve_domain() {
local domain="$1"
if command -v dig >/dev/null 2>&1; then
dig +short A "$domain" @8.8.8.8 2>/dev/null | grep -E '^[0-9.]+$' | head -1
return 0
fi
getent ahostsv4 "$domain" 2>/dev/null | awk '{print $1; exit}'
}
valid_domain() {
[[ "$1" =~ ^[a-zA-Z0-9]([a-zA-Z0-9-]{0,61}[a-zA-Z0-9])?(\.[a-zA-Z0-9]([a-zA-Z0-9-]{0,61}[a-zA-Z0-9])?)*$ ]]
}
valid_email() {
[[ "$1" == *"@"* ]] && [[ "$1" == *"."* ]]
}
prompt_if_empty() {
local var_name="$1"
local prompt="$2"
local default="${3:-}"
local secret="${4:-0}"
local value=""
if [[ -n "${!var_name:-}" ]]; then
return 0
fi
if [[ -n "$default" ]]; then
prompt="$prompt [$default]"
fi
if [[ "$secret" == "1" ]]; then
read -r -s -p "$prompt: " value
echo ""
else
read -r -p "$prompt: " value
fi
if [[ -z "$value" && -n "$default" ]]; then
value="$default"
fi
printf -v "$var_name" '%s' "$value"
}
generate_password() {
openssl rand -base64 32 | tr -d '/+=' | head -c 20
}
write_env_file() {
local env_file="$INSTALL_DIR/.env"
cat > "$env_file" <<EOF
# 由 bootstrap.sh 自动生成
VPS_IP=${VPS_IP}
DOMAIN=${DOMAIN}
ACME_EMAIL=${ACME_EMAIL}
PANEL_USERNAME=${PANEL_USERNAME}
PANEL_PASSWORD=${PANEL_PASSWORD}
EOF
chmod 600 "$env_file"
}
print_banner() {
echo ""
echo -e "${CYAN}${BOLD}╔══════════════════════════════════════╗${NC}"
echo -e "${CYAN}${BOLD}║ jiedian 一键部署 ║${NC}"
echo -e "${CYAN}${BOLD}║ Hysteria2 + Web 管理面板 ║${NC}"
echo -e "${CYAN}${BOLD}╚══════════════════════════════════════╝${NC}"
echo ""
echo "部署前请确认:"
echo " □ 域名 A 记录已指向本机公网 IP"
echo " □ 安全组已放行 22/TCP 80/TCP 443/TCP 8443-8499/UDP"
echo ""
}
confirm_or_abort() {
local answer=""
echo ""
echo -e "${BOLD}即将写入配置:${NC}"
echo " 公网 IP: $VPS_IP"
echo " 域名: $DOMAIN"
echo " 证书邮箱: $ACME_EMAIL"
echo " 用户名: $PANEL_USERNAME"
echo " 密码: ${PANEL_PASSWORD:0:2}****** (${#PANEL_PASSWORD} 位)"
echo ""
read -r -p "确认开始部署?(Y/n): " answer
case "${answer:-Y}" in
Y|y|yes|YES) ;;
*) err "已取消" ;;
esac
}
check_existing_install() {
local env_file="$INSTALL_DIR/.env"
[[ -f "$env_file" ]] || return 0
warn "检测到已有部署($env_file"
local answer=""
read -r -p "是否重新部署?将覆盖 .env 并重新安装 (y/N): " answer
case "${answer:-N}" in
y|Y|yes|YES) ;;
*) err "已取消。若要更新代码请: cd $INSTALL_DIR && git pull" ;;
esac
}
save_credentials() {
# shellcheck disable=SC1091
source "$INSTALL_DIR/.env"
local panel_path="${PANEL_PATH:-}"
if [[ -z "$panel_path" ]]; then
panel_path="$(grep -E '^PANEL_PATH=' "$INSTALL_DIR/.env" | cut -d= -f2- || true)"
fi
[[ -n "$panel_path" ]] || panel_path="jiedian-unknown"
cat > "$CREDS_FILE" <<EOF
jiedian 部署凭证
生成时间: $(date -Iseconds)
面板地址: https://${DOMAIN}/${panel_path}/
用户名: ${PANEL_USERNAME}
密码: ${PANEL_PASSWORD}
面板路径: ${panel_path}
VPS IP: ${VPS_IP}
EOF
chmod 600 "$CREDS_FILE"
}
print_success() {
# shellcheck disable=SC1091
source "$INSTALL_DIR/.env"
local panel_path="${PANEL_PATH:-jiedian-unknown}"
echo ""
echo -e "${GREEN}${BOLD}╔══════════════════════════════════════════════════════╗${NC}"
echo -e "${GREEN}${BOLD}║ 部署完成 ║${NC}"
echo -e "${GREEN}${BOLD}╠══════════════════════════════════════════════════════╣${NC}"
echo -e "${GREEN}${BOLD}${NC} 面板地址: ${CYAN}https://${DOMAIN}/${panel_path}/${NC}"
echo -e "${GREEN}${BOLD}${NC} 用户名: ${PANEL_USERNAME}"
echo -e "${GREEN}${BOLD}${NC} 密码: ${PANEL_PASSWORD}"
echo -e "${GREEN}${BOLD}╠══════════════════════════════════════════════════════╣${NC}"
echo -e "${GREEN}${BOLD}${NC} 凭证已保存: ${CREDS_FILE}"
echo -e "${GREEN}${BOLD}╚══════════════════════════════════════════════════════╝${NC}"
echo ""
echo "下一步:浏览器打开面板 → 登录 → 添加节点 → 复制 Hy2 链接到客户端"
echo ""
}
# ── 参数解析 ──
DOMAIN=""
ACME_EMAIL=""
PANEL_USERNAME=""
PANEL_PASSWORD=""
ASSUME_YES=0
while [[ $# -gt 0 ]]; do
case "$1" in
--domain) DOMAIN="$2"; shift 2 ;;
--email) ACME_EMAIL="$2"; shift 2 ;;
--username) PANEL_USERNAME="$2"; shift 2 ;;
--password) PANEL_PASSWORD="$2"; shift 2 ;;
--yes|-y) ASSUME_YES=1; shift ;;
-h|--help) usage; exit 0 ;;
*) err "未知参数: $1(使用 --help 查看)" ;;
esac
done
check_root
check_os
# curl | bash 时先 clone,再用仓库内脚本继续
ensure_repo
reexec_from_repo "$@"
print_banner
ROOT_DIR="$INSTALL_DIR"
ENV_FILE="$ROOT_DIR/.env"
check_existing_install
VPS_IP="$(detect_public_ip)"
log "检测到公网 IP: $VPS_IP"
prompt_if_empty DOMAIN "域名 (Hy2 + 面板 HTTPS)"
prompt_if_empty ACME_EMAIL "证书邮箱 (Let's Encrypt)"
prompt_if_empty PANEL_USERNAME "面板用户名" "admin"
valid_domain "$DOMAIN" || err "域名格式无效: $DOMAIN"
valid_email "$ACME_EMAIL" || err "邮箱格式无效: $ACME_EMAIL"
[[ -n "$PANEL_USERNAME" ]] || err "用户名不能为空"
if [[ -z "$PANEL_PASSWORD" ]]; then
read -r -s -p "面板密码 (留空自动生成): " PANEL_PASSWORD
echo ""
fi
if [[ -z "$PANEL_PASSWORD" ]]; then
PANEL_PASSWORD="$(generate_password)"
log "已自动生成面板密码"
fi
RESOLVED_IP="$(resolve_domain "$DOMAIN" || true)"
if [[ -z "$RESOLVED_IP" ]]; then
err "域名 $DOMAIN 无法解析,请先将 A 记录指向 $VPS_IP"
fi
if [[ "$RESOLVED_IP" != "$VPS_IP" ]]; then
warn "域名 $DOMAIN 解析为 $RESOLVED_IP,本机公网 IP 为 $VPS_IP"
if [[ "$ASSUME_YES" -eq 0 ]]; then
read -r -p "DNS 可能未生效,继续?(y/N): " dns_ok
case "${dns_ok:-N}" in
y|Y|yes|YES) ;;
*) err "请先修正 DNS 后重试" ;;
esac
fi
fi
if [[ "$ASSUME_YES" -eq 0 ]]; then
confirm_or_abort
fi
write_env_file
log "已写入 $ENV_FILE"
log "开始安装 ..."
bash "$ROOT_DIR/scripts/install.sh"
save_credentials
print_success
-3
View File
@@ -1,3 +0,0 @@
#!/usr/bin/env bash
# 已合并到 install.sh,保留此入口以兼容旧文档
exec bash "$(cd "$(dirname "${BASH_SOURCE[0]}")" && pwd)/install.sh" "$@"
+5 -1
View File
@@ -40,7 +40,11 @@ source "$ENV_FILE"
: "${PANEL_USERNAME:=admin}" : "${PANEL_USERNAME:=admin}"
if [[ -z "${PANEL_PASSWORD:-}" ]]; then if [[ -z "${PANEL_PASSWORD:-}" ]]; then
PANEL_PASSWORD="$(sing-box generate rand --base64 32 | tr -d '/+=' | head -c 20)" if command -v sing-box >/dev/null 2>&1; then
PANEL_PASSWORD="$(sing-box generate rand --base64 32 | tr -d '/+=' | head -c 20)"
else
PANEL_PASSWORD="$(openssl rand -base64 32 | tr -d '/+=' | head -c 20)"
fi
if grep -q "^PANEL_PASSWORD=" "$ENV_FILE" 2>/dev/null; then if grep -q "^PANEL_PASSWORD=" "$ENV_FILE" 2>/dev/null; then
sed -i "s|^PANEL_PASSWORD=.*|PANEL_PASSWORD=${PANEL_PASSWORD}|" "$ENV_FILE" sed -i "s|^PANEL_PASSWORD=.*|PANEL_PASSWORD=${PANEL_PASSWORD}|" "$ENV_FILE"
else else
-33
View File
@@ -1,33 +0,0 @@
#!/usr/bin/env bash
# 本地根据 .env 渲染客户端配置(无需在 VPS 上运行)
set -euo pipefail
SCRIPT_DIR="$(cd "$(dirname "${BASH_SOURCE[0]}")" && pwd)"
ROOT_DIR="$(dirname "$SCRIPT_DIR")"
ENV_FILE="${ROOT_DIR}/.env"
OUT_DIR="${ROOT_DIR}/client/generated"
[[ -f "$ENV_FILE" ]] || { echo "缺少 .env,请先 cp .env.example .env 并填写"; exit 1; }
# shellcheck disable=SC1090
source "$ENV_FILE"
for var in DOMAIN HY2_PASSWORD; do
[[ -n "${!var:-}" ]] || { echo "缺少 .env 变量: $var"; exit 1; }
done
mkdir -p "$OUT_DIR"
HY2_PASSWORD_ENC="$(python3 -c "import sys, urllib.parse; print(urllib.parse.quote(sys.argv[1], safe=''))" "$HY2_PASSWORD")"
sed -e "s|\${DOMAIN}|${DOMAIN}|g" \
-e "s|\${HY2_PASSWORD}|${HY2_PASSWORD}|g" \
"$ROOT_DIR/client/sing-box-client.json.template" > "$OUT_DIR/sing-box-client.json"
cat > "$OUT_DIR/share-links.txt" <<EOF
========== Hysteria2 ==========
hy2://${HY2_PASSWORD_ENC}@${DOMAIN}:8443?sni=${DOMAIN}#Hysteria2
EOF
echo "已生成:"
echo " $OUT_DIR/sing-box-client.json"
echo " $OUT_DIR/share-links.txt"
-1
View File
@@ -30,7 +30,6 @@ echo "[*] 清理本地数据(保留 .env 与代码)..."
ROOT="$(cd "$(dirname "${BASH_SOURCE[0]}")/.." && pwd)" ROOT="$(cd "$(dirname "${BASH_SOURCE[0]}")/.." && pwd)"
rm -rf "${ROOT}/data" rm -rf "${ROOT}/data"
rm -rf "${ROOT}/panel/venv" rm -rf "${ROOT}/panel/venv"
rm -rf "${ROOT}/client/generated"
echo "" echo ""
echo "卸载完成。重新安装:" echo "卸载完成。重新安装:"