3x-ui 式共享节点改造:nodes 状态机 + nodeClients 各自凭据
- 移除 VMess 协议 - VLESS/SS2022 按用户流量统计(AnyTLS 日志解析,SS 节点级) - sing-box v2ray_api stats 支持 - 内存优化:面板 128M,agent 64M,sing-box 64M
This commit is contained in:
+109
-29
@@ -25,52 +25,107 @@ while [[ $# -gt 0 ]]; do
|
||||
done
|
||||
|
||||
[[ "${EUID}" -eq 0 ]] || die "请使用 root 运行"
|
||||
[[ -f /etc/debian_version ]] || die "控制面一键安装器当前支持 Debian 12 / Ubuntu 22.04+"
|
||||
[[ ! -e /opt/nexusgate ]] || die "检测到已有安装,请运行 nexusgate update"
|
||||
IS_OPENWRT=false
|
||||
if [[ -f /etc/openwrt_release ]]; then
|
||||
IS_OPENWRT=true
|
||||
elif [[ ! -f /etc/debian_version ]]; then
|
||||
die "控制面一键安装器当前支持 Debian 12 / Ubuntu 22.04+ 和 OpenWrt"
|
||||
fi
|
||||
|
||||
if [[ -z "$DOMAIN" ]]; then DOMAIN="$(ask '请输入面板域名(如 gate.example.com):')"; fi
|
||||
[[ "$DOMAIN" =~ ^[A-Za-z0-9.-]+$ ]] || die "域名格式不正确"
|
||||
if [[ -z "$DOMAIN" ]]; then
|
||||
if $IS_OPENWRT; then
|
||||
DOMAIN="$(ask '面板域名(OpenWrt 上可留空,留空则仅内网访问、不配置 Caddy):')"
|
||||
else
|
||||
DOMAIN="$(ask '请输入面板域名(如 gate.example.com):')"
|
||||
fi
|
||||
fi
|
||||
if [[ -n "$DOMAIN" ]]; then
|
||||
[[ "$DOMAIN" =~ ^[A-Za-z0-9.-]+$ ]] || die "域名格式不正确"
|
||||
elif ! $IS_OPENWRT; then
|
||||
die "域名不能为空"
|
||||
fi
|
||||
if [[ -z "$EMAIL" ]]; then EMAIL="$(ask '证书邮箱(可留空):')"; fi
|
||||
|
||||
info "安装系统依赖"
|
||||
export DEBIAN_FRONTEND=noninteractive
|
||||
apt-get update -qq
|
||||
apt-get install -y -qq ca-certificates curl tar openssl nodejs caddy
|
||||
if $IS_OPENWRT; then
|
||||
# 注意:OpenWrt 上需预先装好 bash(本脚本依赖 bash):opkg update && opkg install bash
|
||||
opkg update
|
||||
# OpenWrt 上 openssl 命令行工具在 openssl-util 包里;部分精简固件没有 install 命令,需 coreutils-install
|
||||
opkg install node caddy curl ca-certificates openssl-util tar coreutils-install
|
||||
else
|
||||
export DEBIAN_FRONTEND=noninteractive
|
||||
apt-get update -qq
|
||||
apt-get install -y -qq ca-certificates curl tar openssl nodejs caddy
|
||||
fi
|
||||
node_major="$(node -p 'process.versions.node.split(`.`)[0]')"
|
||||
[[ "$node_major" -ge 18 ]] || die "需要 Node.js 18 或更高版本"
|
||||
|
||||
tmp_dir="$(mktemp -d /tmp/nexusgate-install.XXXXXX)"
|
||||
trap 'rm -rf -- "$tmp_dir"' EXIT
|
||||
info "下载 ${REPO}@${BRANCH}"
|
||||
curl -fL --retry 3 "https://github.com/${REPO}/archive/refs/heads/${BRANCH}.tar.gz" -o "$tmp_dir/source.tgz"
|
||||
mkdir -p "$tmp_dir/source"
|
||||
tar -xzf "$tmp_dir/source.tgz" -C "$tmp_dir/source" --strip-components=1
|
||||
[[ -f "$tmp_dir/source/server.js" ]] || die "安装包不完整"
|
||||
# NG_LOCAL_SRC 指向本地源码目录时跳过 GitHub 下载(本地改动尚未 push 时的全新安装用这个)
|
||||
src_dir=""
|
||||
if [[ -n "${NG_LOCAL_SRC:-}" ]]; then
|
||||
[[ -f "${NG_LOCAL_SRC}/server.js" ]] || die "NG_LOCAL_SRC 目录不完整(缺少 server.js)"
|
||||
info "使用本地源码 ${NG_LOCAL_SRC}"
|
||||
src_dir="${NG_LOCAL_SRC}"
|
||||
else
|
||||
tmp_dir="$(mktemp -d /tmp/nexusgate-install.XXXXXX)"
|
||||
trap 'rm -rf -- "$tmp_dir"' EXIT
|
||||
info "下载 ${REPO}@${BRANCH}"
|
||||
curl -fL --retry 3 "https://github.com/${REPO}/archive/refs/heads/${BRANCH}.tar.gz" -o "$tmp_dir/source.tgz"
|
||||
mkdir -p "$tmp_dir/source"
|
||||
tar -xzf "$tmp_dir/source.tgz" -C "$tmp_dir/source"
|
||||
# GitHub tarball 解包后只有一层顶层目录;不用 --strip-components(BusyBox tar 不支持)
|
||||
src_dir="$(echo "$tmp_dir/source"/*/)"
|
||||
[[ -f "${src_dir}server.js" ]] || die "安装包不完整"
|
||||
fi
|
||||
|
||||
getent group nexusgate >/dev/null || groupadd --system nexusgate
|
||||
id nexusgate >/dev/null 2>&1 || useradd --system --gid nexusgate --home-dir /var/lib/nexusgate --shell /usr/sbin/nologin nexusgate
|
||||
install -d -o root -g root -m 0755 /opt/nexusgate
|
||||
cp -a "$tmp_dir/source/." /opt/nexusgate/
|
||||
install -d -o nexusgate -g nexusgate -m 0700 /var/lib/nexusgate
|
||||
if $IS_OPENWRT; then
|
||||
# OpenWrt 是单用户系统,不建专用账号;/var 是内存盘,数据必须放闪存
|
||||
DATA_DIR=/etc/nexusgate/data
|
||||
install -d -m 0755 /opt/nexusgate
|
||||
cp -a "${src_dir}/." /opt/nexusgate/
|
||||
install -d -m 0700 "$DATA_DIR"
|
||||
else
|
||||
DATA_DIR=/var/lib/nexusgate
|
||||
getent group nexusgate >/dev/null || groupadd --system nexusgate
|
||||
id nexusgate >/dev/null 2>&1 || useradd --system --gid nexusgate --home-dir /var/lib/nexusgate --shell /usr/sbin/nologin nexusgate
|
||||
install -d -o root -g root -m 0755 /opt/nexusgate
|
||||
cp -a "${src_dir}/." /opt/nexusgate/
|
||||
install -d -o nexusgate -g nexusgate -m 0700 "$DATA_DIR"
|
||||
fi
|
||||
|
||||
if $IS_OPENWRT && [[ -z "$DOMAIN" ]]; then
|
||||
# 无域名:直接监听内网(OpenWrt 防火墙默认拦截 WAN 入站),纯 HTTP
|
||||
NG_HOST=0.0.0.0
|
||||
NG_COOKIE_SECURE=false
|
||||
else
|
||||
NG_HOST=127.0.0.1
|
||||
NG_COOKIE_SECURE=true
|
||||
fi
|
||||
admin_password="$(openssl rand -base64 24 | tr -d '\n')"
|
||||
session_secret="$(openssl rand -hex 32)"
|
||||
cat > /etc/nexusgate.env <<EOF
|
||||
NODE_ENV=production
|
||||
NG_HOST=127.0.0.1
|
||||
NG_HOST=${NG_HOST}
|
||||
NG_PORT=8787
|
||||
NG_DATA_FILE=/var/lib/nexusgate/nexusgate.json
|
||||
NG_COOKIE_SECURE=true
|
||||
NG_DATA_FILE=${DATA_DIR}/nexusgate.json
|
||||
NG_COOKIE_SECURE=${NG_COOKIE_SECURE}
|
||||
NG_ADMIN_USERNAME=admin
|
||||
NG_ADMIN_PASSWORD=${admin_password}
|
||||
NG_SESSION_SECRET=${session_secret}
|
||||
EOF
|
||||
chmod 0600 /etc/nexusgate.env
|
||||
|
||||
install -m 0644 /opt/nexusgate/systemd/nexusgate.service /etc/systemd/system/nexusgate.service
|
||||
install -d -m 0755 /usr/local/sbin
|
||||
install -m 0755 /opt/nexusgate/scripts/nexusgate.sh /usr/local/sbin/nexusgate
|
||||
ln -sf /usr/local/sbin/nexusgate /usr/local/sbin/ng
|
||||
if $IS_OPENWRT; then
|
||||
install -m 0755 /opt/nexusgate/openrc/nexusgate /etc/init.d/nexusgate
|
||||
else
|
||||
install -m 0644 /opt/nexusgate/systemd/nexusgate.service /etc/systemd/system/nexusgate.service
|
||||
fi
|
||||
|
||||
if [[ -n "$DOMAIN" ]]; then
|
||||
install -d -m 0755 /etc/caddy/Caddyfile.d
|
||||
cat > /etc/caddy/Caddyfile.d/nexusgate.caddy <<EOF
|
||||
${DOMAIN} {
|
||||
@@ -96,23 +151,48 @@ fi
|
||||
caddy fmt --overwrite /etc/caddy/Caddyfile
|
||||
caddy fmt --overwrite /etc/caddy/Caddyfile.d/nexusgate.caddy
|
||||
caddy validate --config /etc/caddy/Caddyfile
|
||||
fi
|
||||
|
||||
systemctl daemon-reload
|
||||
systemctl enable --now nexusgate.service
|
||||
if $IS_OPENWRT; then
|
||||
/etc/init.d/nexusgate enable
|
||||
/etc/init.d/nexusgate start
|
||||
else
|
||||
systemctl daemon-reload
|
||||
systemctl enable --now nexusgate.service
|
||||
fi
|
||||
healthy=false
|
||||
for _ in {1..30}; do
|
||||
if curl -fsS http://127.0.0.1:8787/healthz >/dev/null 2>&1; then healthy=true; break; fi
|
||||
sleep 1
|
||||
done
|
||||
if [[ "$healthy" != true ]]; then
|
||||
systemctl status nexusgate --no-pager || true
|
||||
journalctl -u nexusgate -n 100 --no-pager || true
|
||||
if $IS_OPENWRT; then
|
||||
logread 2>/dev/null | grep -a nexusgate | tail -n 100 || true
|
||||
else
|
||||
systemctl status nexusgate --no-pager || true
|
||||
journalctl -u nexusgate -n 100 --no-pager || true
|
||||
fi
|
||||
die "控制面启动失败,诊断信息已输出"
|
||||
fi
|
||||
if $IS_OPENWRT && [[ "$NG_HOST" == "0.0.0.0" ]] && ! netstat -tln 2>/dev/null | grep -q "0.0.0.0:8787"; then
|
||||
die "控制面未监听 0.0.0.0:8787(环境变量未正确传递),请检查 /etc/init.d/nexusgate"
|
||||
fi
|
||||
sed -i '/^NG_ADMIN_PASSWORD=/d' /etc/nexusgate.env
|
||||
systemctl enable --now caddy
|
||||
systemctl reload caddy
|
||||
if [[ -n "$DOMAIN" ]]; then
|
||||
if $IS_OPENWRT; then
|
||||
/etc/init.d/caddy enable
|
||||
/etc/init.d/caddy restart
|
||||
else
|
||||
systemctl enable --now caddy
|
||||
systemctl reload caddy
|
||||
fi
|
||||
fi
|
||||
|
||||
printf '\n\033[1;32m安装完成\033[0m\n'
|
||||
printf '地址:https://%s\n账号:admin\n密码:%s\n' "$DOMAIN" "$admin_password"
|
||||
if [[ -n "$DOMAIN" ]]; then
|
||||
printf '地址:https://%s\n' "$DOMAIN"
|
||||
else
|
||||
printf '地址:http://<路由器 LAN IP>:8787(内网访问)\n'
|
||||
fi
|
||||
printf '账号:admin\n密码:%s\n' "$admin_password"
|
||||
printf '管理命令:nexusgate 或 ng\n请立即登录并妥善保存密码。\n'
|
||||
|
||||
Reference in New Issue
Block a user