Files
aaaamoooo f4ef3d96a6
CI / test (push) Canceled after 0s
CI / anytls-smoke (push) Canceled after 0s
chore: migrate self-distribution links from GitHub to self-hosted Gitea
GitHub accounts suspended; all first-party distribution now served from
git.881218.xyz/rogue/NexusGate (Gitea):
- raw:  /rogue/NexusGate/raw/branch/<branch>/<path>
- release assets and source archives under the same repo path
- scripts gain a GIT_BASE variable built from NG_REPO (default
  rogue/NexusGate); NG_REPO/NG_BRANCH/--repo/--branch semantics unchanged
- panel enrollment/uninstall commands in public/app.js point at Gitea raw
- install.sh/nexusgate.sh/agent-singbox.sh stats source previously
  defaulted to the upstream repo (a2899882); defaults now this repo
Upstream dependency references (sagernet/sing-box Go module) untouched.
2026-10-20 11:05:55 +00:00

201 lines
6.8 KiB
Bash
Executable File
Raw Permalink Blame History

This file contains ambiguous Unicode characters
This file contains Unicode characters that might be confused with other characters. If you think that this is intentional, you can safely ignore this warning. Use the Escape button to reveal them.
#!/usr/bin/env bash
set -Eeuo pipefail
REPO="${NG_REPO:-rogue/NexusGate}"
BRANCH="${NG_BRANCH:-main}"
# 自建 Gitea 分发基址(源码归档由此拼装)
GIT_BASE="https://git.881218.xyz/${REPO}"
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 指向本地源码目录时跳过远程下载(本地改动尚未 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 "${GIT_BASE}/archive/${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(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'