- 移除 VMess 协议 - VLESS/SS2022 按用户流量统计(AnyTLS 日志解析,SS 节点级) - sing-box v2ray_api stats 支持 - 内存优化:面板 128M,agent 64M,sing-box 64M
199 lines
6.7 KiB
Bash
Executable File
199 lines
6.7 KiB
Bash
Executable File
#!/usr/bin/env bash
|
||
set -Eeuo pipefail
|
||
|
||
REPO="${NG_REPO:-a2899882/NexusGate}"
|
||
BRANCH="${NG_BRANCH:-main}"
|
||
DOMAIN=""
|
||
EMAIL=""
|
||
|
||
die() { printf '错误:%s\n' "$*" >&2; exit 1; }
|
||
info() { printf '\033[1;36m[NexusGate]\033[0m %s\n' "$*"; }
|
||
ask() {
|
||
local prompt="$1" value=""
|
||
if [[ -r /dev/tty ]]; then read -r -p "$prompt" value </dev/tty; fi
|
||
printf '%s' "$value"
|
||
}
|
||
|
||
while [[ $# -gt 0 ]]; do
|
||
case "$1" in
|
||
--domain) DOMAIN="${2:-}"; shift 2 ;;
|
||
--email) EMAIL="${2:-}"; shift 2 ;;
|
||
--repo) REPO="${2:-}"; shift 2 ;;
|
||
--branch) BRANCH="${2:-}"; shift 2 ;;
|
||
*) die "未知参数:$1" ;;
|
||
esac
|
||
done
|
||
|
||
[[ "${EUID}" -eq 0 ]] || die "请使用 root 运行"
|
||
[[ ! -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
|
||
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 "安装系统依赖"
|
||
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 或更高版本"
|
||
|
||
# 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
|
||
|
||
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=${NG_HOST}
|
||
NG_PORT=8787
|
||
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 -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} {
|
||
encode zstd gzip
|
||
reverse_proxy 127.0.0.1:8787
|
||
header {
|
||
Strict-Transport-Security "max-age=31536000; includeSubDomains"
|
||
-Server
|
||
}
|
||
log {
|
||
output file /var/log/caddy/nexusgate-access.log {
|
||
roll_size 20MiB
|
||
roll_keep 5
|
||
roll_keep_for 168h
|
||
}
|
||
}
|
||
EOF
|
||
if [[ -n "$EMAIL" ]]; then printf ' tls %s\n' "$EMAIL" >> /etc/caddy/Caddyfile.d/nexusgate.caddy; fi
|
||
printf '}\n' >> /etc/caddy/Caddyfile.d/nexusgate.caddy
|
||
if ! grep -qF 'import /etc/caddy/Caddyfile.d/*' /etc/caddy/Caddyfile; then
|
||
printf '\nimport /etc/caddy/Caddyfile.d/*\n' >> /etc/caddy/Caddyfile
|
||
fi
|
||
caddy fmt --overwrite /etc/caddy/Caddyfile
|
||
caddy fmt --overwrite /etc/caddy/Caddyfile.d/nexusgate.caddy
|
||
caddy validate --config /etc/caddy/Caddyfile
|
||
fi
|
||
|
||
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
|
||
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
|
||
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'
|
||
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'
|