- 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
15 KiB
install.sh 逻辑文档
概述
install.sh 是 3x-ui 面板的安装脚本,负责在 Linux 服务器上完成以下工作:
- 安装系统依赖包
- 下载并解压 3x-ui 发行版
- 配置 systemd / OpenRC 服务
- 生成随机凭据(用户名、密码、端口、Web 路径)
- 配置 SSL 证书(Let's Encrypt 域名证书、IP 证书、或自定义证书)
- 显示安装结果和访问信息
全局配置
颜色变量
| 变量 | 值 | 用途 |
|---|---|---|
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 行)
按优先级尝试三种方式:
ss -ltn— 检查监听端口netstat -lnt— 回退方案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 行)
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)
关键设计决策
-
强制 SSL:首次安装时必须配置 SSL 证书(三种方式选一),确保面板通过 HTTPS 访问。
-
随机化安全:用户名、密码、端口、Web 路径全部随机生成,避免使用默认凭据。
-
多 OS 兼容:通过
case语句适配 7 大包管理器体系,Alpine 使用 OpenRC,其余使用 systemd。 -
IP 证书支持:利用 Let's Encrypt 的 shortlived profile,为无域名场景提供 SSL 支持(6 天有效期,自动续期)。
-
优雅降级:
- GitHub API 失败时用
curl -4重试 ss不可用时回退到netstat,再回退到lsof- tar.gz 中无服务文件时从 GitHub 下载
- acme.sh reloadcmd 失败不阻止证书安装
- GitHub API 失败时用
-
etckeeper 兼容:自动将数据库文件加入
/etc/.gitignore,避免 etckeeper 追踪频繁变化的数据库。