mirror of
https://github.com/MHSanaei/3x-ui.git
synced 2026-06-07 13:44:24 +00:00
- Replace plain textarea with CodeMirror editor (YAML syntax highlighting, line numbers, auto-indent) for Clash subscription template - Fix confAlerts crash when subClashURI/subURI/subJsonURI is null/undefined (prevented save button from enabling) - Add yaml.js CodeMirror mode asset - Include docs and .gitignore cleanup
485 lines
15 KiB
Markdown
485 lines
15 KiB
Markdown
# install.sh 逻辑文档
|
||
|
||
## 概述
|
||
|
||
`install.sh` 是 3x-ui 面板的安装脚本,负责在 Linux 服务器上完成以下工作:
|
||
|
||
1. 安装系统依赖包
|
||
2. 下载并解压 3x-ui 发行版
|
||
3. 配置 systemd / OpenRC 服务
|
||
4. 生成随机凭据(用户名、密码、端口、Web 路径)
|
||
5. 配置 SSL 证书(Let's Encrypt 域名证书、IP 证书、或自定义证书)
|
||
6. 显示安装结果和访问信息
|
||
|
||
---
|
||
|
||
## 全局配置
|
||
|
||
### 颜色变量
|
||
|
||
| 变量 | 值 | 用途 |
|
||
|---------|----------------|------------|
|
||
| `red` | `\033[0;31m` | 红色文本 |
|
||
| `green` | `\033[0;32m` | 绿色文本 |
|
||
| `blue` | `\033[0;34m` | 蓝色文本 |
|
||
| `yellow`| `\033[0;33m` | 黄色文本 |
|
||
| `plain` | `\033[0m` | 重置颜色 |
|
||
|
||
### 路径变量
|
||
|
||
| 变量 | 默认值 | 说明 |
|
||
|-----------------|-------------------------|--------------------------|
|
||
| `xui_folder` | `/usr/local/x-ui` | x-ui 安装目录 |
|
||
| `xui_service` | `/etc/systemd/system` | systemd 服务文件目录 |
|
||
|
||
可通过环境变量 `XUI_MAIN_FOLDER` 和 `XUI_SERVICE` 覆盖。
|
||
|
||
---
|
||
|
||
## 入口流程
|
||
|
||
```
|
||
install.sh 被执行
|
||
├─ 检查 root 权限
|
||
├─ 检测操作系统发行版
|
||
├─ 检测 CPU 架构
|
||
├─ install_base() ← 安装系统依赖
|
||
└─ install_x-ui($1) ← 主安装逻辑($1 为可选的版本号)
|
||
```
|
||
|
||
---
|
||
|
||
## 函数详解
|
||
|
||
### 1. root 权限检查(第 14-15 行)
|
||
|
||
检查 `$EUID` 是否为 0。非 root 用户直接退出并提示使用 root 权限。
|
||
|
||
### 2. 操作系统检测(第 17-28 行)
|
||
|
||
读取 `/etc/os-release` 或 `/usr/lib/os-release`,将 `$ID` 赋值给 `release` 变量。
|
||
|
||
支持的发行版:
|
||
|
||
| 包管理器 | 发行版 |
|
||
|----------|--------|
|
||
| `apt` | ubuntu, debian, armbian |
|
||
| `dnf` | fedora, amzn, virtuozzo, rhel, almalinux, rocky, ol |
|
||
| `yum` | centos 7 |
|
||
| `pacman` | arch, manjaro, parch |
|
||
| `zypper` | opensuse-tumbleweed, opensuse-leap |
|
||
| `apk` | alpine |
|
||
|
||
### 3. `arch()` — CPU 架构检测(第 30-41 行)
|
||
|
||
通过 `uname -m` 映射到标准架构标识:
|
||
|
||
| `uname -m` 输出 | 返回值 |
|
||
|------------------------|----------|
|
||
| x86_64, x64, amd64 | `amd64` |
|
||
| i*86, x86 | `386` |
|
||
| armv8*, arm64, aarch64 | `arm64` |
|
||
| armv7*, arm | `armv7` |
|
||
| armv6* | `armv6` |
|
||
| armv5* | `armv5` |
|
||
| s390x | `s390x` |
|
||
| 其他 | 退出报错 |
|
||
|
||
### 4. IP/域名验证函数(第 46-57 行)
|
||
|
||
| 函数 | 逻辑 |
|
||
|---------------|---------------------------------------------------|
|
||
| `is_ipv4()` | 正则匹配 `数字.数字.数字.数字` 格式 |
|
||
| `is_ipv6()` | 检查字符串是否包含 `:` |
|
||
| `is_ip()` | 调用 `is_ipv4` 或 `is_ipv6` |
|
||
| `is_domain()` | 正则匹配标准域名格式(含国际化域名 `xn--` 支持) |
|
||
|
||
### 5. `is_port_in_use()` — 端口占用检测(第 60-74 行)
|
||
|
||
按优先级尝试三种方式:
|
||
|
||
1. `ss -ltn` — 检查监听端口
|
||
2. `netstat -lnt` — 回退方案
|
||
3. `lsof -nP -iTCP:端口 -sTCP:LISTEN` — 最后手段
|
||
|
||
任一命中即返回 0(端口被占用)。
|
||
|
||
### 6. `install_base()` — 安装基础依赖(第 76-104 行)
|
||
|
||
根据 `$release` 使用对应的包管理器安装以下公共依赖:
|
||
|
||
```
|
||
curl, tar, tzdata, socat, ca-certificates, openssl
|
||
```
|
||
|
||
额外安装 `cron`(用于 acme.sh 自动续期,仅 apt 系列)。
|
||
|
||
- CentOS 7 使用 `yum`,其他版本使用 `dnf`
|
||
- 未识别的发行版默认回退到 `apt-get`
|
||
|
||
### 7. `gen_random_string(length)` — 随机字符串生成(第 106-111 行)
|
||
|
||
```
|
||
openssl rand -base64(length*2) → 过滤 a-zA-Z0-9 → 截取前 length 个字符
|
||
```
|
||
|
||
用于生成用户名、密码、Web 路径等随机值。
|
||
|
||
### 8. `install_acme()` — 安装 acme.sh(第 113-124 行)
|
||
|
||
```bash
|
||
curl -s https://get.acme.sh | sh
|
||
```
|
||
|
||
安装到 `~/.acme.sh/` 目录。失败返回 1。
|
||
|
||
---
|
||
|
||
## SSL 证书管理
|
||
|
||
### 9. `setup_ssl_certificate(domain, server_ip, port, webBasePath)` — 域名 SSL(第 126-191 行)
|
||
|
||
**用途**:为域名签发 Let's Encrypt 证书。
|
||
|
||
**流程**:
|
||
|
||
```
|
||
检查 acme.sh 是否已安装
|
||
├─ 未安装 → 调用 install_acme()
|
||
└─ 已安装 → 继续
|
||
|
||
创建证书目录:/root/cert/${domain}/
|
||
|
||
签发证书:
|
||
acme.sh --set-default-ca --server letsencrypt
|
||
acme.sh --issue -d ${domain} --listen-v6 --standalone --httpport 80
|
||
↳ 失败 → 清理并返回 1
|
||
|
||
安装证书:
|
||
acme.sh --installcert
|
||
--key-file /root/cert/${domain}/privkey.pem
|
||
--fullchain-file /root/cert/${domain}/fullchain.pem
|
||
--reloadcmd "systemctl restart x-ui"
|
||
|
||
启用自动续期:acme.sh --upgrade --auto-upgrade
|
||
|
||
设置文件权限:
|
||
privkey.pem → 600(仅所有者可读)
|
||
fullchain.pem → 644
|
||
|
||
配置面板证书路径:
|
||
x-ui cert -webCert fullchain.pem -webCertKey privkey.pem
|
||
```
|
||
|
||
**前提条件**:80 端口必须可从外网访问。
|
||
|
||
### 10. `setup_ip_certificate(ipv4, ipv6)` — IP 证书(第 195-343 行)
|
||
|
||
**用途**:为 IP 地址签发 Let's Encrypt 短期证书(约 6 天有效期)。
|
||
|
||
**流程**:
|
||
|
||
```
|
||
检查 acme.sh
|
||
验证 IPv4 地址格式
|
||
|
||
创建证书目录:/root/cert/ip/
|
||
|
||
选择 HTTP-01 监听端口:
|
||
└─ 默认 80,用户可自定义
|
||
└─ 循环检测端口占用,被占用则提示换端口
|
||
|
||
签发证书:
|
||
acme.sh --issue
|
||
-d ${ipv4} [-d ${ipv6}]
|
||
--standalone
|
||
--server letsencrypt
|
||
--certificate-profile shortlived
|
||
--days 6
|
||
--httpport ${WebPort}
|
||
|
||
安装证书:
|
||
acme.sh --installcert
|
||
--key-file /root/cert/ip/privkey.pem
|
||
--fullchain-file /root/cert/ip/fullchain.pem
|
||
--reloadcmd "systemctl restart x-ui || rc-service x-ui restart"
|
||
↳ 通过检查文件是否存在(而非退出码)判断成功
|
||
|
||
启用自动续期
|
||
设置文件权限
|
||
配置面板证书路径
|
||
```
|
||
|
||
**关键特性**:
|
||
|
||
- 使用 `--certificate-profile shortlived` 配置文件,证书有效期约 6 天
|
||
- acme.sh cron 任务会在到期前自动续期
|
||
- 不依赖退出码判断安装成功(因为 reloadcmd 失败会导致非零退出)
|
||
- 支持 IPv4 + IPv6 双栈
|
||
|
||
### 11. `ssl_cert_issue()` — 手动 SSL 证书签发(第 346-509 行)
|
||
|
||
**用途**:交互式域名证书签发,提供更多自定义选项。
|
||
|
||
**流程**:
|
||
|
||
```
|
||
读取当前面板的 webBasePath 和 port
|
||
|
||
检查 acme.sh(不存在则安装)
|
||
|
||
获取并验证用户输入的域名:
|
||
└─ 循环直到输入有效域名
|
||
└─ 检查是否已存在该域名的证书
|
||
|
||
创建证书目录:/root/cert/${domain}/
|
||
|
||
选择端口(默认 80)
|
||
|
||
临时停止面板(释放端口)
|
||
|
||
签发证书:
|
||
acme.sh --issue -d ${domain} --listen-v6 --standalone --httpport ${WebPort}
|
||
|
||
设置 reloadcmd(证书续期后执行的命令):
|
||
├─ 默认:systemctl restart x-ui || rc-service x-ui restart
|
||
├─ 选项 1:systemctl reload nginx ; systemctl restart x-ui
|
||
├─ 选项 2:自定义命令
|
||
└─ 选项 0:保持默认
|
||
|
||
安装证书并启用自动续期
|
||
|
||
启动面板
|
||
|
||
询问是否将证书应用到面板:
|
||
└─ 是 → x-ui cert -webCert ... -webCertKey ...
|
||
└─ 否 → 跳过
|
||
```
|
||
|
||
**特点**:
|
||
|
||
- 签发前会停止面板以释放端口
|
||
- 支持自定义 reloadcmd(例如先 reload nginx 再重启 x-ui)
|
||
- 签发失败会自动重新启动面板
|
||
|
||
### 12. `prompt_and_setup_ssl(panel_port, web_base_path, server_ip)` — SSL 选择菜单(第 513-638 行)
|
||
|
||
**用途**:安装时的统一 SSL 配置入口,提供三种选择。
|
||
|
||
**菜单**:
|
||
|
||
```
|
||
1. Let's Encrypt 域名证书(90 天有效期,自动续期)
|
||
└─ 调用 ssl_cert_issue()
|
||
└─ 从 acme.sh 列表提取域名作为 SSL_HOST
|
||
|
||
2. Let's Encrypt IP 证书(6 天有效期,自动续期) ← 默认选项
|
||
└─ 可选输入 IPv6 地址
|
||
└─ 停止面板释放 80 端口
|
||
└─ 调用 setup_ip_certificate(server_ip, ipv6)
|
||
└─ SSL_HOST = server_ip
|
||
|
||
3. 自定义 SSL 证书(指定已有文件路径)
|
||
└─ 输入域名
|
||
└─ 循环验证证书文件(存在、可读、非空)
|
||
└─ 循环验证私钥文件(存在、可读、非空)
|
||
└─ x-ui cert -webCert ... -webCertKey ...
|
||
└─ 提示用户自行管理续期
|
||
```
|
||
|
||
**全局变量**:设置 `SSL_HOST` 供后续显示访问地址使用。
|
||
|
||
---
|
||
|
||
## 安装后配置
|
||
|
||
### 13. `config_after_install()` — 安装后配置(第 640-760 行)
|
||
|
||
**用途**:首次安装后的凭据生成、端口设置、Web 路径生成、SSL 配置。
|
||
|
||
**流程图**:
|
||
|
||
```
|
||
读取当前面板设置:
|
||
- hasDefaultCredential(是否为默认凭据)
|
||
- webBasePath
|
||
- port
|
||
- cert(证书路径)
|
||
|
||
获取服务器公网 IP:
|
||
└─ 依次尝试 6 个 API:
|
||
1. api4.ipify.org
|
||
2. ipv4.icanhazip.com
|
||
3. v4.api.ipinfo.io/ip
|
||
4. ipv4.myexternalip.com/raw
|
||
5. 4.ident.me
|
||
6. check-host.net/ip
|
||
|
||
判断 webBasePath 是否足够长(≥4 字符):
|
||
|
||
┌─ webBasePath 过短
|
||
│
|
||
│ ├─ hasDefaultCredential == true(首次安装)
|
||
│ │ ├─ 生成随机 webBasePath(18 位)
|
||
│ │ ├─ 生成随机用户名(10 位)
|
||
│ │ ├─ 生成随机密码(10 位)
|
||
│ │ ├─ 询问是否自定义端口
|
||
│ │ │ ├─ 是 → 用户输入端口
|
||
│ │ │ └─ 否 → 随机生成 1024-62000 范围端口
|
||
│ │ ├─ 应用设置:x-ui setting -username ... -password ... -port ... -webBasePath ...
|
||
│ │ ├─ prompt_and_setup_ssl() ← 必需
|
||
│ │ └─ 显示完整凭据和访问地址
|
||
│ │
|
||
│ └─ hasDefaultCredential != true(非首次安装)
|
||
│ ├─ 生成新 webBasePath
|
||
│ ├─ 检查是否有证书:
|
||
│ │ ├─ 无 → prompt_and_setup_ssl()(推荐)
|
||
│ │ └─ 有 → 显示 HTTP 访问地址
|
||
│ └─ 结束
|
||
│
|
||
└─ webBasePath 正常(≥4 字符)
|
||
|
||
├─ hasDefaultCredential == true
|
||
│ ├─ 生成随机用户名和密码
|
||
│ ├─ 应用新凭据
|
||
│ └─ 显示凭据
|
||
│
|
||
└─ hasDefaultCredential != true
|
||
└─ 提示凭据已正确设置
|
||
|
||
再次检查证书:
|
||
├─ 无证书 → prompt_and_setup_ssl()(推荐)
|
||
└─ 有证书 → 跳过
|
||
|
||
最后执行:x-ui migrate(数据库迁移)
|
||
```
|
||
|
||
---
|
||
|
||
## 主安装逻辑
|
||
|
||
### 14. `install_x-ui(version)` — 主安装函数(第 762-958 行)
|
||
|
||
**参数**:`$1` 可选,指定安装版本号(如 `v2.3.5`)。
|
||
|
||
**流程**:
|
||
|
||
```
|
||
cd /usr/local/
|
||
|
||
┌─ 无版本参数(安装最新版)
|
||
│ ├─ 从 GitHub API 获取最新版本号
|
||
│ │ └─ IPv4 失败时重试 curl -4
|
||
│ └─ 下载:x-ui-linux-${arch}.tar.gz
|
||
│
|
||
└─ 有版本参数
|
||
├─ 验证版本号 ≥ v2.3.5
|
||
└─ 下载指定版本
|
||
|
||
同时下载 x-ui.sh 到 /usr/bin/x-ui-temp
|
||
|
||
停止已有 x-ui 服务并删除旧安装目录
|
||
|
||
解压 tar.gz,设置执行权限
|
||
|
||
ARM 架构特殊处理:
|
||
armv5/armv6/armv7 → 重命名为 xray-linux-arm
|
||
|
||
安装 x-ui.sh 到 /usr/bin/x-ui
|
||
创建日志目录 /var/log/x-ui/
|
||
|
||
调用 config_after_install() ← 生成凭据 + SSL
|
||
|
||
etckeeper 兼容:
|
||
└─ 如果 /etc/.git 存在,将 x-ui.db 加入 .gitignore
|
||
|
||
┌─ Alpine Linux
|
||
│ ├─ 下载 OpenRC 脚本 x-ui.rc → /etc/init.d/x-ui
|
||
│ ├─ rc-update add x-ui(启用开机自启)
|
||
│ └─ rc-service x-ui start
|
||
│
|
||
└─ 其他系统(systemd)
|
||
├─ 优先使用 tar.gz 中的服务文件
|
||
│ ├─ x-ui.service ← 通用
|
||
│ ├─ x-ui.service.debian ← Ubuntu/Debian
|
||
│ ├─ x-ui.service.arch ← Arch/Manjaro
|
||
│ └─ x-ui.service.rhel ← 其他(CentOS/Fedora 等)
|
||
│
|
||
├─ 如果 tar.gz 中没有,从 GitHub 下载对应文件
|
||
│
|
||
└─ 配置服务:
|
||
chown root:root x-ui.service
|
||
chmod 644 x-ui.service
|
||
systemctl daemon-reload
|
||
systemctl enable x-ui
|
||
systemctl start x-ui
|
||
|
||
显示安装完成信息和子命令用法
|
||
```
|
||
|
||
**子命令列表**(安装完成后显示):
|
||
|
||
| 命令 | 功能 |
|
||
|-------------------|--------------------|
|
||
| `x-ui` | 打开管理菜单 |
|
||
| `x-ui start` | 启动面板 |
|
||
| `x-ui stop` | 停止面板 |
|
||
| `x-ui restart` | 重启面板 |
|
||
| `x-ui status` | 查看状态 |
|
||
| `x-ui settings` | 查看当前设置 |
|
||
| `x-ui enable` | 设置开机自启 |
|
||
| `x-ui disable` | 取消开机自启 |
|
||
| `x-ui log` | 查看日志 |
|
||
| `x-ui banlog` | 查看 Fail2ban 日志 |
|
||
| `x-ui update` | 更新 |
|
||
| `x-ui legacy` | 安装旧版本 |
|
||
| `x-ui install` | 安装 |
|
||
| `x-ui uninstall` | 卸载 |
|
||
|
||
---
|
||
|
||
## 调用关系总结
|
||
|
||
```
|
||
install.sh
|
||
│
|
||
├─ install_base()
|
||
│ └─ 根据发行版安装 curl, tar, tzdata, socat, ca-certificates, openssl
|
||
│
|
||
└─ install_x-ui($1)
|
||
├─ 下载 x-ui 发行版和 x-ui.sh
|
||
├─ 解压、设置权限
|
||
├─ config_after_install()
|
||
│ ├─ gen_random_string() × 3(用户名/密码/Web路径)
|
||
│ ├─ 获取公网 IP
|
||
│ ├─ prompt_and_setup_ssl()
|
||
│ │ ├─ [选项1] ssl_cert_issue()
|
||
│ │ │ ├─ install_acme()
|
||
│ │ │ └─ acme.sh 签发/安装/续期域名证书
|
||
│ │ ├─ [选项2] setup_ip_certificate()
|
||
│ │ │ ├─ install_acme()
|
||
│ │ │ └─ acme.sh 签发/安装/续期 IP 短期证书
|
||
│ │ └─ [选项3] 用户提供自定义证书路径
|
||
│ └─ x-ui migrate
|
||
└─ 配置系统服务(systemd 或 OpenRC)
|
||
```
|
||
|
||
---
|
||
|
||
## 关键设计决策
|
||
|
||
1. **强制 SSL**:首次安装时必须配置 SSL 证书(三种方式选一),确保面板通过 HTTPS 访问。
|
||
|
||
2. **随机化安全**:用户名、密码、端口、Web 路径全部随机生成,避免使用默认凭据。
|
||
|
||
3. **多 OS 兼容**:通过 `case` 语句适配 7 大包管理器体系,Alpine 使用 OpenRC,其余使用 systemd。
|
||
|
||
4. **IP 证书支持**:利用 Let's Encrypt 的 shortlived profile,为无域名场景提供 SSL 支持(6 天有效期,自动续期)。
|
||
|
||
5. **优雅降级**:
|
||
- GitHub API 失败时用 `curl -4` 重试
|
||
- `ss` 不可用时回退到 `netstat`,再回退到 `lsof`
|
||
- tar.gz 中无服务文件时从 GitHub 下载
|
||
- acme.sh reloadcmd 失败不阻止证书安装
|
||
|
||
6. **etckeeper 兼容**:自动将数据库文件加入 `/etc/.gitignore`,避免 etckeeper 追踪频繁变化的数据库。
|