feat: add web admin panel for node management

Add Flask panel with login, add/delete nodes, and share link copy.
Generate sing-box config from SQLite; add uninstall script and clean install flow.
Panel served at https://DOMAIN:8444 via nginx.

Co-authored-by: Cursor <cursoragent@cursor.com>
This commit is contained in:
dekun
2026-06-16 09:10:19 +08:00
parent e8631a0e10
commit bccf6cfdce
21 changed files with 1069 additions and 305 deletions
+2 -96
View File
@@ -1,97 +1,3 @@
#!/usr/bin/env bash
# 证书已申请但 sing-box 未安装完成时,执行本脚本补全部署
set -euo pipefail
SCRIPT_DIR="$(cd "$(dirname "${BASH_SOURCE[0]}")" && pwd)"
ROOT_DIR="$(dirname "$SCRIPT_DIR")"
ENV_FILE="${ROOT_DIR}/.env"
[[ $EUID -eq 0 ]] || { echo "请使用 root 运行"; exit 1; }
[[ -f "$ENV_FILE" ]] || { echo "缺少 .env"; exit 1; }
# shellcheck disable=SC1090
source "$ENV_FILE"
: "${DOMAIN:?}"
: "${UUID:?}"
: "${REALITY_PRIVATE_KEY:?}"
: "${REALITY_SHORT_ID:?}"
: "${HY2_PASSWORD:?}"
: "${REALITY_PUBLIC_KEY:?}"
if ! command -v sing-box &>/dev/null; then
echo "sing-box 未安装,请先运行: bash scripts/install.sh"
exit 1
fi
mkdir -p /etc/sing-box/certs
if [[ ! -f /etc/sing-box/certs/fullchain.pem ]]; then
echo "安装证书..."
/root/.acme.sh/acme.sh --install-cert -d "$DOMAIN" \
--key-file /etc/sing-box/certs/privkey.pem \
--fullchain-file /etc/sing-box/certs/fullchain.pem \
--reloadcmd "systemctl restart sing-box || true"
fi
echo "生成 sing-box 配置..."
sed -e "s|\${UUID}|${UUID}|g" \
-e "s|\${REALITY_SERVER_NAME}|${REALITY_SERVER_NAME:-www.microsoft.com}|g" \
-e "s|\${REALITY_PRIVATE_KEY}|${REALITY_PRIVATE_KEY}|g" \
-e "s|\${REALITY_SHORT_ID}|${REALITY_SHORT_ID}|g" \
-e "s|\${HY2_PASSWORD}|${HY2_PASSWORD}|g" \
-e "s|\${DOMAIN}|${DOMAIN}|g" \
"$ROOT_DIR/server/sing-box.json.template" > /etc/sing-box/config.json
sing-box check -c /etc/sing-box/config.json
cat > /etc/systemd/system/sing-box.service <<'UNIT'
[Unit]
Description=sing-box service
After=network-online.target nginx.service
Wants=network-online.target
[Service]
Type=simple
ExecStart=/usr/local/bin/sing-box run -c /etc/sing-box/config.json
Restart=on-failure
RestartSec=5
LimitNOFILE=1048576
[Install]
WantedBy=multi-user.target
UNIT
systemctl daemon-reload
systemctl enable sing-box
systemctl restart sing-box
CLIENT_DIR="${ROOT_DIR}/client/generated"
mkdir -p "$CLIENT_DIR"
sed -e "s|\${VPS_IP}|${VPS_IP}|g" \
-e "s|\${DOMAIN}|${DOMAIN}|g" \
-e "s|\${UUID}|${UUID}|g" \
-e "s|\${REALITY_SERVER_NAME}|${REALITY_SERVER_NAME:-www.microsoft.com}|g" \
-e "s|\${REALITY_PUBLIC_KEY}|${REALITY_PUBLIC_KEY}|g" \
-e "s|\${REALITY_SHORT_ID}|${REALITY_SHORT_ID}|g" \
-e "s|\${HY2_PASSWORD}|${HY2_PASSWORD}|g" \
"$ROOT_DIR/client/sing-box-client.json.template" > "$CLIENT_DIR/sing-box-client.json"
cat > "$CLIENT_DIR/share-links.txt" <<EOF
========== VLESS + Reality (主力) ==========
vless://${UUID}@${VPS_IP}:443?encryption=none&flow=xtls-rprx-vision&security=reality&sni=${REALITY_SERVER_NAME:-www.microsoft.com}&fp=chrome&pbk=${REALITY_PUBLIC_KEY}&sid=${REALITY_SHORT_ID}&type=tcp#Reality-Main
========== Hysteria2 (备用) ==========
hy2://${HY2_PASSWORD}@${DOMAIN}:8443?sni=${DOMAIN}#Hysteria2-Backup
EOF
/root/.acme.sh/acme.sh --install-cert -d "$DOMAIN" \
--key-file /etc/sing-box/certs/privkey.pem \
--fullchain-file /etc/sing-box/certs/fullchain.pem \
--reloadcmd "systemctl restart sing-box" \
|| echo "警告: acme reloadcmd 注册失败,sing-box 已在运行,可忽略"
echo ""
echo "完成!sing-box 状态:"
systemctl status sing-box --no-pager
echo ""
cat "$CLIENT_DIR/share-links.txt"
# 已合并到 install.sh,保留此入口以兼容旧文档
exec bash "$(cd "$(dirname "${BASH_SOURCE[0]}")" && pwd)/install.sh" "$@"